db and auth refactoring

This commit is contained in:
Michele 2021-02-20 00:18:07 +00:00
parent 0e1c16ab91
commit aa472f9e29
45 changed files with 2182 additions and 697 deletions

View file

@ -4,4 +4,35 @@ to start the container run:
``` ```
docker run --name=<name> -p:5000:80 -v /home/michele/sledgemapper/:/app/db -d privateregistry.michelescandura.com/michele/sledgemapper:<version> docker run --name=<name> -p:5000:80 -v /home/michele/sledgemapper/:/app/db -d privateregistry.michelescandura.com/michele/sledgemapper:<version>
```
Curl
Register user
```
curl -i -X POST -H "Content-Type: application/json" http://localhost:5000/users/register -d '{\"FirstName\":\"Michele\",\"LastName\":\"Scandura\", \"Username\":\"michele.scandura@outlook.com\", \"Password\":\"password1\", \"Initials\":\"MS\"}'
```
Login
```
curl -i -X POST -H "Content-Type: application/json" http://localhost:5000/users/authenticate -d '{\"Username\":\"michele.scandura@outlook.com\", \"Password\":\"password1\"}'
```
New Campaign
```
curl -i -X POST -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IjEiLCJuYmYiOjE2MTM3MjgzMjksImV4cCI6MTYxNDMzMzEyOCwiaWF0IjoxNjEzNzI4MzI5fQ.VEsDbYUTnnvpgWnB5buE88JyGx_cg3TJb5ybC3eLvmc" http://localhost:5000/campaign/highfell -d '""'
```
Get Campaigns
```
curl -i -X GET -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IjEiLCJuYmYiOjE2MTM3MjgzMjksImV4cCI6MTYxNDMzMzEyOCwiaWF0IjoxNjEzNzI4MzI5fQ.VEsDbYUTnnvpgWnB5buE88JyGx_cg3TJb5ybC3eLvmc" http://localhost:5000/campaign -d '""'
```
```
curl -i -X POST -H "Content-Type: application/json" http://localhost:5000/AuthManagement/register -d '{\"FirstName\":\"Michele\",\"LastName\":\"Scandura\", \"UserName\":\"michele\", \"Password\":\"Password1!\", \"Initials\":\"MS\", \"Email\":\"michele.scandura@outlook.com\"}'
```
```
curl -i -X POST -H "Content-Type: application/json" http://localhost:5000/AuthManagement/login -d '{ \"Password\":\"Password1!\", \"Email\":\"michele.scandura@outlook.com\"}'
``` ```

View file

@ -1,9 +1,36 @@
using System;
using System.Collections.Generic;
using MediatR;
namespace Sledgemapper.Api.Commands namespace Sledgemapper.Api.Commands
{ {
public class NewSessionCommand : BaseCommand<bool> public class NewSessionCommand : BaseCommand<bool>
{ {
public NewSessionCommand(string sessionName, int userId):base(sessionName, userId) public NewSessionCommand(string sessionName, int userId) : base(sessionName, userId)
{ {
} }
} }
public class NewCampaignCommand : IRequest<bool>
{
public double Timestamp { get; private set; }
public string CampaignName { get; private set; }
public string UserId { get; private set; }
public NewCampaignCommand(string campaingName, string userId)
{
Timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds();
CampaignName = campaingName;
UserId = userId;
}
}
public class GetCampaignsCommand : IRequest<List<Core.Entities.Campaign>>
{
public string UserId { get; private set; }
public GetCampaignsCommand(string userId)
{
UserId = userId;
}
}
} }

View file

@ -0,0 +1,184 @@
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Sledgemapper.Api.Commands;
using Sledgemapper.Api.Notifications;
using Sledgemapper.Entities;
using Sledgemapper.Models.Users;
using Sledgemapper.Shared.Entities;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
namespace Sledgemapper.Api.Controllers
{
[Route("[controller]")] // api/authmanagement
[ApiController]
public class AuthManagementController : ControllerBase
{
private readonly UserManager<User> _userManager;
private readonly JwtConfig _jwtConfig;
public AuthManagementController(UserManager<User> userManager,
IOptionsMonitor<JwtConfig> optionsMonitor)
{
_userManager = userManager;
_jwtConfig = optionsMonitor.CurrentValue;
}
[HttpPost]
[Route("Register")]
public async Task<IActionResult> Register([FromBody] Sledgemapper.Models.Users.RegisterModel user)
{
// Check if the incoming request is valid
if (ModelState.IsValid)
{
// check i the user with the same email exist
var existingUser = await _userManager.FindByEmailAsync(user.Email);
if (existingUser != null)
{
return BadRequest(new Sledgemapper.Models.Users.RegistrationResponse()
{
Result = false,
Errors = new List<string>(){
"Email already exist"
}
});
}
var newUser = new User() { Email = user.Email, UserName = user.UserName };
var isCreated = await _userManager.CreateAsync(newUser, user.Password);
if (isCreated.Succeeded)
{
var jwtToken = GenerateJwtToken(newUser);
return Ok(new Sledgemapper.Models.Users.RegistrationResponse()
{
Result = true,
Token = jwtToken
});
}
return new JsonResult(new Sledgemapper.Models.Users.RegistrationResponse()
{
Result = false,
Errors = isCreated.Errors.Select(x => x.Description).ToList()
}
)
{ StatusCode = 500 };
}
return BadRequest(new Sledgemapper.Models.Users.RegistrationResponse()
{
Result = false,
Errors = new List<string>(){
"Invalid payload"
}
});
}
private string GenerateJwtToken(User user)
{
// Now its ime to define the jwt token which will be responsible of creating our tokens
var jwtTokenHandler = new JwtSecurityTokenHandler();
// We get our secret from the appsettings
var key = Encoding.ASCII.GetBytes(_jwtConfig.Secret);
// we define our token descriptor
// We need to utilise claims which are properties in our token which gives information about the token
// which belong to the specific user who it belongs to
// so it could contain their id, name, email the good part is that these information
// are generated by our server and identity framework which is valid and trusted
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim("Id", user.Id.ToString()),
new Claim(JwtRegisteredClaimNames.Sub, user.Email),
new Claim(JwtRegisteredClaimNames.Email, user.Email),
// the JTI is used for our refresh token which we will be convering in the next video
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
}),
// the life span of the token needs to be shorter and utilise refresh token to keep the user signedin
// but since this is a demo app we can extend it to fit our current need
Expires = DateTime.UtcNow.AddHours(6),
// here we are adding the encryption alogorithim information which will be used to decrypt our token
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha512Signature)
};
var token = jwtTokenHandler.CreateToken(tokenDescriptor);
var jwtToken = jwtTokenHandler.WriteToken(token);
return jwtToken;
}
[HttpPost]
[Route("Login")]
public async Task<IActionResult> Login([FromBody] UserLoginRequest user)
{
if (ModelState.IsValid)
{
// check if the user with the same email exist
var existingUser = await _userManager.FindByEmailAsync(user.Email);
if (existingUser == null)
{
// We dont want to give to much information on why the request has failed for security reasons
return BadRequest(new RegistrationResponse()
{
Result = false,
Errors = new List<string>(){
"Invalid authentication request"
}
});
}
// Now we need to check if the user has inputed the right password
var isCorrect = await _userManager.CheckPasswordAsync(existingUser, user.Password);
if (isCorrect)
{
var jwtToken = GenerateJwtToken(existingUser);
return Ok(new RegistrationResponse()
{
Result = true,
Token = jwtToken
});
}
else
{
// We dont want to give to much information on why the request has failed for security reasons
return BadRequest(new RegistrationResponse()
{
Result = false,
Errors = new List<string>(){
"Invalid authentication request"
}
});
}
}
return BadRequest(new RegistrationResponse()
{
Result = false,
Errors = new List<string>(){
"Invalid payload"
}
});
}
}
}

View file

@ -0,0 +1,39 @@
using MediatR;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Sledgemapper.Api.Commands;
using Sledgemapper.Api.Notifications;
using Sledgemapper.Shared.Entities;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Sledgemapper.Api.Controllers
{
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Route("[controller]")]
public class CampaignController : ControllerBase
{
private readonly IMediator _mediator;
private string UserId => HttpContext.User.Claims.FirstOrDefault(m => m.Type == "Id").Value;
public CampaignController(IMediator mediator) => _mediator = mediator;
[HttpPost]
[Route("{campaignName}")]
public async Task<bool> Post(string campaignName)
{
var result = await _mediator.Send(new NewCampaignCommand(campaignName, UserId.ToString()));
return result;
}
[HttpGet]
public async Task<List<Core.Entities.Campaign>> Get()
{
var result = await _mediator.Send(new GetCampaignsCommand(UserId));
return result;
}
}
}

View file

@ -9,98 +9,82 @@ using System.Threading.Tasks;
namespace Sledgemapper.Api.Controllers namespace Sledgemapper.Api.Controllers
{ {
[Authorize] [Authorize]
[Route("[controller]/{sessionName}")] [Route("[controller]/{mapName}")]
public class SessionController : ControllerBase public class MapController : ControllerBase
{ {
private readonly IMediator _mediator; private readonly IMediator _mediator;
private int UserId => int.Parse(HttpContext.User.Identity.Name); private int UserId => int.Parse(HttpContext.User.Identity.Name);
public SessionController(IMediator mediator) => _mediator = mediator; public MapController(IMediator mediator) => _mediator = mediator;
[HttpPost] [HttpPost]
public async Task<bool> Post(string sessionName) public async Task<bool> Post(string mapName)
{ {
var result = await _mediator.Send(new NewSessionCommand(sessionName, UserId)); var result = await _mediator.Send(new NewSessionCommand(mapName, UserId));
return result; return result;
} }
[HttpGet] [HttpGet]
public async Task<Session> Get(string sessionName) public async Task<Session> Get(string mapName)
{ {
var result = await _mediator.Send(new GetMapSnapshotCommand(sessionName)); var result = await _mediator.Send(new GetMapSnapshotCommand(mapName));
return result; return result;
} }
// [HttpPost("ping")]
// public async Task Post(string sessionName, [FromBody] Ping pingLocation)
// {
// await _mediator.Send(new PingCommand(sessionName, pingLocation, UserId));
// }
[HttpPost("snapshot")] [HttpPost("snapshot")]
public async Task Post(string sessionName, [FromBody] Session session) public async Task Post(string mapName, [FromBody] Session session)
{ {
await _mediator.Send(new NewSnapshotCommand(sessionName, session, UserId)); await _mediator.Send(new NewSnapshotCommand(mapName, session, UserId));
}
[HttpPost("tile")]
public async Task Post(string sessionName, [FromBody] Tile tile)
{
await _mediator.Send(new NewTileCommand(sessionName, tile, UserId));
} }
[HttpPost("overlay")] [HttpPost("overlay")]
public async Task Post(string sessionName, [FromBody] Overlay overlay) public async Task Post(string mapName, [FromBody] Overlay overlay)
{ {
await _mediator.Send(new NewOverlayCommand(sessionName, overlay, UserId)); await _mediator.Send(new NewOverlayCommand(mapName, overlay, UserId));
} }
[HttpPost("wall")] [HttpPost("wall")]
public async Task Post(string sessionName, [FromBody] Wall wall) public async Task Post(string mapName, [FromBody] Wall wall)
{ {
await _mediator.Send(new NewWallCommand(sessionName, wall, UserId)); await _mediator.Send(new NewWallCommand(mapName, wall, UserId));
} }
[HttpPost("note")] [HttpPost("note")]
public async Task Post(string sessionName, [FromBody] Note note) public async Task Post(string mapName, [FromBody] Note note)
{ {
await _mediator.Send(new NewNoteCommand(sessionName, note, UserId)); await _mediator.Send(new NewNoteCommand(mapName, note, UserId));
} }
[HttpPost("room")] [HttpPost("room")]
public async Task Post(string sessionName, [FromBody] Room room) public async Task Post(string mapName, [FromBody] Room room)
{ {
await _mediator.Send(new NewRoomCommand(sessionName, room, UserId)); await _mediator.Send(new NewRoomCommand(mapName, room, UserId));
} }
[HttpPost("line")] [HttpPost("line")]
public async Task Post(string sessionName, [FromBody] Line line) public async Task Post(string mapName, [FromBody] Line line)
{ {
await _mediator.Send(new NewLineCommand(sessionName, line, UserId)); await _mediator.Send(new NewLineCommand(mapName, line, UserId));
}
[HttpDelete("tile")]
public async Task Delete(string sessionName, [FromBody] Tile tile)
{
await _mediator.Send(new DeleteTileCommand(sessionName, tile, UserId));
} }
[HttpDelete("overlay")] [HttpDelete("overlay")]
public async Task Delete(string sessionName, [FromBody] Overlay overlay) public async Task Delete(string mapName, [FromBody] Overlay overlay)
{ {
await _mediator.Send(new DeleteOverlayCommand(sessionName, overlay, UserId)); await _mediator.Send(new DeleteOverlayCommand(mapName, overlay, UserId));
} }
[HttpDelete("wall")] [HttpDelete("wall")]
public async Task Delete(string sessionName, [FromBody] Wall wall) public async Task Delete(string mapName, [FromBody] Wall wall)
{ {
await _mediator.Send(new DeleteWallCommand(sessionName, wall, UserId)); await _mediator.Send(new DeleteWallCommand(mapName, wall, UserId));
} }
[HttpDelete("note")] [HttpDelete("note")]
public async Task Delete(string sessionName, [FromBody] Note note) public async Task Delete(string mapName, [FromBody] Note note)
{ {
await _mediator.Send(new DeleteNoteCommand(sessionName, note, UserId)); await _mediator.Send(new DeleteNoteCommand(mapName, note, UserId));
} }
} }
} }

View file

@ -1,136 +0,0 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using AutoMapper;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.Extensions.Options;
using System.Text;
using Microsoft.IdentityModel.Tokens;
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Sledgemapper.Entities;
using Sledgemapper.Models.Users;
using Sledgemapper.Helpers;
using Sledgemapper.Api.Infrastructure.Services;
namespace Sledgemapper.Controllers
{
[Authorize]
[ApiController]
[Route("[controller]")]
public class UsersController : ControllerBase
{
private IUserService _userService;
private IMapper _mapper;
private readonly AppSettings _appSettings;
public UsersController(
IUserService userService,
IMapper mapper,
IOptions<AppSettings> appSettings)
{
_userService = userService;
_mapper = mapper;
_appSettings = appSettings.Value;
}
[AllowAnonymous]
[HttpPost("authenticate")]
public IActionResult Authenticate([FromBody]AuthenticateModel model)
{
var user = _userService.Authenticate(model.Username, model.Password);
if (user == null)
return BadRequest(new { message = "Username or password is incorrect" });
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, user.Id.ToString())
}),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
// return basic user info and authentication token
return Ok(new
{
Id = user.Id,
Username = user.Username,
FirstName = user.FirstName,
LastName = user.LastName,
Initials = user.Initials,
Token = tokenString
});
}
[AllowAnonymous]
[HttpPost("register")]
public IActionResult Register([FromBody]RegisterModel model)
{
// map model to entity
var user = _mapper.Map<User>(model);
try
{
// create user
_userService.Create(user, model.Password);
return Ok();
}
catch (AppException ex)
{
// return error message if there was an exception
return BadRequest(new { message = ex.Message });
}
}
[HttpGet]
public IActionResult GetAll()
{
var users = _userService.GetAll();
var model = _mapper.Map<IList<UserModel>>(users);
return Ok(model);
}
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
var user = _userService.GetById(id);
var model = _mapper.Map<UserModel>(user);
return Ok(model);
}
[HttpPut("{id}")]
public IActionResult Update(int id, [FromBody]UpdateModel model)
{
// map model to entity and set id
var user = _mapper.Map<User>(model);
user.Id = id;
try
{
// update user
_userService.Update(user, model.Password);
return Ok();
}
catch (AppException ex)
{
// return error message if there was an exception
return BadRequest(new { message = ex.Message });
}
}
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
_userService.Delete(id);
return Ok();
}
}
}

View file

@ -0,0 +1,7 @@
using System.ComponentModel.DataAnnotations;
public abstract class BaseEntity
{
[Key]
public int Id { get; set; }
}

View file

@ -0,0 +1,21 @@
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Sledgemapper.Entities;
namespace Sledgemapper.Api.Core.Entities
{
[Index(nameof(CampaignName), nameof(OwnerId), IsUnique = true)]
public class Campaign
{
public int CampaignId { get; set; }
public string CampaignName { get; set; }
public string OwnerId { get; set; }
public User Owner { get; set; }
public ICollection<User> InvitedUsers { get; set; }
public ICollection<Map> Maps { get; set; }
}
}

View file

@ -1,20 +0,0 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Sledgemapper.Entities;
namespace Sledgemapper.Api.Core.Entities.CampaignAggregate
{
public class Campaign
{
[Key]
public int CampaignId { get; set; }
[Required]
public string CampaignName { get; set; }
[Required]
public int OwnerUserId { get; set; }
public List<User> InvitedUsers { get; set; }
}
}

View file

@ -1,6 +1,6 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace Sledgemapper.Api.Core.Entities.CampaignAggregate namespace Sledgemapper.Api.Core.Entities
{ {
public class Map public class Map
{ {

View file

@ -0,0 +1,18 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Identity;
namespace Sledgemapper.Entities
{
public class User:IdentityUser
{
// public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
// public string Email { get; set; }
// public string Username { get; set; }
public string Initials { get; set; }
// public byte[] PasswordHash { get; set; }
public byte[] PasswordSalt { get; set; }
public ICollection<Sledgemapper.Api.Core.Entities.Campaign> Campaigns {get;set;}
}
}

View file

@ -0,0 +1,78 @@
using MediatR;
using Microsoft.EntityFrameworkCore;
using Sledgemapper.Api.Commands;
using Sledgemapper.Api.Infrastructure.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Sledgemapper.Api.Handlers
{
public class NewCampaignCommandHandler : IRequestHandler<NewCampaignCommand, bool>
{
private readonly IMediator _mediator;
private readonly SledgemapperDbContext _dbcontext;
public NewCampaignCommandHandler(IMediator mediator, SledgemapperDbContext dbcontext)
{
_mediator = mediator;
_dbcontext = dbcontext;
}
public async Task<bool> Handle(NewCampaignCommand notification, CancellationToken cancellationToken)
{
try
{
var user = await _dbcontext.Users.FindAsync(notification.UserId);
_dbcontext.Attach(user);
var campaign = new Core.Entities.Campaign
{
CampaignName = notification.CampaignName,
OwnerId = user.Id,
InvitedUsers = new System.Collections.Generic.List<Entities.User> { user }
};
_dbcontext.Campaigns.Add(campaign);
await _dbcontext.SaveChangesAsync();
return true;
}
catch (Exception ex)
{
}
return false;
}
}
public class GetCampaignsCommandHandler : IRequestHandler<GetCampaignsCommand, List<Core.Entities.Campaign>>
{
private readonly IMediator _mediator;
private readonly SledgemapperDbContext _dbcontext;
public GetCampaignsCommandHandler(IMediator mediator, SledgemapperDbContext dbcontext)
{
_mediator = mediator;
_dbcontext = dbcontext;
}
public async Task<List<Core.Entities.Campaign>> Handle(GetCampaignsCommand command, CancellationToken cancellationToken)
{
try
{
var user = await _dbcontext.Users.FindAsync(command.UserId);
_dbcontext.Attach(user);
var campaigns = _dbcontext.Campaigns.Where(campaign => campaign.OwnerId == command.UserId || campaign.InvitedUsers.Contains(user));
return campaigns.ToList();
}
catch (Exception ex)
{
}
return new List<Core.Entities.Campaign>();
}
}
}

View file

@ -1,7 +0,0 @@
namespace Sledgemapper.Helpers
{
public class AppSettings
{
public string Secret { get; set; }
}
}

View file

@ -8,9 +8,7 @@ namespace Sledgemapper.Helpers
{ {
public AutoMapperProfile() public AutoMapperProfile()
{ {
CreateMap<User, UserModel>();
CreateMap<RegisterModel, User>(); CreateMap<RegisterModel, User>();
CreateMap<UpdateModel, User>();
} }
} }
} }

View file

@ -1,24 +0,0 @@
// using Microsoft.EntityFrameworkCore;
// using Microsoft.Extensions.Configuration;
// using Sledgemapper.Entities;
// namespace Sledgemapper.Helpers
// {
// public class DataContext : DbContext
// {
// protected readonly IConfiguration Configuration;
// public DataContext(IConfiguration configuration)
// {
// Configuration = configuration;
// }
// protected override void OnConfiguring(DbContextOptionsBuilder options)
// {
// // connect to sql server database
// options.UseSqlServer(Configuration.GetConnectionString("WebApiDatabase"));
// }
// public DbSet<User> Users { get; set; }
// }
// }

View file

@ -1,16 +0,0 @@
// using Microsoft.EntityFrameworkCore;
// using Microsoft.Extensions.Configuration;
// namespace Sledgemapper.Helpers
// {
// public class SqliteDataContext : DataContext
// {
// public SqliteDataContext(IConfiguration configuration) : base(configuration) { }
// protected override void OnConfiguring(DbContextOptionsBuilder options)
// {
// // connect to sqlite database
// options.UseSqlite(Configuration.GetConnectionString("WebApiDatabase"));
// }
// }
// }

View file

@ -89,7 +89,7 @@ namespace Sledgemapper.Api.Hubs
public async Task Ping(string sessionName, Tile location) public async Task Ping(string sessionName, Tile location)
{ {
var userId = int.Parse(Context.User.Identity.Name); var userId = int.Parse(Context.User.Identity.Name);
var user = _dbContext.Users.First(u => u.Id == userId); var user = _dbContext.Users.First(u => u.Id == Context.User.Identity.Name);
var player = new Player { UserId = userId, Initials = user.Initials, Position = new Tile { X = 0, Y = 0 }, Color = UserColors[userId] }; var player = new Player { UserId = userId, Initials = user.Initials, Position = new Tile { X = 0, Y = 0 }, Color = UserColors[userId] };
await Clients.Group(sessionName).Ping(new Ping{X=location.X, Y=location.Y, Player=player}); await Clients.Group(sessionName).Ping(new Ping{X=location.X, Y=location.Y, Player=player});
@ -106,7 +106,7 @@ namespace Sledgemapper.Api.Hubs
_dbContext.SessionUsers.Add(userSession); _dbContext.SessionUsers.Add(userSession);
await _dbContext.SaveChangesAsync(); await _dbContext.SaveChangesAsync();
await Groups.AddToGroupAsync(Context.ConnectionId, session.SessionName); await Groups.AddToGroupAsync(Context.ConnectionId, session.SessionName);
var user = _dbContext.Users.First(u => u.Id == userId); var user = _dbContext.Users.First(u => u.Id == Context.User.Identity.Name);
var player = new Player { UserId = userId, Initials = user.Initials, Position = new Tile { X = 0, Y = 0 }, Color = UserColors[userId] }; var player = new Player { UserId = userId, Initials = user.Initials, Position = new Tile { X = 0, Y = 0 }, Color = UserColors[userId] };
@ -131,7 +131,7 @@ namespace Sledgemapper.Api.Hubs
{ {
var userId = int.Parse(Context.User.Identity.Name); var userId = int.Parse(Context.User.Identity.Name);
var SessionUsers = _dbContext.SessionUsers.Where(m => m.SessionId == sessionId).OrderBy(m => m.UserId).ToList(); var SessionUsers = _dbContext.SessionUsers.Where(m => m.SessionId == sessionId).OrderBy(m => m.UserId).ToList();
var user = _dbContext.Users.First(u => u.Id == userId); var user = _dbContext.Users.First(u => u.Id == Context.User.Identity.Name);
var player = new Player { UserId = userId, Initials = user.Initials, Position = tile, Color = UserColors[userId] }; var player = new Player { UserId = userId, Initials = user.Initials, Position = tile, Color = UserColors[userId] };
await Clients.Group(sessionName).PlayerUpdate(player); await Clients.Group(sessionName).PlayerUpdate(player);
} }

View file

@ -1,88 +0,0 @@
using Microsoft.EntityFrameworkCore;
using Sledgemapper.Api.Core.Entities.CampaignAggregate;
using Sledgemapper.Api.Models;
using Sledgemapper.Entities;
namespace Sledgemapper.Api.Infrastructure.Data
{
// public static class DbInitializer
// {
// public static void Initialize(SledgemapperDbContext context)
// {
// context.Database.EnsureCreated();
// }
// }
public class SledgemapperDbContext : DbContext
{
public DbSet<Sledgemapper.Api.Core.Entities.CampaignAggregate.Campaign> Campaigns { get; set; }
public DbSet<MapLog> MapLogs { get; set; }
public DbSet<Map> Maps { get; set; }
public DbSet<Session> Sessions { get; set; }
public DbSet<SessionUser> SessionUsers { get; set; }
public DbSet<Snapshot> Snapshots { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<UserConnection> UserConnections { get; set; }
public SledgemapperDbContext(DbContextOptions options) : base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// optionsBuilder.
// options.MigrationsAssembly(Assembly.GetExecutingAssembly().FullName);
// optionsBuilder.UseSqlite("Filename=SledgemapperDatabase.db", options =>
// {
// options.MigrationsAssembly(Assembly.GetExecutingAssembly().FullName);
// });
optionsBuilder.UseSqlite("Filename=Sledgemapper.db").UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
base.OnConfiguring(optionsBuilder);
}
// protected override void OnModelCreating(ModelBuilder modelBuilder)
// {
// // Map table names
// modelBuilder.Entity<MapLog>().ToTable("MapLog", "dbo");
// modelBuilder.Entity<MapLog>(entity =>
// {
// entity.HasKey(e => e.MapLogId);
// });
// modelBuilder.Entity<Session>().ToTable("Session", "dbo");
// modelBuilder.Entity<Session>(entity =>
// {
// entity.HasKey(e => e.SessionId);
// entity.HasIndex(e => e.SessionName).IsUnique();
// });
// modelBuilder.Entity<UserConnection>().ToTable("UserConnection", "dbo");
// modelBuilder.Entity<UserConnection>(entity =>
// {
// entity.HasKey(e => e.UserConnectionId);
// entity.HasIndex(e => e.UserId);
// });
// modelBuilder.Entity<SessionUser>().ToTable("SessionUser", "dbo");
// modelBuilder.Entity<SessionUser>(entity =>
// {
// entity.HasKey(e => e.SessionUserId);
// entity.HasIndex(e => e.SessionId);
// });
// modelBuilder.Entity<Snapshot>().ToTable("Snapshot", "dbo");
// modelBuilder.Entity<Snapshot>(entity =>
// {
// entity.HasKey(e => e.SnapshotId);
// });
// base.OnModelCreating(modelBuilder);
// }
}
}

View file

@ -0,0 +1,96 @@
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Sledgemapper.Api.Core.Entities;
using Sledgemapper.Api.Models;
using Sledgemapper.Entities;
namespace Sledgemapper.Api.Infrastructure.Data
{
// public static class DbInitializer
// {
// public static void Initialize(SledgemapperDbContext context)
// {
// context.Database.EnsureCreated();
// }
// }
public class SledgemapperDbContext : IdentityDbContext
{
public DbSet<Sledgemapper.Api.Core.Entities.Campaign> Campaigns { get; set; }
public DbSet<MapLog> MapLogs { get; set; }
public DbSet<Map> Maps { get; set; }
public DbSet<Session> Sessions { get; set; }
public DbSet<SessionUser> SessionUsers { get; set; }
public DbSet<Snapshot> Snapshots { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<UserConnection> UserConnections { get; set; }
public SledgemapperDbContext(DbContextOptions options) : base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// optionsBuilder.
// options.MigrationsAssembly(Assembly.GetExecutingAssembly().FullName);
// optionsBuilder.UseSqlite("Filename=SledgemapperDatabase.db", options =>
// {
// options.MigrationsAssembly(Assembly.GetExecutingAssembly().FullName);
// });
optionsBuilder.UseSqlite("Filename=Sledgemapper.db").UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Core.Entities.Campaign>().HasOne<User>(e=>e.Owner);
modelBuilder.Entity<Core.Entities.Campaign>().HasMany<User>(e=>e.InvitedUsers).WithMany(e=>e.Campaigns);
modelBuilder.Entity<User>() //Use your application user class here
.ToTable( "Users" ); //Set the table name here
// // Map table names
// modelBuilder.Entity<MapLog>().ToTable("MapLog", "dbo");
// modelBuilder.Entity<MapLog>(entity =>
// {
// entity.HasKey(e => e.MapLogId);
// });
// modelBuilder.Entity<Session>().ToTable("Session", "dbo");
// modelBuilder.Entity<Session>(entity =>
// {
// entity.HasKey(e => e.SessionId);
// entity.HasIndex(e => e.SessionName).IsUnique();
// });
// modelBuilder.Entity<UserConnection>().ToTable("UserConnection", "dbo");
// modelBuilder.Entity<UserConnection>(entity =>
// {
// entity.HasKey(e => e.UserConnectionId);
// entity.HasIndex(e => e.UserId);
// });
// modelBuilder.Entity<SessionUser>().ToTable("SessionUser", "dbo");
// modelBuilder.Entity<SessionUser>(entity =>
// {
// entity.HasKey(e => e.SessionUserId);
// entity.HasIndex(e => e.SessionId);
// });
// modelBuilder.Entity<Snapshot>().ToTable("Snapshot", "dbo");
// modelBuilder.Entity<Snapshot>(entity =>
// {
// entity.HasKey(e => e.SnapshotId);
// });
base.OnModelCreating(modelBuilder);
}
}
}

View file

@ -1,160 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Sledgemapper.Api.Infrastructure.Data;
using Sledgemapper.Entities;
using Sledgemapper.Helpers;
namespace Sledgemapper.Api.Infrastructure.Services
{
public interface IUserService
{
User Authenticate(string username, string password);
IEnumerable<User> GetAll();
User GetById(int id);
User Create(User user, string password);
void Update(User user, string password = null);
void Delete(int id);
}
public class UserService : IUserService
{
private SledgemapperDbContext _context;
public UserService(SledgemapperDbContext context)
{
_context = context;
}
public User Authenticate(string username, string password)
{
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
return null;
var user = _context.Users.SingleOrDefault(x => x.Username == username);
// check if username exists
if (user == null)
return null;
// check if password is correct
if (!VerifyPasswordHash(password, user.PasswordHash, user.PasswordSalt))
return null;
// authentication successful
return user;
}
public IEnumerable<User> GetAll()
{
return _context.Users;
}
public User GetById(int id)
{
return _context.Users.Find(id);
}
public User Create(User user, string password)
{
// validation
if (string.IsNullOrWhiteSpace(password))
throw new AppException("Password is required");
if (_context.Users.Any(x => x.Username == user.Username))
throw new AppException("Username \"" + user.Username + "\" is already taken");
byte[] passwordHash, passwordSalt;
CreatePasswordHash(password, out passwordHash, out passwordSalt);
user.PasswordHash = passwordHash;
user.PasswordSalt = passwordSalt;
_context.Users.Add(user);
_context.SaveChanges();
return user;
}
public void Update(User userParam, string password = null)
{
var user = _context.Users.Find(userParam.Id);
if (user == null)
throw new AppException("User not found");
// update username if it has changed
if (!string.IsNullOrWhiteSpace(userParam.Username) && userParam.Username != user.Username)
{
// throw error if the new username is already taken
if (_context.Users.Any(x => x.Username == userParam.Username))
throw new AppException("Username " + userParam.Username + " is already taken");
user.Username = userParam.Username;
}
// update user properties if provided
if (!string.IsNullOrWhiteSpace(userParam.FirstName))
user.FirstName = userParam.FirstName;
if (!string.IsNullOrWhiteSpace(userParam.LastName))
user.LastName = userParam.LastName;
// update password if provided
if (!string.IsNullOrWhiteSpace(password))
{
byte[] passwordHash, passwordSalt;
CreatePasswordHash(password, out passwordHash, out passwordSalt);
user.PasswordHash = passwordHash;
user.PasswordSalt = passwordSalt;
}
_context.Users.Update(user);
_context.SaveChanges();
}
public void Delete(int id)
{
var user = _context.Users.Find(id);
if (user != null)
{
_context.Users.Remove(user);
_context.SaveChanges();
}
}
// private helper methods
private static void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
{
if (password == null) throw new ArgumentNullException("password");
if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("Value cannot be empty or whitespace only string.", "password");
using (var hmac = new System.Security.Cryptography.HMACSHA512())
{
passwordSalt = hmac.Key;
passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
}
}
private static bool VerifyPasswordHash(string password, byte[] storedHash, byte[] storedSalt)
{
if (password == null) throw new ArgumentNullException("password");
if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("Value cannot be empty or whitespace only string.", "password");
if (storedHash.Length != 64) throw new ArgumentException("Invalid length of password hash (64 bytes expected).", "passwordHash");
if (storedSalt.Length != 128) throw new ArgumentException("Invalid length of password salt (128 bytes expected).", "passwordHash");
using (var hmac = new System.Security.Cryptography.HMACSHA512(storedSalt))
{
var computedHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
for (int i = 0; i < computedHash.Length; i++)
{
if (computedHash[i] != storedHash[i]) return false;
}
}
return true;
}
}
}

View file

@ -0,0 +1,7 @@
namespace Sledgemapper.Api
{
public class JwtConfig
{
public string Secret { get; set; }
}
}

View file

@ -9,7 +9,7 @@ using Sledgemapper.Api.Infrastructure.Data;
namespace Sledgemapper.Api.Migrations namespace Sledgemapper.Api.Migrations
{ {
[DbContext(typeof(SledgemapperDbContext))] [DbContext(typeof(SledgemapperDbContext))]
[Migration("20210214232542_InitialCreate")] [Migration("20210219223114_InitialCreate")]
partial class InitialCreate partial class InitialCreate
{ {
protected override void BuildTargetModel(ModelBuilder modelBuilder) protected override void BuildTargetModel(ModelBuilder modelBuilder)
@ -18,25 +18,44 @@ namespace Sledgemapper.Api.Migrations
modelBuilder modelBuilder
.HasAnnotation("ProductVersion", "5.0.3"); .HasAnnotation("ProductVersion", "5.0.3");
modelBuilder.Entity("Sledgemapper.Api.Models.Campaign", b => modelBuilder.Entity("CampaignUser", b =>
{
b.Property<int>("CampaignsCampaignId")
.HasColumnType("INTEGER");
b.Property<int>("InvitedUsersId")
.HasColumnType("INTEGER");
b.HasKey("CampaignsCampaignId", "InvitedUsersId");
b.HasIndex("InvitedUsersId");
b.ToTable("CampaignUser");
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Campaign", b =>
{ {
b.Property<int>("CampaignId") b.Property<int>("CampaignId")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<string>("CampaignName") b.Property<string>("CampaignName")
.IsRequired()
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<int>("OwnerUserId") b.Property<int>("OwnerId")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.HasKey("CampaignId"); b.HasKey("CampaignId");
b.HasIndex("OwnerId");
b.HasIndex("CampaignName", "OwnerId")
.IsUnique();
b.ToTable("Campaigns"); b.ToTable("Campaigns");
}); });
modelBuilder.Entity("Sledgemapper.Api.Models.Map", b => modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Map", b =>
{ {
b.Property<int>("MapId") b.Property<int>("MapId")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@ -51,6 +70,8 @@ namespace Sledgemapper.Api.Migrations
b.HasKey("MapId"); b.HasKey("MapId");
b.HasIndex("CampaignId");
b.ToTable("Maps"); b.ToTable("Maps");
}); });
@ -169,9 +190,6 @@ namespace Sledgemapper.Api.Migrations
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<int?>("CampaignId")
.HasColumnType("INTEGER");
b.Property<string>("FirstName") b.Property<string>("FirstName")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
@ -192,21 +210,47 @@ namespace Sledgemapper.Api.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("CampaignId");
b.ToTable("Users"); b.ToTable("Users");
}); });
modelBuilder.Entity("Sledgemapper.Entities.User", b => modelBuilder.Entity("CampaignUser", b =>
{ {
b.HasOne("Sledgemapper.Api.Models.Campaign", null) b.HasOne("Sledgemapper.Api.Core.Entities.Campaign", null)
.WithMany("InvitedUsers") .WithMany()
.HasForeignKey("CampaignId"); .HasForeignKey("CampaignsCampaignId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Sledgemapper.Entities.User", null)
.WithMany()
.HasForeignKey("InvitedUsersId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
}); });
modelBuilder.Entity("Sledgemapper.Api.Models.Campaign", b => modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Campaign", b =>
{ {
b.Navigation("InvitedUsers"); b.HasOne("Sledgemapper.Entities.User", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Owner");
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Map", b =>
{
b.HasOne("Sledgemapper.Api.Core.Entities.Campaign", null)
.WithMany("Maps")
.HasForeignKey("CampaignId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Campaign", b =>
{
b.Navigation("Maps");
}); });
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }

View file

@ -7,20 +7,6 @@ namespace Sledgemapper.Api.Migrations
{ {
protected override void Up(MigrationBuilder migrationBuilder) protected override void Up(MigrationBuilder migrationBuilder)
{ {
migrationBuilder.CreateTable(
name: "Campaigns",
columns: table => new
{
CampaignId = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
CampaignName = table.Column<string>(type: "TEXT", nullable: false),
OwnerUserId = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Campaigns", x => x.CampaignId);
});
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "MapLogs", name: "MapLogs",
columns: table => new columns: table => new
@ -39,20 +25,6 @@ namespace Sledgemapper.Api.Migrations
table.PrimaryKey("PK_MapLogs", x => x.MapLogId); table.PrimaryKey("PK_MapLogs", x => x.MapLogId);
}); });
migrationBuilder.CreateTable(
name: "Maps",
columns: table => new
{
MapId = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
MapName = table.Column<string>(type: "TEXT", nullable: false),
CampaignId = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Maps", x => x.MapId);
});
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "Sessions", name: "Sessions",
columns: table => new columns: table => new
@ -121,28 +93,104 @@ namespace Sledgemapper.Api.Migrations
Username = table.Column<string>(type: "TEXT", nullable: true), Username = table.Column<string>(type: "TEXT", nullable: true),
Initials = table.Column<string>(type: "TEXT", nullable: true), Initials = table.Column<string>(type: "TEXT", nullable: true),
PasswordHash = table.Column<byte[]>(type: "BLOB", nullable: true), PasswordHash = table.Column<byte[]>(type: "BLOB", nullable: true),
PasswordSalt = table.Column<byte[]>(type: "BLOB", nullable: true), PasswordSalt = table.Column<byte[]>(type: "BLOB", nullable: true)
CampaignId = table.Column<int>(type: "INTEGER", nullable: true)
}, },
constraints: table => constraints: table =>
{ {
table.PrimaryKey("PK_Users", x => x.Id); table.PrimaryKey("PK_Users", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Campaigns",
columns: table => new
{
CampaignId = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
CampaignName = table.Column<string>(type: "TEXT", nullable: true),
OwnerId = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Campaigns", x => x.CampaignId);
table.ForeignKey( table.ForeignKey(
name: "FK_Users_Campaigns_CampaignId", name: "FK_Campaigns_Users_OwnerId",
column: x => x.OwnerId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "CampaignUser",
columns: table => new
{
CampaignsCampaignId = table.Column<int>(type: "INTEGER", nullable: false),
InvitedUsersId = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CampaignUser", x => new { x.CampaignsCampaignId, x.InvitedUsersId });
table.ForeignKey(
name: "FK_CampaignUser_Campaigns_CampaignsCampaignId",
column: x => x.CampaignsCampaignId,
principalTable: "Campaigns",
principalColumn: "CampaignId",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_CampaignUser_Users_InvitedUsersId",
column: x => x.InvitedUsersId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Maps",
columns: table => new
{
MapId = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
MapName = table.Column<string>(type: "TEXT", nullable: false),
CampaignId = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Maps", x => x.MapId);
table.ForeignKey(
name: "FK_Maps_Campaigns_CampaignId",
column: x => x.CampaignId, column: x => x.CampaignId,
principalTable: "Campaigns", principalTable: "Campaigns",
principalColumn: "CampaignId", principalColumn: "CampaignId",
onDelete: ReferentialAction.Restrict); onDelete: ReferentialAction.Cascade);
}); });
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_Users_CampaignId", name: "IX_Campaigns_CampaignName_OwnerId",
table: "Users", table: "Campaigns",
columns: new[] { "CampaignName", "OwnerId" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Campaigns_OwnerId",
table: "Campaigns",
column: "OwnerId");
migrationBuilder.CreateIndex(
name: "IX_CampaignUser_InvitedUsersId",
table: "CampaignUser",
column: "InvitedUsersId");
migrationBuilder.CreateIndex(
name: "IX_Maps_CampaignId",
table: "Maps",
column: "CampaignId"); column: "CampaignId");
} }
protected override void Down(MigrationBuilder migrationBuilder) protected override void Down(MigrationBuilder migrationBuilder)
{ {
migrationBuilder.DropTable(
name: "CampaignUser");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "MapLogs"); name: "MapLogs");
@ -162,10 +210,10 @@ namespace Sledgemapper.Api.Migrations
name: "UserConnections"); name: "UserConnections");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "Users"); name: "Campaigns");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "Campaigns"); name: "Users");
} }
} }
} }

View file

@ -2,39 +2,60 @@
using System; using System;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Sledgemapper.Api.Infrastructure.Data; using Sledgemapper.Api.Infrastructure.Data;
namespace Sledgemapper.Api.Migrations namespace Sledgemapper.Api.Migrations
{ {
[DbContext(typeof(SledgemapperDbContext))] [DbContext(typeof(SledgemapperDbContext))]
partial class SledgemapperDbContextModelSnapshot : ModelSnapshot [Migration("20210219223251_Adding authentication to our Api")]
partial class AddingauthenticationtoourApi
{ {
protected override void BuildModel(ModelBuilder modelBuilder) protected override void BuildTargetModel(ModelBuilder modelBuilder)
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder modelBuilder
.HasAnnotation("ProductVersion", "5.0.3"); .HasAnnotation("ProductVersion", "5.0.3");
modelBuilder.Entity("Sledgemapper.Api.Models.Campaign", b => modelBuilder.Entity("CampaignUser", b =>
{
b.Property<int>("CampaignsCampaignId")
.HasColumnType("INTEGER");
b.Property<int>("InvitedUsersId")
.HasColumnType("INTEGER");
b.HasKey("CampaignsCampaignId", "InvitedUsersId");
b.HasIndex("InvitedUsersId");
b.ToTable("CampaignUser");
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Campaign", b =>
{ {
b.Property<int>("CampaignId") b.Property<int>("CampaignId")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<string>("CampaignName") b.Property<string>("CampaignName")
.IsRequired()
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<int>("OwnerUserId") b.Property<int>("OwnerId")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.HasKey("CampaignId"); b.HasKey("CampaignId");
b.HasIndex("OwnerId");
b.HasIndex("CampaignName", "OwnerId")
.IsUnique();
b.ToTable("Campaigns"); b.ToTable("Campaigns");
}); });
modelBuilder.Entity("Sledgemapper.Api.Models.Map", b => modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Map", b =>
{ {
b.Property<int>("MapId") b.Property<int>("MapId")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@ -49,6 +70,8 @@ namespace Sledgemapper.Api.Migrations
b.HasKey("MapId"); b.HasKey("MapId");
b.HasIndex("CampaignId");
b.ToTable("Maps"); b.ToTable("Maps");
}); });
@ -167,9 +190,6 @@ namespace Sledgemapper.Api.Migrations
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<int?>("CampaignId")
.HasColumnType("INTEGER");
b.Property<string>("FirstName") b.Property<string>("FirstName")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
@ -190,21 +210,47 @@ namespace Sledgemapper.Api.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("CampaignId");
b.ToTable("Users"); b.ToTable("Users");
}); });
modelBuilder.Entity("Sledgemapper.Entities.User", b => modelBuilder.Entity("CampaignUser", b =>
{ {
b.HasOne("Sledgemapper.Api.Models.Campaign", null) b.HasOne("Sledgemapper.Api.Core.Entities.Campaign", null)
.WithMany("InvitedUsers") .WithMany()
.HasForeignKey("CampaignId"); .HasForeignKey("CampaignsCampaignId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Sledgemapper.Entities.User", null)
.WithMany()
.HasForeignKey("InvitedUsersId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
}); });
modelBuilder.Entity("Sledgemapper.Api.Models.Campaign", b => modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Campaign", b =>
{ {
b.Navigation("InvitedUsers"); b.HasOne("Sledgemapper.Entities.User", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Owner");
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Map", b =>
{
b.HasOne("Sledgemapper.Api.Core.Entities.Campaign", null)
.WithMany("Maps")
.HasForeignKey("CampaignId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Campaign", b =>
{
b.Navigation("Maps");
}); });
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }

View file

@ -0,0 +1,17 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Sledgemapper.Api.Migrations
{
public partial class AddingauthenticationtoourApi : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

View file

@ -0,0 +1,505 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Sledgemapper.Api.Infrastructure.Data;
namespace Sledgemapper.Api.Migrations
{
[DbContext(typeof(SledgemapperDbContext))]
[Migration("20210219230948_rename table")]
partial class renametable
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "5.0.3");
modelBuilder.Entity("CampaignUser", b =>
{
b.Property<int>("CampaignsCampaignId")
.HasColumnType("INTEGER");
b.Property<string>("InvitedUsersId")
.HasColumnType("TEXT");
b.HasKey("CampaignsCampaignId", "InvitedUsersId");
b.HasIndex("InvitedUsersId");
b.ToTable("CampaignUser");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<int>("AccessFailedCount")
.HasColumnType("INTEGER");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<bool>("EmailConfirmed")
.HasColumnType("INTEGER");
b.Property<bool>("LockoutEnabled")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("TEXT");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("PasswordHash")
.HasColumnType("TEXT");
b.Property<string>("PhoneNumber")
.HasColumnType("TEXT");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("INTEGER");
b.Property<string>("SecurityStamp")
.HasColumnType("TEXT");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("INTEGER");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("ProviderKey")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("ProviderDisplayName")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.HasColumnType("TEXT");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Campaign", b =>
{
b.Property<int>("CampaignId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("CampaignName")
.HasColumnType("TEXT");
b.Property<string>("OwnerId")
.HasColumnType("TEXT");
b.HasKey("CampaignId");
b.HasIndex("OwnerId");
b.HasIndex("CampaignName", "OwnerId")
.IsUnique();
b.ToTable("Campaigns");
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Map", b =>
{
b.Property<int>("MapId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("CampaignId")
.HasColumnType("INTEGER");
b.Property<string>("MapName")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("MapId");
b.HasIndex("CampaignId");
b.ToTable("Maps");
});
modelBuilder.Entity("Sledgemapper.Api.Models.MapLog", b =>
{
b.Property<int>("MapLogId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Object")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("Operation")
.IsRequired()
.HasMaxLength(1)
.HasColumnType("TEXT");
b.Property<int>("SessionId")
.HasColumnType("INTEGER");
b.Property<double>("Timestamp")
.HasColumnType("REAL");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<int>("UserId")
.HasColumnType("INTEGER");
b.HasKey("MapLogId");
b.ToTable("MapLogs");
});
modelBuilder.Entity("Sledgemapper.Api.Models.Session", b =>
{
b.Property<int>("SessionId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("OwnerUserId")
.HasColumnType("INTEGER");
b.Property<string>("SessionName")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("SessionId");
b.ToTable("Sessions");
});
modelBuilder.Entity("Sledgemapper.Api.Models.SessionUser", b =>
{
b.Property<int>("SessionUserId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("SessionId")
.HasColumnType("INTEGER");
b.Property<int>("UserId")
.HasColumnType("INTEGER");
b.HasKey("SessionUserId");
b.ToTable("SessionUsers");
});
modelBuilder.Entity("Sledgemapper.Api.Models.Snapshot", b =>
{
b.Property<int>("SnapshotId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Object")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("SessionId")
.HasColumnType("INTEGER");
b.Property<double>("Timestamp")
.HasColumnType("REAL");
b.HasKey("SnapshotId");
b.ToTable("Snapshots");
});
modelBuilder.Entity("Sledgemapper.Api.Models.UserConnection", b =>
{
b.Property<int>("UserConnectionId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ConnectionId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("UserId")
.HasColumnType("INTEGER");
b.HasKey("UserConnectionId");
b.ToTable("UserConnections");
});
modelBuilder.Entity("Sledgemapper.Entities.User", b =>
{
b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser");
b.Property<string>("FirstName")
.HasColumnType("TEXT");
b.Property<string>("Initials")
.HasColumnType("TEXT");
b.Property<string>("LastName")
.HasColumnType("TEXT");
b.Property<byte[]>("PasswordSalt")
.HasColumnType("BLOB");
b.Property<string>("Username")
.HasColumnType("TEXT");
b.ToTable("Users");
});
modelBuilder.Entity("CampaignUser", b =>
{
b.HasOne("Sledgemapper.Api.Core.Entities.Campaign", null)
.WithMany()
.HasForeignKey("CampaignsCampaignId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Sledgemapper.Entities.User", null)
.WithMany()
.HasForeignKey("InvitedUsersId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Campaign", b =>
{
b.HasOne("Sledgemapper.Entities.User", "Owner")
.WithMany()
.HasForeignKey("OwnerId");
b.Navigation("Owner");
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Map", b =>
{
b.HasOne("Sledgemapper.Api.Core.Entities.Campaign", null)
.WithMany("Maps")
.HasForeignKey("CampaignId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Sledgemapper.Entities.User", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithOne()
.HasForeignKey("Sledgemapper.Entities.User", "Id")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Campaign", b =>
{
b.Navigation("Maps");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,315 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Sledgemapper.Api.Migrations
{
public partial class renametable : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Campaigns_Users_OwnerId",
table: "Campaigns");
migrationBuilder.DropColumn(
name: "PasswordHash",
table: "Users");
migrationBuilder.AlterColumn<string>(
name: "Id",
table: "Users",
type: "TEXT",
nullable: false,
oldClrType: typeof(int),
oldType: "INTEGER")
.OldAnnotation("Sqlite:Autoincrement", true);
migrationBuilder.AlterColumn<string>(
name: "InvitedUsersId",
table: "CampaignUser",
type: "TEXT",
nullable: false,
oldClrType: typeof(int),
oldType: "INTEGER");
migrationBuilder.AlterColumn<string>(
name: "OwnerId",
table: "Campaigns",
type: "TEXT",
nullable: true,
oldClrType: typeof(int),
oldType: "INTEGER");
migrationBuilder.CreateTable(
name: "AspNetRoles",
columns: table => new
{
Id = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
NormalizedName = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
ConcurrencyStamp = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<string>(type: "TEXT", nullable: false),
UserName = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
Email = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
NormalizedEmail = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(type: "INTEGER", nullable: false),
PasswordHash = table.Column<string>(type: "TEXT", nullable: true),
SecurityStamp = table.Column<string>(type: "TEXT", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "TEXT", nullable: true),
PhoneNumber = table.Column<string>(type: "TEXT", nullable: true),
PhoneNumberConfirmed = table.Column<bool>(type: "INTEGER", nullable: false),
TwoFactorEnabled = table.Column<bool>(type: "INTEGER", nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(type: "TEXT", nullable: true),
LockoutEnabled = table.Column<bool>(type: "INTEGER", nullable: false),
AccessFailedCount = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
RoleId = table.Column<string>(type: "TEXT", nullable: false),
ClaimType = table.Column<string>(type: "TEXT", nullable: true),
ClaimValue = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
UserId = table.Column<string>(type: "TEXT", nullable: false),
ClaimType = table.Column<string>(type: "TEXT", nullable: true),
ClaimValue = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "TEXT", maxLength: 128, nullable: false),
ProviderKey = table.Column<string>(type: "TEXT", maxLength: 128, nullable: false),
ProviderDisplayName = table.Column<string>(type: "TEXT", nullable: true),
UserId = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<string>(type: "TEXT", nullable: false),
RoleId = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<string>(type: "TEXT", nullable: false),
LoginProvider = table.Column<string>(type: "TEXT", maxLength: 128, nullable: false),
Name = table.Column<string>(type: "TEXT", maxLength: 128, nullable: false),
Value = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_AspNetRoleClaims_RoleId",
table: "AspNetRoleClaims",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "AspNetRoles",
column: "NormalizedName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserRoles_RoleId",
table: "AspNetUserRoles",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true);
migrationBuilder.AddForeignKey(
name: "FK_Campaigns_Users_OwnerId",
table: "Campaigns",
column: "OwnerId",
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_Users_AspNetUsers_Id",
table: "Users",
column: "Id",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Campaigns_Users_OwnerId",
table: "Campaigns");
migrationBuilder.DropForeignKey(
name: "FK_Users_AspNetUsers_Id",
table: "Users");
migrationBuilder.DropTable(
name: "AspNetRoleClaims");
migrationBuilder.DropTable(
name: "AspNetUserClaims");
migrationBuilder.DropTable(
name: "AspNetUserLogins");
migrationBuilder.DropTable(
name: "AspNetUserRoles");
migrationBuilder.DropTable(
name: "AspNetUserTokens");
migrationBuilder.DropTable(
name: "AspNetRoles");
migrationBuilder.DropTable(
name: "AspNetUsers");
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "Users",
type: "INTEGER",
nullable: false,
oldClrType: typeof(string),
oldType: "TEXT")
.Annotation("Sqlite:Autoincrement", true);
migrationBuilder.AddColumn<byte[]>(
name: "PasswordHash",
table: "Users",
type: "BLOB",
nullable: true);
migrationBuilder.AlterColumn<int>(
name: "InvitedUsersId",
table: "CampaignUser",
type: "INTEGER",
nullable: false,
oldClrType: typeof(string),
oldType: "TEXT");
migrationBuilder.AlterColumn<int>(
name: "OwnerId",
table: "Campaigns",
type: "INTEGER",
nullable: false,
defaultValue: 0,
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AddForeignKey(
name: "FK_Campaigns_Users_OwnerId",
table: "Campaigns",
column: "OwnerId",
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
}

View file

@ -0,0 +1,503 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Sledgemapper.Api.Infrastructure.Data;
namespace Sledgemapper.Api.Migrations
{
[DbContext(typeof(SledgemapperDbContext))]
partial class SledgemapperDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "5.0.3");
modelBuilder.Entity("CampaignUser", b =>
{
b.Property<int>("CampaignsCampaignId")
.HasColumnType("INTEGER");
b.Property<string>("InvitedUsersId")
.HasColumnType("TEXT");
b.HasKey("CampaignsCampaignId", "InvitedUsersId");
b.HasIndex("InvitedUsersId");
b.ToTable("CampaignUser");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<int>("AccessFailedCount")
.HasColumnType("INTEGER");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<bool>("EmailConfirmed")
.HasColumnType("INTEGER");
b.Property<bool>("LockoutEnabled")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("TEXT");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("PasswordHash")
.HasColumnType("TEXT");
b.Property<string>("PhoneNumber")
.HasColumnType("TEXT");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("INTEGER");
b.Property<string>("SecurityStamp")
.HasColumnType("TEXT");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("INTEGER");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("ProviderKey")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("ProviderDisplayName")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.HasColumnType("TEXT");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Campaign", b =>
{
b.Property<int>("CampaignId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("CampaignName")
.HasColumnType("TEXT");
b.Property<string>("OwnerId")
.HasColumnType("TEXT");
b.HasKey("CampaignId");
b.HasIndex("OwnerId");
b.HasIndex("CampaignName", "OwnerId")
.IsUnique();
b.ToTable("Campaigns");
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Map", b =>
{
b.Property<int>("MapId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("CampaignId")
.HasColumnType("INTEGER");
b.Property<string>("MapName")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("MapId");
b.HasIndex("CampaignId");
b.ToTable("Maps");
});
modelBuilder.Entity("Sledgemapper.Api.Models.MapLog", b =>
{
b.Property<int>("MapLogId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Object")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("Operation")
.IsRequired()
.HasMaxLength(1)
.HasColumnType("TEXT");
b.Property<int>("SessionId")
.HasColumnType("INTEGER");
b.Property<double>("Timestamp")
.HasColumnType("REAL");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<int>("UserId")
.HasColumnType("INTEGER");
b.HasKey("MapLogId");
b.ToTable("MapLogs");
});
modelBuilder.Entity("Sledgemapper.Api.Models.Session", b =>
{
b.Property<int>("SessionId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("OwnerUserId")
.HasColumnType("INTEGER");
b.Property<string>("SessionName")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("SessionId");
b.ToTable("Sessions");
});
modelBuilder.Entity("Sledgemapper.Api.Models.SessionUser", b =>
{
b.Property<int>("SessionUserId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("SessionId")
.HasColumnType("INTEGER");
b.Property<int>("UserId")
.HasColumnType("INTEGER");
b.HasKey("SessionUserId");
b.ToTable("SessionUsers");
});
modelBuilder.Entity("Sledgemapper.Api.Models.Snapshot", b =>
{
b.Property<int>("SnapshotId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Object")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("SessionId")
.HasColumnType("INTEGER");
b.Property<double>("Timestamp")
.HasColumnType("REAL");
b.HasKey("SnapshotId");
b.ToTable("Snapshots");
});
modelBuilder.Entity("Sledgemapper.Api.Models.UserConnection", b =>
{
b.Property<int>("UserConnectionId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ConnectionId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("UserId")
.HasColumnType("INTEGER");
b.HasKey("UserConnectionId");
b.ToTable("UserConnections");
});
modelBuilder.Entity("Sledgemapper.Entities.User", b =>
{
b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser");
b.Property<string>("FirstName")
.HasColumnType("TEXT");
b.Property<string>("Initials")
.HasColumnType("TEXT");
b.Property<string>("LastName")
.HasColumnType("TEXT");
b.Property<byte[]>("PasswordSalt")
.HasColumnType("BLOB");
b.Property<string>("Username")
.HasColumnType("TEXT");
b.ToTable("Users");
});
modelBuilder.Entity("CampaignUser", b =>
{
b.HasOne("Sledgemapper.Api.Core.Entities.Campaign", null)
.WithMany()
.HasForeignKey("CampaignsCampaignId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Sledgemapper.Entities.User", null)
.WithMany()
.HasForeignKey("InvitedUsersId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Campaign", b =>
{
b.HasOne("Sledgemapper.Entities.User", "Owner")
.WithMany()
.HasForeignKey("OwnerId");
b.Navigation("Owner");
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Map", b =>
{
b.HasOne("Sledgemapper.Api.Core.Entities.Campaign", null)
.WithMany("Maps")
.HasForeignKey("CampaignId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Sledgemapper.Entities.User", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithOne()
.HasForeignKey("Sledgemapper.Entities.User", "Id")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Campaign", b =>
{
b.Navigation("Maps");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace Sledgemapper.Models.Users
{
public class AuthResult
{
public string Token { get; set; }
public bool Result { get; set; }
public List<string> Errors { get; set; }
}
}

View file

@ -6,16 +6,18 @@ namespace Sledgemapper.Models.Users
{ {
[Required] [Required]
public string FirstName { get; set; } public string FirstName { get; set; }
[Required]
public string UserName { get; set; }
[Required] [Required]
public string LastName { get; set; } public string LastName { get; set; }
[Required] [Required]
public string Username { get; set; } public string Email { get; set; }
[Required] [Required]
public string Password { get; set; } public string Password { get; set; }
[Required] [Required]
public string Initials { get; set; } public string Initials { get; set; }
} }

View file

@ -0,0 +1,7 @@
namespace Sledgemapper.Models.Users
{
public class RegistrationResponse : AuthResult
{
}
}

View file

@ -1,10 +0,0 @@
namespace Sledgemapper.Models.Users
{
public class UpdateModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
}

View file

@ -1,13 +0,0 @@
namespace Sledgemapper.Entities
{
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Username { get; set; }
public string Initials { get; set; }
public byte[] PasswordHash { get; set; }
public byte[] PasswordSalt { get; set; }
}
}

View file

@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations;
namespace Sledgemapper.Models.Users
{
public class UserLoginRequest
{
[Required]
public string Email { get; set; }
[Required]
public string Password { get; set; }
}
}

View file

@ -1,11 +0,0 @@
namespace Sledgemapper.Models.Users
{
public class UserModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Username { get; set; }
public string Initials { get; set; }
}
}

View file

@ -10,11 +10,15 @@
<PackageReference Include="mediatr" Version="9.0.0" /> <PackageReference Include="mediatr" Version="9.0.0" />
<PackageReference Include="mediatr.extensions.microsoft.dependencyinjection" Version="9.0.0" /> <PackageReference Include="mediatr.extensions.microsoft.dependencyinjection" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="5.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.3"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.3" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="5.0.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.0.7" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.8.0" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.8.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.3" />
</ItemGroup> </ItemGroup>

View file

@ -1,11 +1,8 @@
using System; using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Sledgemapper.Api.Infrastructure.Data; using Sledgemapper.Api.Infrastructure.Data;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using MediatR; using MediatR;
@ -13,10 +10,7 @@ using Microsoft.IdentityModel.Tokens;
using Sledgemapper.Helpers; using Sledgemapper.Helpers;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using System.Text; using System.Text;
using AutoMapper;
using System.Security.Claims;
using Sledgemapper.Api.Hubs; using Sledgemapper.Api.Hubs;
using Sledgemapper.Api.Infrastructure.Services;
namespace Sledgemapper.Api namespace Sledgemapper.Api
{ {
@ -31,93 +25,67 @@ namespace Sledgemapper.Api
} }
// This method gets called by the runtime. Use this method to add services to the container. // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
// if (_env.IsProduction()) services.AddCors();
// services.AddDbContext<DataContext>();
// else
// services.AddDbContext<DataContext, SqliteDataContext>();
// services.AddRazorPages();
services.AddCors();
services.AddControllers(); services.AddControllers();
services.AddSignalR(); services.AddSignalR();
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
services.AddMediatR(typeof(Startup)); services.AddMediatR(typeof(Startup));
services.AddDbContext<SledgemapperDbContext>(options => {options.UseSqlite("Data Source=db/sledgemapper.db"); options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);}); services.AddDbContext<SledgemapperDbContext>(options => { options.UseSqlite("Data Source=db/sledgemapper.db"); options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); });
// services.AddEntityFrameworkSqlite().AddDbContext<SledgemapperDbContext>(); services.Configure<JwtConfig>(Configuration.GetSection("JwtConfig"));
// configure strongly typed settings objects
var c = Configuration.GetSection("AppSettings");
var appSettingsSection = Configuration.GetSection("AppSettings");
services.Configure<AppSettings>(appSettingsSection);
// configure jwt authentication // configure DI for application services
var appSettings = appSettingsSection.Get<AppSettings>();
var key = Encoding.ASCII.GetBytes(appSettings.Secret); // within this section we are configuring the authentication and setting the default scheme
services.AddAuthentication(x => services.AddAuthentication(options =>
{ {
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}) })
.AddJwtBearer(x => .AddJwtBearer(jwt =>
{ {
x.Events = new JwtBearerEvents var key = Encoding.ASCII.GetBytes(Configuration["JwtConfig:Secret"]);
jwt.SaveToken = true;
jwt.TokenValidationParameters = new TokenValidationParameters
{ {
OnTokenValidated = context => ValidateIssuerSigningKey = true, // this will validate the 3rd part of the jwt token using the secret that we added in the appsettings and verify we have generated the jwt token
{ IssuerSigningKey = new SymmetricSecurityKey(key), // Add the secret key to our Jwt encryption
var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();
var userId = int.Parse(context.Principal.Identity.Name);
var user = userService.GetById(userId);
if (user == null)
{
// return unauthorized if user no longer exists
context.Fail("Unauthorized");
}
context.HttpContext.User.Claims.Append(new Claim(ClaimTypes.Name, user.Username));
context.HttpContext.User.Claims.Append(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
return Task.CompletedTask;
}
};
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false, ValidateIssuer = false,
ValidateAudience = false ValidateAudience = false,
RequireExpirationTime = false,
ValidateLifetime = true
}; };
}); });
// configure DI for application services services.AddDefaultIdentity<Entities.User>(options => options.SignIn.RequireConfirmedAccount = false)
services.AddScoped<IUserService, UserService>(); .AddEntityFrameworkStores<SledgemapperDbContext>();
services.AddSwaggerGen();
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, SledgemapperDbContext dataContext) public void Configure(IApplicationBuilder app, IWebHostEnvironment env, SledgemapperDbContext dataContext)
{ {
dataContext.Database.Migrate(); // Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// if (env.IsDevelopment()) // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// { // specifying the Swagger JSON endpoint.
// app.UseDeveloperExceptionPage(); app.UseSwaggerUI(c =>
// } {
// else c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
// { });
// app.UseExceptionHandler("/Error");
// // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
// app.UseHsts();
// }
// //app.UseHttpsRedirection(); dataContext.Database.Migrate();
// app.UseStaticFiles();
app.UseRouting(); app.UseRouting();
// global cors policy
app.UseCors(x => x app.UseCors(x => x
.AllowAnyOrigin() .AllowAnyOrigin()
.AllowAnyMethod() .AllowAnyMethod()
@ -132,9 +100,7 @@ namespace Sledgemapper.Api
app.UseEndpoints(endpoints => app.UseEndpoints(endpoints =>
{ {
// endpoints.MapRazorPages();
endpoints.MapHub<SledgemapperHub>("/sledgemapperhub"); endpoints.MapHub<SledgemapperHub>("/sledgemapperhub");
}); });
} }
} }

View file

@ -1,16 +1,16 @@
{ {
"AppSettings": { "JwtConfig": {
"Secret": "THIS IS USED TO SIGN AND VERIFY JWT TOKENS, REPLACE IT WITH YOUR OWN SECRET, IT CAN BE ANY STRING" "Secret": "ALy9zGFVZBza9cju458dVC2rBdwPqfb7"
}, },
"ConnectionStrings": { "ConnectionStrings": {
"WebApiDatabase": "ENTER PRODUCTION SQL SERVER CONNECTION STRING HERE" "WebApiDatabase": "ENTER PRODUCTION SQL SERVER CONNECTION STRING HERE"
}, },
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"Default": "Information", "Default": "Information",
"Microsoft": "Warning", "Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information" "Microsoft.Hosting.Lifetime": "Information"
} }
}, },
"AllowedHosts": "*" "AllowedHosts": "*"
} }

View file

@ -1,4 +1,4 @@
/* Generated by MyraPad at 11/02/2021 23:16:18 */ /* Generated by MyraPad at 19/02/2021 14:56:38 */
using Myra; using Myra;
using Myra.Graphics2D; using Myra.Graphics2D;
using Myra.Graphics2D.TextureAtlases; using Myra.Graphics2D.TextureAtlases;
@ -103,17 +103,17 @@ namespace Sledgemapper.UI
var menuSeparator4 = new MenuSeparator(); var menuSeparator4 = new MenuSeparator();
MenuCampaignInvite = new MenuItem(); MenuCampaignPlayers = new MenuItem();
MenuCampaignInvite.Text = "&Invite"; MenuCampaignPlayers.Text = "&Players";
MenuCampaignInvite.ShortcutText = "Ctrl+I"; MenuCampaignPlayers.ShortcutText = "CtrI+P";
MenuCampaignInvite.Id = "MenuCampaignInvite"; MenuCampaignPlayers.Id = "MenuCampaignPlayers";
var menuItem2 = new MenuItem(); var menuItem2 = new MenuItem();
menuItem2.Text = "C&ampaign"; menuItem2.Text = "C&ampaign";
menuItem2.Items.Add(MenuCampaingNew); menuItem2.Items.Add(MenuCampaingNew);
menuItem2.Items.Add(MenuCampaignOpen); menuItem2.Items.Add(MenuCampaignOpen);
menuItem2.Items.Add(menuSeparator4); menuItem2.Items.Add(menuSeparator4);
menuItem2.Items.Add(MenuCampaignInvite); menuItem2.Items.Add(MenuCampaignPlayers);
MenuMapNew = new MenuItem(); MenuMapNew = new MenuItem();
MenuMapNew.Text = "&New"; MenuMapNew.Text = "&New";
@ -348,7 +348,7 @@ namespace Sledgemapper.UI
public MenuItem MenuConnectUpload; public MenuItem MenuConnectUpload;
public MenuItem MenuCampaingNew; public MenuItem MenuCampaingNew;
public MenuItem MenuCampaignOpen; public MenuItem MenuCampaignOpen;
public MenuItem MenuCampaignInvite; public MenuItem MenuCampaignPlayers;
public MenuItem MenuMapNew; public MenuItem MenuMapNew;
public MenuItem MenuMapOpen; public MenuItem MenuMapOpen;
public MenuItem MenuViewShowNotes; public MenuItem MenuViewShowNotes;

View file

@ -27,7 +27,7 @@
<MenuItem Text="&amp;New" ShortcutText="Ctrl+N" Id="MenuCampaingNew" /> <MenuItem Text="&amp;New" ShortcutText="Ctrl+N" Id="MenuCampaingNew" />
<MenuItem Text="&amp;Open" ShortcutText="Ctrl+O" Id="MenuCampaignOpen" /> <MenuItem Text="&amp;Open" ShortcutText="Ctrl+O" Id="MenuCampaignOpen" />
<MenuSeparator /> <MenuSeparator />
<MenuItem Text="&amp;Invite" ShortcutText="Ctrl+I" Id="MenuCampaignInvite" /> <MenuItem Text="&amp;Players" ShortcutText="CtrI+P" Id="MenuCampaignPlayers" />
</MenuItem> </MenuItem>
<MenuItem Text="&amp;Map" ShortcutText="Ctrl+M"> <MenuItem Text="&amp;Map" ShortcutText="Ctrl+M">
<MenuItem Text="&amp;New" ShortcutText="Ctrl+N" Id="MenuMapNew" /> <MenuItem Text="&amp;New" ShortcutText="Ctrl+N" Id="MenuMapNew" />