Merge branch 'features/finish-authorization-backend' into 'unstable'
Add authorization See merge request internship-2025/survey-webapp/survey-webapp!5
This commit is contained in:
commit
43feaae7f3
28 changed files with 1164 additions and 13 deletions
|
|
@ -1,5 +1,7 @@
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using SurveyBackend.Core.Services;
|
||||||
using SurveyBackend.DTOs;
|
using SurveyBackend.DTOs;
|
||||||
|
using SurveyBackend.Mappers.UserDTOs;
|
||||||
|
|
||||||
namespace SurveyBackend.Controllers;
|
namespace SurveyBackend.Controllers;
|
||||||
|
|
||||||
|
|
@ -7,9 +9,24 @@ namespace SurveyBackend.Controllers;
|
||||||
[Route("auth")]
|
[Route("auth")]
|
||||||
public class AuthController : ControllerBase
|
public class AuthController : ControllerBase
|
||||||
{
|
{
|
||||||
[HttpPost("login")]
|
private readonly IAuthorizationService _authorizationService;
|
||||||
public async Task<IActionResult> GetToken([FromBody] UserLoginDto loginData)
|
|
||||||
|
public AuthController(IAuthorizationService authorizationService)
|
||||||
{
|
{
|
||||||
return Ok();
|
_authorizationService = authorizationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("login")]
|
||||||
|
public async Task<IActionResult> LogIn([FromBody] UserLoginDto loginData)
|
||||||
|
{
|
||||||
|
var token = await _authorizationService.LogInUser(loginData.Email, loginData.Password);
|
||||||
|
return Ok(new { token = token });
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("register")]
|
||||||
|
public async Task<IActionResult> Register([FromBody] UserRegistrationDto registerData)
|
||||||
|
{
|
||||||
|
var token = await _authorizationService.RegisterUser(UserRegistrationMapper.UserRegistrationToModel(registerData));
|
||||||
|
return Ok(new { token = token });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
using SurveyBackend.Core.Models;
|
||||||
|
using SurveyBackend.Core.Services;
|
||||||
|
using SurveyBackend.DTOs;
|
||||||
|
|
||||||
|
namespace SurveyBackend.Mappers.UserDTOs;
|
||||||
|
|
||||||
|
public static class UserRegistrationMapper
|
||||||
|
{
|
||||||
|
public static User UserRegistrationToModel(UserRegistrationDto dto) => new User
|
||||||
|
{
|
||||||
|
Email = dto.Email,
|
||||||
|
FirstName = dto.FirstName,
|
||||||
|
LastName = dto.LastName,
|
||||||
|
Password = dto.Password,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
using SurveyBackend.Services.Exceptions;
|
||||||
|
|
||||||
|
namespace SurveyBackend.Middlewares;
|
||||||
|
|
||||||
|
public class ExceptionsMiddleware
|
||||||
|
{
|
||||||
|
private readonly RequestDelegate _next;
|
||||||
|
private readonly ILogger<ExceptionsMiddleware> _logger;
|
||||||
|
|
||||||
|
public ExceptionsMiddleware(RequestDelegate next, ILogger<ExceptionsMiddleware> logger)
|
||||||
|
{
|
||||||
|
_next = next;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InvokeAsync(HttpContext context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _next(context);
|
||||||
|
}
|
||||||
|
catch (ServiceException ex)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = ex.StatusCode;
|
||||||
|
context.Response.ContentType = "application/json";
|
||||||
|
|
||||||
|
var response = new
|
||||||
|
{
|
||||||
|
error = ex.Message
|
||||||
|
};
|
||||||
|
|
||||||
|
await context.Response.WriteAsJsonAsync(response);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
|
||||||
|
context.Response.StatusCode = 500;
|
||||||
|
context.Response.ContentType = "application/json";
|
||||||
|
|
||||||
|
var response = new
|
||||||
|
{
|
||||||
|
error = "Internal Server Error. GG WP, request bub fix"
|
||||||
|
};
|
||||||
|
|
||||||
|
await context.Response.WriteAsJsonAsync(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,8 +2,14 @@ using System.Text;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using SurveyBackend.Core.Repositories;
|
||||||
|
using SurveyBackend.Core.Services;
|
||||||
using SurveyBackend.Infrastructure;
|
using SurveyBackend.Infrastructure;
|
||||||
using SurveyBackend.Infrastructure.Data;
|
using SurveyBackend.Infrastructure.Data;
|
||||||
|
using SurveyBackend.Infrastructure.Repositories;
|
||||||
|
using SurveyBackend.Middlewares;
|
||||||
|
using SurveyBackend.Services;
|
||||||
|
using SurveyBackend.Services.Services;
|
||||||
using SurveyLib.Core.Repositories;
|
using SurveyLib.Core.Repositories;
|
||||||
using SurveyLib.Core.Services;
|
using SurveyLib.Core.Services;
|
||||||
using SurveyLib.Infrastructure.EFCore.Data;
|
using SurveyLib.Infrastructure.EFCore.Data;
|
||||||
|
|
@ -27,6 +33,13 @@ public class Program
|
||||||
|
|
||||||
builder.Services.AddScoped<SurveyDbContext>(provider => provider.GetRequiredService<ApplicationDbContext>());
|
builder.Services.AddScoped<SurveyDbContext>(provider => provider.GetRequiredService<ApplicationDbContext>());
|
||||||
|
|
||||||
|
builder.Services.AddScoped<IUserRepository, UserRepository>();
|
||||||
|
builder.Services.AddScoped<IUserService, UserService>();
|
||||||
|
|
||||||
|
builder.Services.AddScoped<IPasswordHasher, Sha256PasswordHasher>();
|
||||||
|
|
||||||
|
builder.Services.AddScoped<IAuthorizationService, AuthorizationService>();
|
||||||
|
|
||||||
builder.Services.AddScoped<ISurveyRepository, SurveyRepository>();
|
builder.Services.AddScoped<ISurveyRepository, SurveyRepository>();
|
||||||
builder.Services.AddScoped<ISurveyService, SurveyService>();
|
builder.Services.AddScoped<ISurveyService, SurveyService>();
|
||||||
|
|
||||||
|
|
@ -59,6 +72,8 @@ public class Program
|
||||||
app.UseSwaggerUI();
|
app.UseSwaggerUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.UseMiddleware<ExceptionsMiddleware>();
|
||||||
|
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,18 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.14" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.14" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.2"/>
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.2"/>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.3" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.15">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.15" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0"/>
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\SurveyBackend.Core\SurveyBackend.Core.csproj" />
|
<ProjectReference Include="..\SurveyBackend.Core\SurveyBackend.Core.csproj" />
|
||||||
<ProjectReference Include="..\SurveyBackend.Infrastructure\SurveyBackend.Infrastructure.csproj" />
|
<ProjectReference Include="..\SurveyBackend.Infrastructure\SurveyBackend.Infrastructure.csproj" />
|
||||||
|
<ProjectReference Include="..\SurveyBackend.Services\SurveyBackend.Services.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ namespace SurveyBackend.Core.Models;
|
||||||
|
|
||||||
public class User
|
public class User
|
||||||
{
|
{
|
||||||
public string Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
public string FirstName { get; set; }
|
public string FirstName { get; set; }
|
||||||
public string LastName { get; set; }
|
public string LastName { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,5 @@ namespace SurveyBackend.Core.Repositories;
|
||||||
|
|
||||||
public interface IUserRepository : IGenericRepository<User>
|
public interface IUserRepository : IGenericRepository<User>
|
||||||
{
|
{
|
||||||
|
public Task<User?> GetUserByEmail(string email);
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
using SurveyBackend.Core.Models;
|
||||||
|
|
||||||
|
namespace SurveyBackend.Core.Services;
|
||||||
|
|
||||||
|
public interface IAuthorizationService
|
||||||
|
{
|
||||||
|
public Task<string> LogInUser(string email, string password);
|
||||||
|
public Task<string> RegisterUser(User user);
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace SurveyBackend.Infrastructure.Services;
|
namespace SurveyBackend.Core.Services;
|
||||||
|
|
||||||
public interface IPasswordHasher
|
public interface IPasswordHasher
|
||||||
{
|
{
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
|
using SurveyBackend.Core.Models;
|
||||||
|
|
||||||
namespace SurveyBackend.Core.Services;
|
namespace SurveyBackend.Core.Services;
|
||||||
|
|
||||||
public interface IUserService
|
public interface IUserService
|
||||||
{
|
{
|
||||||
|
public Task<User> GetUserByEmail(string email);
|
||||||
|
public Task<bool> IsEmailTaken(string email);
|
||||||
|
public Task CreateUserAsync(User user);
|
||||||
}
|
}
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.14" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.15" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
321
SurveyBackend/SurveyBackend.Infrastructure/Data/Migrations/20250418123442_Initial.Designer.cs
generated
Normal file
321
SurveyBackend/SurveyBackend.Infrastructure/Data/Migrations/20250418123442_Initial.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,321 @@
|
||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using SurveyBackend.Infrastructure.Data;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace SurveyBackend.Infrastructure.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
[Migration("20250418123442_Initial")]
|
||||||
|
partial class Initial
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "8.0.15");
|
||||||
|
|
||||||
|
modelBuilder.Entity("GroupUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("GroupsId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("UsersId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("GroupsId", "UsersId");
|
||||||
|
|
||||||
|
b.HasIndex("UsersId");
|
||||||
|
|
||||||
|
b.ToTable("GroupUser");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyBackend.Core.Models.Group", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Label")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Groups");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyBackend.Core.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("FirstName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.Answer", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("CompletionId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("QuestionId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("AnswerText")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("CompletionId", "QuestionId");
|
||||||
|
|
||||||
|
b.HasIndex("QuestionId");
|
||||||
|
|
||||||
|
b.ToTable("Answers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.AnswerVariant", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("MultipleAnswerQuestionId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("QuestionId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("SingleAnswerQuestionId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Text")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("MultipleAnswerQuestionId");
|
||||||
|
|
||||||
|
b.HasIndex("QuestionId");
|
||||||
|
|
||||||
|
b.HasIndex("SingleAnswerQuestionId");
|
||||||
|
|
||||||
|
b.ToTable("AnswerVariant");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.Completion", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FinishedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("SurveyId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SurveyId");
|
||||||
|
|
||||||
|
b.ToTable("Completions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.QuestionBase", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Discriminator")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(34)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("SurveyId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SurveyId");
|
||||||
|
|
||||||
|
b.ToTable("Questions");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("QuestionBase");
|
||||||
|
|
||||||
|
b.UseTphMappingStrategy();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.Survey", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Surveys");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.QuestionVariants.MultipleAnswerQuestion", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("SurveyLib.Core.Models.QuestionBase");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("MultipleAnswerQuestion");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.QuestionVariants.SingleAnswerQuestion", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("SurveyLib.Core.Models.QuestionBase");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("SingleAnswerQuestion");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.QuestionVariants.TextQuestion", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("SurveyLib.Core.Models.QuestionBase");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("TextQuestion");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GroupUser", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SurveyBackend.Core.Models.Group", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GroupsId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SurveyBackend.Core.Models.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UsersId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.Answer", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SurveyLib.Core.Models.Completion", "Completion")
|
||||||
|
.WithMany("Answers")
|
||||||
|
.HasForeignKey("CompletionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SurveyLib.Core.Models.QuestionBase", "Question")
|
||||||
|
.WithMany("Answers")
|
||||||
|
.HasForeignKey("QuestionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Completion");
|
||||||
|
|
||||||
|
b.Navigation("Question");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.AnswerVariant", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SurveyLib.Core.Models.QuestionVariants.MultipleAnswerQuestion", null)
|
||||||
|
.WithMany("AnswerVariants")
|
||||||
|
.HasForeignKey("MultipleAnswerQuestionId");
|
||||||
|
|
||||||
|
b.HasOne("SurveyLib.Core.Models.QuestionBase", "Question")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("QuestionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SurveyLib.Core.Models.QuestionVariants.SingleAnswerQuestion", null)
|
||||||
|
.WithMany("AnswerVariants")
|
||||||
|
.HasForeignKey("SingleAnswerQuestionId");
|
||||||
|
|
||||||
|
b.Navigation("Question");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.Completion", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SurveyLib.Core.Models.Survey", "Survey")
|
||||||
|
.WithMany("Completions")
|
||||||
|
.HasForeignKey("SurveyId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Survey");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.QuestionBase", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SurveyLib.Core.Models.Survey", "Survey")
|
||||||
|
.WithMany("Questions")
|
||||||
|
.HasForeignKey("SurveyId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Survey");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.Completion", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Answers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.QuestionBase", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Answers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.Survey", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Completions");
|
||||||
|
|
||||||
|
b.Navigation("Questions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.QuestionVariants.MultipleAnswerQuestion", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("AnswerVariants");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.QuestionVariants.SingleAnswerQuestion", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("AnswerVariants");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,243 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace SurveyBackend.Infrastructure.Data.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Initial : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Groups",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Label = table.Column<string>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Groups", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Surveys",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Title = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Description = table.Column<string>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Surveys", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Users",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Email = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
FirstName = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
LastName = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Password = table.Column<string>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Users", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Completions",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
SurveyId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
FinishedAt = table.Column<DateTime>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Completions", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Completions_Surveys_SurveyId",
|
||||||
|
column: x => x.SurveyId,
|
||||||
|
principalTable: "Surveys",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Questions",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
SurveyId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
Title = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Discriminator = table.Column<string>(type: "TEXT", maxLength: 34, nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Questions", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Questions_Surveys_SurveyId",
|
||||||
|
column: x => x.SurveyId,
|
||||||
|
principalTable: "Surveys",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "GroupUser",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
GroupsId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
UsersId = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_GroupUser", x => new { x.GroupsId, x.UsersId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_GroupUser_Groups_GroupsId",
|
||||||
|
column: x => x.GroupsId,
|
||||||
|
principalTable: "Groups",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_GroupUser_Users_UsersId",
|
||||||
|
column: x => x.UsersId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Answers",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
CompletionId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
QuestionId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
AnswerText = table.Column<string>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Answers", x => new { x.CompletionId, x.QuestionId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Answers_Completions_CompletionId",
|
||||||
|
column: x => x.CompletionId,
|
||||||
|
principalTable: "Completions",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Answers_Questions_QuestionId",
|
||||||
|
column: x => x.QuestionId,
|
||||||
|
principalTable: "Questions",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AnswerVariant",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
QuestionId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
Text = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
MultipleAnswerQuestionId = table.Column<int>(type: "INTEGER", nullable: true),
|
||||||
|
SingleAnswerQuestionId = table.Column<int>(type: "INTEGER", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AnswerVariant", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AnswerVariant_Questions_MultipleAnswerQuestionId",
|
||||||
|
column: x => x.MultipleAnswerQuestionId,
|
||||||
|
principalTable: "Questions",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AnswerVariant_Questions_QuestionId",
|
||||||
|
column: x => x.QuestionId,
|
||||||
|
principalTable: "Questions",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AnswerVariant_Questions_SingleAnswerQuestionId",
|
||||||
|
column: x => x.SingleAnswerQuestionId,
|
||||||
|
principalTable: "Questions",
|
||||||
|
principalColumn: "Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Answers_QuestionId",
|
||||||
|
table: "Answers",
|
||||||
|
column: "QuestionId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AnswerVariant_MultipleAnswerQuestionId",
|
||||||
|
table: "AnswerVariant",
|
||||||
|
column: "MultipleAnswerQuestionId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AnswerVariant_QuestionId",
|
||||||
|
table: "AnswerVariant",
|
||||||
|
column: "QuestionId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AnswerVariant_SingleAnswerQuestionId",
|
||||||
|
table: "AnswerVariant",
|
||||||
|
column: "SingleAnswerQuestionId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Completions_SurveyId",
|
||||||
|
table: "Completions",
|
||||||
|
column: "SurveyId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_GroupUser_UsersId",
|
||||||
|
table: "GroupUser",
|
||||||
|
column: "UsersId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Questions_SurveyId",
|
||||||
|
table: "Questions",
|
||||||
|
column: "SurveyId");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Answers");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AnswerVariant");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "GroupUser");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Completions");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Questions");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Groups");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Surveys");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,318 @@
|
||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using SurveyBackend.Infrastructure.Data;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace SurveyBackend.Infrastructure.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
|
||||||
|
{
|
||||||
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "8.0.15");
|
||||||
|
|
||||||
|
modelBuilder.Entity("GroupUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("GroupsId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("UsersId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("GroupsId", "UsersId");
|
||||||
|
|
||||||
|
b.HasIndex("UsersId");
|
||||||
|
|
||||||
|
b.ToTable("GroupUser");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyBackend.Core.Models.Group", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Label")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Groups");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyBackend.Core.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("FirstName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.Answer", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("CompletionId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("QuestionId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("AnswerText")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("CompletionId", "QuestionId");
|
||||||
|
|
||||||
|
b.HasIndex("QuestionId");
|
||||||
|
|
||||||
|
b.ToTable("Answers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.AnswerVariant", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("MultipleAnswerQuestionId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("QuestionId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("SingleAnswerQuestionId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Text")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("MultipleAnswerQuestionId");
|
||||||
|
|
||||||
|
b.HasIndex("QuestionId");
|
||||||
|
|
||||||
|
b.HasIndex("SingleAnswerQuestionId");
|
||||||
|
|
||||||
|
b.ToTable("AnswerVariant");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.Completion", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FinishedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("SurveyId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SurveyId");
|
||||||
|
|
||||||
|
b.ToTable("Completions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.QuestionBase", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Discriminator")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(34)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("SurveyId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SurveyId");
|
||||||
|
|
||||||
|
b.ToTable("Questions");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("QuestionBase");
|
||||||
|
|
||||||
|
b.UseTphMappingStrategy();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.Survey", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Surveys");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.QuestionVariants.MultipleAnswerQuestion", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("SurveyLib.Core.Models.QuestionBase");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("MultipleAnswerQuestion");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.QuestionVariants.SingleAnswerQuestion", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("SurveyLib.Core.Models.QuestionBase");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("SingleAnswerQuestion");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.QuestionVariants.TextQuestion", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("SurveyLib.Core.Models.QuestionBase");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("TextQuestion");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GroupUser", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SurveyBackend.Core.Models.Group", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GroupsId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SurveyBackend.Core.Models.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UsersId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.Answer", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SurveyLib.Core.Models.Completion", "Completion")
|
||||||
|
.WithMany("Answers")
|
||||||
|
.HasForeignKey("CompletionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SurveyLib.Core.Models.QuestionBase", "Question")
|
||||||
|
.WithMany("Answers")
|
||||||
|
.HasForeignKey("QuestionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Completion");
|
||||||
|
|
||||||
|
b.Navigation("Question");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.AnswerVariant", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SurveyLib.Core.Models.QuestionVariants.MultipleAnswerQuestion", null)
|
||||||
|
.WithMany("AnswerVariants")
|
||||||
|
.HasForeignKey("MultipleAnswerQuestionId");
|
||||||
|
|
||||||
|
b.HasOne("SurveyLib.Core.Models.QuestionBase", "Question")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("QuestionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SurveyLib.Core.Models.QuestionVariants.SingleAnswerQuestion", null)
|
||||||
|
.WithMany("AnswerVariants")
|
||||||
|
.HasForeignKey("SingleAnswerQuestionId");
|
||||||
|
|
||||||
|
b.Navigation("Question");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.Completion", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SurveyLib.Core.Models.Survey", "Survey")
|
||||||
|
.WithMany("Completions")
|
||||||
|
.HasForeignKey("SurveyId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Survey");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.QuestionBase", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SurveyLib.Core.Models.Survey", "Survey")
|
||||||
|
.WithMany("Questions")
|
||||||
|
.HasForeignKey("SurveyId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Survey");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.Completion", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Answers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.QuestionBase", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Answers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.Survey", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Completions");
|
||||||
|
|
||||||
|
b.Navigation("Questions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.QuestionVariants.MultipleAnswerQuestion", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("AnswerVariants");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SurveyLib.Core.Models.QuestionVariants.SingleAnswerQuestion", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("AnswerVariants");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -41,4 +41,9 @@ public class UserRepository : IUserRepository
|
||||||
_context.Users.Remove(entity);
|
_context.Users.Remove(entity);
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<User?> GetUserByEmail(string email)
|
||||||
|
{
|
||||||
|
return await _context.Users.FirstOrDefaultAsync(u => u.Email == email);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,7 +7,11 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.3" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.15" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.15">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.1.2" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.1.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
@ -16,4 +20,8 @@
|
||||||
<ProjectReference Include="..\SurveyBackend.Core\SurveyBackend.Core.csproj" />
|
<ProjectReference Include="..\SurveyBackend.Core\SurveyBackend.Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Data\Migrations\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ using System.Text;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
namespace SurveyBackend.Infrastructure;
|
namespace SurveyBackend.Services;
|
||||||
|
|
||||||
public static class AuthOptions
|
public static class AuthOptions
|
||||||
{
|
{
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace SurveyBackend.Services.Exceptions;
|
||||||
|
|
||||||
|
public class ConflictException : ServiceException
|
||||||
|
{
|
||||||
|
public override int StatusCode => 409;
|
||||||
|
|
||||||
|
public ConflictException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace SurveyBackend.Services.Exceptions;
|
||||||
|
|
||||||
|
public class NotFoundException : ServiceException
|
||||||
|
{
|
||||||
|
public override int StatusCode => 404;
|
||||||
|
|
||||||
|
public NotFoundException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace SurveyBackend.Services.Exceptions;
|
||||||
|
|
||||||
|
public abstract class ServiceException : Exception
|
||||||
|
{
|
||||||
|
public abstract int StatusCode { get; }
|
||||||
|
|
||||||
|
protected ServiceException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace SurveyBackend.Services.Exceptions;
|
||||||
|
|
||||||
|
public class UnauthorizedException : ServiceException
|
||||||
|
{
|
||||||
|
public override int StatusCode => 401;
|
||||||
|
|
||||||
|
public UnauthorizedException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@ using System.Security.Claims;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using SurveyBackend.Core.Models;
|
using SurveyBackend.Core.Models;
|
||||||
|
|
||||||
namespace SurveyBackend.Infrastructure.Helpers;
|
namespace SurveyBackend.Services.Helpers;
|
||||||
|
|
||||||
public class TokenHelper
|
public class TokenHelper
|
||||||
{
|
{
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
using SurveyBackend.Core.Models;
|
||||||
|
using SurveyBackend.Core.Services;
|
||||||
|
using SurveyBackend.Services.Exceptions;
|
||||||
|
using SurveyBackend.Services.Helpers;
|
||||||
|
|
||||||
|
namespace SurveyBackend.Services.Services;
|
||||||
|
|
||||||
|
public class AuthorizationService : IAuthorizationService
|
||||||
|
{
|
||||||
|
private readonly IUserService _userService;
|
||||||
|
private readonly IPasswordHasher _passwordHasher;
|
||||||
|
|
||||||
|
public AuthorizationService(IUserService userService, IPasswordHasher passwordHasher)
|
||||||
|
{
|
||||||
|
_userService = userService;
|
||||||
|
_passwordHasher = passwordHasher;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> LogInUser(string email, string password)
|
||||||
|
{
|
||||||
|
var user = await _userService.GetUserByEmail(email);
|
||||||
|
if (!_passwordHasher.Verify(password, user.Password))
|
||||||
|
{
|
||||||
|
throw new UnauthorizedException("Password is incorrect.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var token = TokenHelper.GetAuthToken(user);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> RegisterUser(User user)
|
||||||
|
{
|
||||||
|
var isEmailTaken = await _userService.IsEmailTaken(user.Email);
|
||||||
|
if (isEmailTaken)
|
||||||
|
{
|
||||||
|
throw new ConflictException("Email already exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Password = _passwordHasher.HashPassword(user.Password);
|
||||||
|
|
||||||
|
await _userService.CreateUserAsync(user);
|
||||||
|
var token = TokenHelper.GetAuthToken(user);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
using SurveyBackend.Core.Services;
|
||||||
|
|
||||||
namespace SurveyBackend.Infrastructure.Services;
|
namespace SurveyBackend.Services.Services;
|
||||||
|
|
||||||
public class Sha256PasswordHasher : IPasswordHasher
|
public class Sha256PasswordHasher : IPasswordHasher
|
||||||
{
|
{
|
||||||
31
SurveyBackend/SurveyBackend.Services/Services/UserService.cs
Normal file
31
SurveyBackend/SurveyBackend.Services/Services/UserService.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
using SurveyBackend.Core.Models;
|
||||||
|
using SurveyBackend.Core.Repositories;
|
||||||
|
using SurveyBackend.Core.Services;
|
||||||
|
using SurveyBackend.Services.Exceptions;
|
||||||
|
|
||||||
|
namespace SurveyBackend.Services.Services;
|
||||||
|
|
||||||
|
public class UserService : IUserService
|
||||||
|
{
|
||||||
|
private readonly IUserRepository _userRepository;
|
||||||
|
|
||||||
|
public UserService(IUserRepository userRepository)
|
||||||
|
{
|
||||||
|
_userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<User> GetUserByEmail(string email)
|
||||||
|
{
|
||||||
|
return await _userRepository.GetUserByEmail(email) ?? throw new NotFoundException("Email not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> IsEmailTaken(string email)
|
||||||
|
{
|
||||||
|
return await _userRepository.GetUserByEmail(email) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateUserAsync(User user)
|
||||||
|
{
|
||||||
|
await _userRepository.AddAsync(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\SurveyBackend.Core\SurveyBackend.Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.1.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -10,6 +10,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SurveyLib.Infrastructure.EF
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SurveyLib.Core", "..\SurveyLib\SurveyLib.Core\SurveyLib.Core.csproj", "{C17C405B-37CF-48E6-AA44-44B878F4DE56}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SurveyLib.Core", "..\SurveyLib\SurveyLib.Core\SurveyLib.Core.csproj", "{C17C405B-37CF-48E6-AA44-44B878F4DE56}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SurveyBackend.Services", "SurveyBackend.Services\SurveyBackend.Services.csproj", "{3CDA6495-4FB2-4F07-8B2F-15BFD2A35181}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -36,5 +38,9 @@ Global
|
||||||
{C17C405B-37CF-48E6-AA44-44B878F4DE56}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{C17C405B-37CF-48E6-AA44-44B878F4DE56}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{C17C405B-37CF-48E6-AA44-44B878F4DE56}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{C17C405B-37CF-48E6-AA44-44B878F4DE56}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{C17C405B-37CF-48E6-AA44-44B878F4DE56}.Release|Any CPU.Build.0 = Release|Any CPU
|
{C17C405B-37CF-48E6-AA44-44B878F4DE56}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{3CDA6495-4FB2-4F07-8B2F-15BFD2A35181}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3CDA6495-4FB2-4F07-8B2F-15BFD2A35181}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3CDA6495-4FB2-4F07-8B2F-15BFD2A35181}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3CDA6495-4FB2-4F07-8B2F-15BFD2A35181}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 7bbc78fbd7eef3bb2497b966ea73eba31aa7032c
|
Subproject commit fe2735da5040501f143526a8c1af19c8023f6368
|
||||||
Loading…
Add table
Add a link
Reference in a new issue