add authentication, add basic routes for user

tests
maxime 1 year ago
parent 7bf6f9c5ec
commit 82e59e0c86

2
.gitignore vendored

@ -1,6 +1,8 @@
.idea
.vs
*.db*
# Build results
[Dd]ebug/

@ -6,11 +6,19 @@
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<StartWorkingDirectory>$(MSBuildProjectDirectory)</StartWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0"/>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.4.0-preview1" />
<PackageReference Include="Microsoft.IdentityModel.Protocols" Version="7.4.0-preview1" />
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="7.4.0-preview1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
<ItemGroup>
@ -20,7 +28,21 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DbServices\DbServices.csproj" />
<ProjectReference Include="..\Services\Services.csproj" />
<ProjectReference Include="..\StubContext\StubContext.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.AspNetCore.Authentication.JwtBearer">
<HintPath>..\..\..\..\.nuget\packages\microsoft.aspnetcore.authentication.jwtbearer\8.0.0\lib\net8.0\Microsoft.AspNetCore.Authentication.JwtBearer.dll</HintPath>
</Reference>
<Reference Include="Microsoft.IdentityModel.Tokens">
<HintPath>..\..\..\..\.nuget\packages\microsoft.identitymodel.tokens\7.0.3\lib\net8.0\Microsoft.IdentityModel.Tokens.dll</HintPath>
</Reference>
<Reference Include="System.IdentityModel.Tokens.Jwt">
<HintPath>..\..\..\..\.nuget\packages\system.identitymodel.tokens.jwt\7.0.3\lib\net8.0\System.IdentityModel.Tokens.Jwt.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

@ -0,0 +1,16 @@
using API.Validation;
using Microsoft.AspNetCore.Mvc;
namespace API;
public static class AppHttpContext
{
public static int CurrentUserId(this ControllerBase b)
{
var idClaim = b.HttpContext
.User
.Claims
.First(c => c.Type == IdentityData.IdUserClaimName);
return int.Parse(idClaim.Value);
}
}

@ -0,0 +1,10 @@
namespace API;
internal static class Constants
{
public const string DefaultProfilePicture =
"https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png";
}

@ -5,11 +5,12 @@ using Services;
namespace API.Controllers;
public class AccountsController(UserService service) : ControllerBase
[ApiController]
public class AccountsController(IUserService service) : ControllerBase
{
private static string _defaultProfilePicture =
private const string DefaultProfilePicture =
"https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png";
[HttpGet("/admin/list-users")]
public async Task<IEnumerable<User>> ListUsers(
[Range(0, int.MaxValue, ErrorMessage = "Only positive number allowed")]
@ -51,7 +52,7 @@ public class AccountsController(UserService service) : ControllerBase
bool isAdmin = false
)
{
return service.CreateUser(username, email, password, _defaultProfilePicture, isAdmin);
return service.CreateUser(username, email, password, DefaultProfilePicture, isAdmin);
}
[HttpDelete("/admin/user")]
@ -72,7 +73,7 @@ public class AccountsController(UserService service) : ControllerBase
{
try
{
await service.UpdateUser(new User(id, username, email, _defaultProfilePicture, isAdmin));
await service.UpdateUser(new User(id, username, email, DefaultProfilePicture, isAdmin));
return Ok();
}
catch (ServiceException e)

@ -0,0 +1,99 @@
using System.ComponentModel.DataAnnotations;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using API.Validation;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using Model;
using Services;
using Services.Failures;
namespace API.Controllers;
[ApiController]
public class AuthenticationController(IUserService service, IConfiguration config) : ControllerBase
{
private readonly SymmetricSecurityKey _key = new(Encoding.UTF8.GetBytes(config["JWT:Key"]!));
private static readonly TimeSpan TokenLifetime = TimeSpan.FromMinutes(50);
public record GenerateTokenRequest(
[MaxLength(256, ErrorMessage = "Email address is too wide")]
[EmailAddress]
string Email,
[MaxLength(256, ErrorMessage = "Password is too wide")]
string Password);
private record AuthenticationResponse(String Token, DateTime ExpirationDate);
[HttpPost("/auth/token")]
public async Task<IActionResult> GenerateToken([FromBody] GenerateTokenRequest req)
{
var user = await service.Authorize(req.Email, req.Password);
if (user == null)
return BadRequest(new Dictionary<string, string[]>
{
{ "unauthorized", ["Invalid email or password"] }
});
var (jwt, expirationDate) = GenerateJwt(user);
return Ok(new AuthenticationResponse(jwt, expirationDate));
}
public record RegisterAccountRequest(
[MaxLength(256, ErrorMessage = "name is longer than 256")]
string Username,
[MaxLength(256, ErrorMessage = "email is longer than 256")]
[EmailAddress]
string Email,
[StringLength(256, MinimumLength = 4, ErrorMessage = "password length must be between 4 and 256")]
string Password);
[HttpPost("/auth/register")]
public async Task<IActionResult> RegisterAccount([FromBody] RegisterAccountRequest req)
{
if (await service.GetUser(req.Email) != null)
{
return BadRequest(new Dictionary<string, string[]>
{
{ "email", ["The email address already exists"] }
});
}
var user = await service.CreateUser(req.Username, req.Email, req.Password, Constants.DefaultProfilePicture,
false);
var (jwt, expirationDate) = GenerateJwt(user);
return Ok(new AuthenticationResponse(jwt, expirationDate));
}
private (string, DateTime) GenerateJwt(User user)
{
var tokenHandler = new JwtSecurityTokenHandler();
var claims = new List<Claim>
{
new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new(JwtRegisteredClaimNames.Sub, user.Email),
new(JwtRegisteredClaimNames.Email, user.Email),
new(IdentityData.IdUserClaimName, user.Id.ToString()),
new(IdentityData.AdminUserClaimName, user.IsAdmin.ToString())
};
var expirationDate = DateTime.UtcNow.Add(TokenLifetime);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = expirationDate,
SigningCredentials = new SigningCredentials(_key, SecurityAlgorithms.HmacSha256)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var jwt = tokenHandler.WriteToken(token);
return ("Bearer " + jwt, expirationDate);
}
}

@ -0,0 +1,32 @@
using System.ComponentModel.DataAnnotations;
using API.Validation;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Services;
namespace API.Controllers;
[ApiController]
public class TacticController(ITacticService service) : ControllerBase
{
[HttpPut("/tactic/{tacticId:int}/name")]
[Authorize]
public async Task<IActionResult> UpdateName(
int tacticId,
[Range(1, 50)] [Name] string name)
{
var userId = this.CurrentUserId();
if (!await service.HasAnyRights(userId, tacticId))
{
return Forbid();
}
return await service.UpdateName(tacticId, name) ? Ok() : NotFound();
}
// [Authorize]
// public async Task<IActionResult> SetTacticStepContent(int tacticId, int stepId)
// {
//
// }
}

@ -0,0 +1,31 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Model;
using Services;
namespace API.Controllers;
[ApiController]
public class UserController(IUserService users, ITeamService teams, ITacticService tactics) : ControllerBase
{
[Authorize]
[HttpGet("/user")]
public async Task<User> GetUser()
{
var userId = this.CurrentUserId();
return (await users.GetUser(userId))!;
}
public record GetUserDataResponse(User User, Team[] Teams, Tactic[] Tactics);
[Authorize]
[HttpGet("/user-data")]
public async Task<GetUserDataResponse> GetUserData()
{
var userId = this.CurrentUserId();
var user = await users.GetUser(userId);
var userTeams = await teams.ListTeamsOf(userId);
var userTactics = await tactics.ListTacticsOf(userId);
return new GetUserDataResponse(user!, userTeams.ToArray(), userTactics.ToArray());
}
}

@ -1,10 +1,58 @@
using System.Net.Mime;
using API.Validation;
using DbServices;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using Services;
using StubContext;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
var config = builder.Configuration;
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddControllers();
builder.Services.AddControllers()
.ConfigureApiBehaviorOptions(options => options.InvalidModelStateResponseFactory = context =>
new BadRequestObjectResult(context.ModelState)
{
ContentTypes = { MediaTypeNames.Application.Json }
});
builder.Services.AddCors(options =>
options.AddPolicy("cors", policy =>
policy
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
));
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(
x => x.TokenValidationParameters = new TokenValidationParameters
{
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["JWT:Key"]!)),
ValidateLifetime = true,
ValidateIssuer = false,
ValidateAudience = false,
ValidateIssuerSigningKey = true
}
);
builder.Services.AddAuthorization(options =>
options.AddPolicy(IdentityData.AdminUserPolicyName, p => p.RequireClaim(IdentityData.AdminUserClaimName)));
var appContext = new StubAppContext();
appContext.Database.EnsureCreated();
builder.Services.AddScoped<IUserService>(_ => new DbUserService(appContext));
builder.Services.AddScoped<ITeamService>(_ => new DbTeamService(appContext));
builder.Services.AddScoped<ITacticService>(_ => new DbTacticService(appContext));
var app = builder.Build();
@ -15,7 +63,13 @@ if (app.Environment.IsDevelopment())
app.UseSwaggerUI();
}
app.MapControllers();
app.UseHttpsRedirection();
app.UseCors("cors");
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
app.Run();

@ -12,7 +12,7 @@
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchBrowser": false,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5254",
"environmentVariables": {

@ -0,0 +1,9 @@
namespace API.Validation;
internal class IdentityData
{
public const string AdminUserClaimName = "admin";
public const string AdminUserPolicyName = "Admin";
public const string IdUserClaimName = "id";
}

@ -0,0 +1,28 @@
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
namespace API.Validation;
public partial class NameAttribute : ValidationAttribute
{
protected override ValidationResult? IsValid(object? value, ValidationContext context)
{
var name = context.DisplayName;
if (value is not string str)
{
return new ValidationResult($"{name} should be a string.");
}
if (NameRegex().Match(str).Success)
{
return ValidationResult.Success;
}
return new ValidationResult(
$"{name} should only contain numbers, letters, accents, spaces, _ and - characters.");
}
[GeneratedRegex("[^[0-9a-zA-Zà-üÀ-Ü _-]*$]")]
private static partial Regex NameRegex();
}

@ -1,8 +1,12 @@
{
"JWT": {
"Key": "Remember to use a secret key on prod"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.Authentication": "Trace"
}
},
"AllowedHosts": "*"

@ -7,14 +7,15 @@ namespace AppContext;
public class AppContext(DbContextOptions<AppContext> options) : DbContext(options)
{
public DbSet<UserEntity> Users { get; }
public DbSet<TacticEntity> Tactics { get; }
public DbSet<TeamEntity> Teams { get; }
public DbSet<MemberEntity> Members { get; }
public DbSet<UserEntity> Users { get; init; }
public DbSet<TacticEntity> Tactics { get; init; }
public DbSet<TeamEntity> Teams { get; init; }
public DbSet<MemberEntity> Members { get; init; }
public DbSet<TacticStepEntity> TacticSteps { get; set; }
public AppContext() : this(
new DbContextOptionsBuilder<AppContext>()
.UseSqlite("Data Source=database.db")
.UseSqlite("DataSource=database.db")
.Options
)
{
@ -29,6 +30,12 @@ public class AppContext(DbContextOptions<AppContext> options) : DbContext(option
v => HashString(v),
v => v
);
builder.Entity<MemberEntity>()
.HasKey("UserId", "TeamId");
builder.Entity<TacticStepEntity>()
.HasKey("TacticId", "StepId");
}
private static string HashString(string str)

@ -8,6 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0">

@ -2,6 +2,7 @@ namespace AppContext.Entities;
public class MemberEntity
{
public int TeamId { get; set; }
public TeamEntity? Team { get; set; }

@ -13,4 +13,7 @@ public class TacticEntity
public CourtType Type { get; set; }
public required string JsonContent { get; set; }
public required int RootStepId { get; set; }
public TacticStepEntity RootStep { get; set; }
}

@ -0,0 +1,16 @@
using Model;
namespace AppContext.Entities;
public class TacticStepEntity
{
public required int TacticId { get; set; }
public Tactic Tactic { get; set; }
public required int ParentId { get; set; }
public TacticStepEntity Parent { get; set; }
public IEnumerable<TacticStepEntity> Children { get; set; } = new List<TacticStepEntity>();
public int StepId { get; set; }
public required string JsonContent { get; set; }
}

@ -10,8 +10,13 @@ public static class EntitiesToModels
return new User(entity.Id, entity.Name, entity.Email, entity.ProfilePicture, entity.IsAdmin);
}
// public static Team ToModel(this TeamEntity entity)
// {
//
// }
public static Tactic ToModel(this TacticEntity entity)
{
return new Tactic(entity.Id, entity.Name, entity.OwnerId, entity.Type, entity.CreationDate);
}
public static Team ToModel(this TeamEntity entity)
{
return new Team(entity.Id, entity.Name, entity.Picture, entity.MainColor, entity.SecondColor);
}
}

@ -0,0 +1,115 @@
using System.Collections;
using AppContext.Entities;
using Converters;
using Microsoft.EntityFrameworkCore;
using Model;
using Services;
namespace DbServices;
public class DbTacticService(AppContext.AppContext context) : ITacticService
{
public Task<IEnumerable<Tactic>> ListTacticsOf(int userId)
{
return Task.FromResult(
context.Tactics
.Where(t => t.OwnerId == userId)
.AsEnumerable()
.Select(e => e.ToModel())
);
}
public async Task<bool> HasAnyRights(int userId, int tacticId)
{
var tacticEntity = await context.Tactics.FirstOrDefaultAsync(u => u.Id == tacticId);
if (tacticEntity == null)
return false;
return tacticEntity.OwnerId == userId;
}
public async Task<bool> UpdateName(int tacticId, string name)
{
var entity = await context.Tactics.FirstOrDefaultAsync(t => t.Id == tacticId);
if (entity == null)
return false;
entity.Name = name;
return await context.SaveChangesAsync() > 0;
}
public async Task<bool> SetTacticStepContent(int tacticId, int stepId, string json)
{
var entity = await context.TacticSteps
.FirstOrDefaultAsync(t => t.TacticId == tacticId && t.StepId == stepId);
if (entity == null)
return false;
entity.JsonContent = json;
return await context.SaveChangesAsync() > 0;
}
public async Task<string?> GetTacticStepContent(int tacticId, int stepId)
{
return (await context
.TacticSteps
.FirstOrDefaultAsync(t => t.TacticId == tacticId && t.StepId == stepId)
)?.JsonContent;
}
public Task<IEnumerable<Tactic>> ListUserTactics(int userId)
{
return Task.FromResult(context
.Tactics
.Where(t => t.OwnerId == userId)
.AsEnumerable()
.Select(e => e.ToModel())
);
}
public async Task<int> AddTacticStep(int tacticId, int parentStepId, string initialJson)
{
var entity = new TacticStepEntity
{
JsonContent = "{components: []}",
ParentId = parentStepId,
TacticId = tacticId
};
await context.AddAsync(entity);
await context.SaveChangesAsync();
return entity.StepId;
}
public async Task<bool> RemoveTacticStep(int tacticId, int stepId)
{
var toRemove = new List<int> { stepId };
while (toRemove.Count != 0)
{
var id = toRemove[0];
toRemove.RemoveAt(0);
var step = await context.TacticSteps
.Include(s => s.Children)
.FirstOrDefaultAsync(t => t.TacticId == tacticId && t.StepId == id);
if (step == null)
{
if (id == stepId)
return false;
throw new Exception(
$"step contains a children that does not exists in the database ({tacticId} / {id})"
);
}
var stepChildren = step.Children.Select(s => s.StepId);
toRemove.AddRange(stepChildren);
context.Remove(step);
}
return await context.SaveChangesAsync() > 0;
}
}

@ -0,0 +1,20 @@
using Converters;
using Microsoft.EntityFrameworkCore;
using Model;
using Services;
namespace DbServices;
public class DbTeamService(AppContext.AppContext context) : ITeamService
{
public Task<IEnumerable<Team>> ListTeamsOf(int userId)
{
return Task.FromResult(
context.Teams
.Include(t => t.Members)
.Where(t => t.Members.Any(m => m.UserId == userId))
.AsEnumerable()
.Select(t => t.ToModel())
);
}
}

@ -8,7 +8,7 @@ using Services.Failures;
namespace DbServices;
public class DbUserService(AppContext.AppContext context) : UserService
public class DbUserService(AppContext.AppContext context) : IUserService
{
public Task<IEnumerable<User>> ListUsers(string nameNeedle)
{
@ -34,6 +34,11 @@ public class DbUserService(AppContext.AppContext context) : UserService
return (await context.Users.FirstOrDefaultAsync(e => e.Id == id))?.ToModel();
}
public async Task<User?> GetUser(string email)
{
return (await context.Users.FirstOrDefaultAsync(e => e.Email == email))?.ToModel();
}
public async Task<User> CreateUser(string username, string email, string password, string profilePicture,
bool isAdmin)
{
@ -69,4 +74,12 @@ public class DbUserService(AppContext.AppContext context) : UserService
entity.Id = user.Id;
await context.SaveChangesAsync();
}
public async Task<User?> Authorize(string email, string password)
{
return (await context
.Users
.FirstOrDefaultAsync(u => u.Email == email))
?.ToModel();
}
}

@ -0,0 +1,3 @@
namespace Model;
public record Tactic(int Id, string Name, int OwnerId, CourtType CourtType, DateTime CreationDate);

@ -0,0 +1,3 @@
namespace Model;
public record Team(int Id, string Name, string Picture, string MainColor, string SecondColor);

@ -6,4 +6,9 @@ public record Failure(string Name, string Message)
{
return new("not found", message);
}
public static Failure Forbidden(string message)
{
return new("forbidden", message);
}
}

@ -0,0 +1,18 @@
using Model;
namespace Services;
public interface ITacticService
{
public Task<IEnumerable<Tactic>> ListTacticsOf(int userId);
public Task<bool> HasAnyRights(int userId, int tacticId);
public Task<bool> UpdateName(int tacticId, string name);
public Task<bool> SetTacticStepContent(int tacticId, int stepId, string json);
public Task<string?> GetTacticStepContent(int tacticId, int stepId);
public Task<IEnumerable<Tactic>> ListUserTactics(int userId);
public Task<int> AddTacticStep(int tacticId, int parentStepId, string initialJson);
public Task<bool> RemoveTacticStep(int tacticId, int stepId);
}

@ -0,0 +1,10 @@
using Model;
namespace Services;
public interface ITeamService
{
public Task<IEnumerable<Team>> ListTeamsOf(int userId);
}

@ -2,18 +2,21 @@
namespace Services;
public interface UserService
public interface IUserService
{
Task<IEnumerable<User>> ListUsers(string nameNeedle);
Task<IEnumerable<User>> ListUsers();
Task<User?> GetUser(int id);
Task<User?> GetUser(string email);
Task<User> CreateUser(string username, string email, string password, string profilePicture, bool isAdmin);
Task<bool> RemoveUsers(params int[] identifiers);
Task UpdateUser(User user);
public Task<User?> Authorize(string email, string password);
}

@ -11,7 +11,7 @@ using StubContext;
namespace StubContext.Migrations
{
[DbContext(typeof(StubAppContext))]
[Migration("20240212084944_m1")]
[Migration("20240212203956_m1")]
partial class m1
{
/// <inheritdoc />
@ -106,10 +106,17 @@ namespace StubContext.Migrations
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("IsAdmin")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("ProfilePicture")
.IsRequired()
.HasColumnType("TEXT");
@ -123,35 +130,45 @@ namespace StubContext.Migrations
{
Id = 1,
Email = "maxime@mail.com",
IsAdmin = true,
Name = "maxime",
Password = "Abq2gmly3eYK29oU+krGTUfRH2MAka//xH4nqbZV1Ak=",
ProfilePicture = "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png"
},
new
{
Id = 2,
Email = "mael@mail.com",
IsAdmin = true,
Name = "mael",
Password = "b4IE5XGndyILJn/ZgMdX9YH+rcux1Rvp9X4adjzXzto=",
ProfilePicture = "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png"
},
new
{
Id = 3,
Email = "yanis@mail.com",
IsAdmin = true,
Name = "yanis",
Password = "XZOJugDxViwhvojERZCWfwocYdwICNTyl8VwNZjdVdM=",
ProfilePicture = "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png"
},
new
{
Id = 4,
Email = "simon@mail.com",
IsAdmin = true,
Name = "simon",
Password = "FzsWErXcFnZrRwgY6j18tXdFzq+Jm+jmYKeOTFVMy68=",
ProfilePicture = "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png"
},
new
{
Id = 5,
Email = "vivien@mail.com",
IsAdmin = true,
Name = "vivien",
Password = "6oIi8obqxLNGf1UdE6dFVbffc/+z93AoZiZieibD5vM=",
ProfilePicture = "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png"
});
});

@ -35,9 +35,11 @@ namespace StubContext.Migrations
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Password = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: false),
Email = table.Column<string>(type: "TEXT", nullable: false),
ProfilePicture = table.Column<string>(type: "TEXT", nullable: false)
ProfilePicture = table.Column<string>(type: "TEXT", nullable: false),
IsAdmin = table.Column<bool>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
@ -94,14 +96,14 @@ namespace StubContext.Migrations
migrationBuilder.InsertData(
table: "Users",
columns: new[] { "Id", "Email", "Name", "ProfilePicture" },
columns: new[] { "Id", "Email", "IsAdmin", "Name", "Password", "ProfilePicture" },
values: new object[,]
{
{ 1, "maxime@mail.com", "maxime", "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png" },
{ 2, "mael@mail.com", "mael", "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png" },
{ 3, "yanis@mail.com", "yanis", "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png" },
{ 4, "simon@mail.com", "simon", "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png" },
{ 5, "vivien@mail.com", "vivien", "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png" }
{ 1, "maxime@mail.com", true, "maxime", "lhrwN9GTh2+T/KWpOnGJTI5rt8mZVrljOtDRuYv9Xck=", "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png" },
{ 2, "mael@mail.com", true, "mael", "m+9+DO+fDO5BH33h6rpEvHwVlFTt4Xb0Sa3/qGmDymI=", "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png" },
{ 3, "yanis@mail.com", true, "yanis", "I63Z72IN7LSzp1nG18wX2yAN2kM16WOxMIIMI3o5Nno=", "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png" },
{ 4, "simon@mail.com", true, "simon", "SGbhGgYSXuQpyvdKOlTrUxJcrV3iBZGt5NFZiWtxKWw=", "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png" },
{ 5, "vivien@mail.com", true, "vivien", "v5dtqo9qg96d7ajz+DQlvVZ1Mbeu9RstFXtuhX5SGfo=", "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png" }
});
migrationBuilder.CreateIndex(

@ -103,10 +103,17 @@ namespace StubContext.Migrations
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("IsAdmin")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("ProfilePicture")
.IsRequired()
.HasColumnType("TEXT");
@ -120,35 +127,45 @@ namespace StubContext.Migrations
{
Id = 1,
Email = "maxime@mail.com",
IsAdmin = true,
Name = "maxime",
Password = "cRJvoN/47sgLBqqriPmmThe0HRkZ0IvXw6qomIcnZ7M=",
ProfilePicture = "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png"
},
new
{
Id = 2,
Email = "mael@mail.com",
IsAdmin = true,
Name = "mael",
Password = "opi1I908QEQ3POUbgBjHd/998dWJmvVTmRuDcxlv3do=",
ProfilePicture = "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png"
},
new
{
Id = 3,
Email = "yanis@mail.com",
IsAdmin = true,
Name = "yanis",
Password = "7qmnCq6Kto7dEMhH7chzpqetNkbAMFhxLMxMKo599ws=",
ProfilePicture = "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png"
},
new
{
Id = 4,
Email = "simon@mail.com",
IsAdmin = true,
Name = "simon",
Password = "Hzx7qgkwFMtVZsMp+DK6+ui8AGhbxSeCMC2bOdvLaQA=",
ProfilePicture = "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png"
},
new
{
Id = 5,
Email = "vivien@mail.com",
IsAdmin = true,
Name = "vivien",
Password = "Cjntk37NpF7fct5OfJftgzeZi+ki4Y8aYHsKKm9RmBA=",
ProfilePicture = "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png"
});
});

@ -9,7 +9,7 @@ public class StubAppContext(DbContextOptions<AppContext> options) : AppContext(o
{
public StubAppContext() : this(
new DbContextOptionsBuilder<AppContext>()
.UseSqlite("Data Source=database.db")
.UseSqlite("DataSource=database.db")
.Options
)
{

@ -4,6 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<StartWorkingDirectory>$(MSBuildProjectDirectory)</StartWorkingDirectory>
</PropertyGroup>
<ItemGroup>

Loading…
Cancel
Save