From f212f85d006c71142bbaa1264ea3c588a4688998 Mon Sep 17 00:00:00 2001 From: quentin Date: Sat, 31 Aug 2024 18:38:07 -0500 Subject: [PATCH] Added signup support --- .gitignore | 5 +- .../GrantNames/SignupGrantNames.cs | 14 +++++ .../Interfaces/ISignupAuthentication.cs | 9 +++ API/Authentication/SignupAuthentication.cs | 46 ++++++++++++++ API/Controllers/SignupController.cs | 62 +++++++++++++++++++ API/DTO/Base/SignupDTO.cs | 33 ++++++++++ API/DTO/Base/Update/SignupUpdateDTO.cs | 16 +++++ API/Program.cs | 15 +++-- API/Services/ServiceBase.cs | 2 +- API/Services/SignupService.cs | 16 +++++ DAL/Contexts/SASGContext.cs | 12 ++++ DAL/Models/Audits/AuditSignup.cs | 28 +++++++++ DAL/Models/Signup.cs | 39 ++++++++++++ Setup/Filler/Grants.sql | 24 +++++++ 14 files changed, 310 insertions(+), 11 deletions(-) create mode 100644 API/Authentication/GrantNames/SignupGrantNames.cs create mode 100644 API/Authentication/Interfaces/ISignupAuthentication.cs create mode 100644 API/Authentication/SignupAuthentication.cs create mode 100644 API/Controllers/SignupController.cs create mode 100644 API/DTO/Base/SignupDTO.cs create mode 100644 API/DTO/Base/Update/SignupUpdateDTO.cs create mode 100644 API/Services/SignupService.cs create mode 100644 DAL/Models/Audits/AuditSignup.cs create mode 100644 DAL/Models/Signup.cs diff --git a/.gitignore b/.gitignore index f12d3ea..339ca85 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,4 @@ /API/appsettings.* /Setup/bin/ /Setup/obj/ -/Setup/appsettings.* -/web/bin/ -/web/obj/ -/web/appsettings.* +/Setup/appsettings.* \ No newline at end of file diff --git a/API/Authentication/GrantNames/SignupGrantNames.cs b/API/Authentication/GrantNames/SignupGrantNames.cs new file mode 100644 index 0000000..57dbce6 --- /dev/null +++ b/API/Authentication/GrantNames/SignupGrantNames.cs @@ -0,0 +1,14 @@ +namespace API.Authentication.GrantNames +{ + public static class SignupGrantNames + { + public const string CanGetAll = "api.signup.get.all"; + public const string CanGetAny = "api.signup.get.any"; + public const string CanGet = "api.signup.get"; + public const string CanAdd = "api.signup.add"; + public const string CanUpdateAny = "api.signup.update.any"; + public const string CanUpdate = "api.signup.update"; + public const string CanDeleteAny = "api.signup.delete.any"; + public const string CanDelete = "api.signup.delete"; + } +} diff --git a/API/Authentication/Interfaces/ISignupAuthentication.cs b/API/Authentication/Interfaces/ISignupAuthentication.cs new file mode 100644 index 0000000..97ce538 --- /dev/null +++ b/API/Authentication/Interfaces/ISignupAuthentication.cs @@ -0,0 +1,9 @@ +using API.DTO.Base.Update; +using DAL.Models; + +namespace API.Authentication.Interfaces +{ + public interface ISignupAuthentication : IGenericAuthentication + { + } +} diff --git a/API/Authentication/SignupAuthentication.cs b/API/Authentication/SignupAuthentication.cs new file mode 100644 index 0000000..b89bda3 --- /dev/null +++ b/API/Authentication/SignupAuthentication.cs @@ -0,0 +1,46 @@ +using API.Authentication.GrantNames; +using API.Authentication.Interfaces; +using API.DTO.Base.Update; +using API.Services.Interfaces; +using DAL.Models; + +namespace API.Authentication +{ + public class SignupAuthentication : ISignupAuthentication + { + private readonly IGrantManager _grantManager; + private readonly ILogger _logger; + + public SignupAuthentication(IGrantManager grantManager, ILogger logger) + { + _grantManager = grantManager; + _logger = logger; + } + + //todo make more restrictive + + public bool canGetAll(User user) + { + return _grantManager.hasGrant(user.permissionId, SignupGrantNames.CanGetAll); + } + public bool canGet(Signup model, User user) + { + return _grantManager.hasGrant(user.permissionId, SignupGrantNames.CanGetAny) || + _grantManager.getULongValues(user.permissionId, SignupGrantNames.CanGet).Exists(x => x == model.id); + } + public bool canAdd(SignupDTO item, User user) + { + return _grantManager.hasGrant(user.permissionId, SignupGrantNames.CanAdd); + } + public bool canUpdate(Signup model, User user) + { + return _grantManager.hasGrant(user.permissionId, SignupGrantNames.CanUpdateAny) || + _grantManager.getULongValues(user.permissionId, SignupGrantNames.CanUpdate).Exists(x => x == model.id); + } + public bool canDelete(Signup model, User user) + { + return _grantManager.hasGrant(user.permissionId, SignupGrantNames.CanDeleteAny) || + _grantManager.getULongValues(user.permissionId, SignupGrantNames.CanDelete).Exists(x => x == model.id); + } + } +} diff --git a/API/Controllers/SignupController.cs b/API/Controllers/SignupController.cs new file mode 100644 index 0000000..d3592b9 --- /dev/null +++ b/API/Controllers/SignupController.cs @@ -0,0 +1,62 @@ +using API.Authentication; +using API.Authentication.Interfaces; +using API.DTO.Base.Update; +using API.Services; +using DAL.Models; +using DAL.Models.Audits; +using Microsoft.AspNetCore.Mvc; +using MUser = DAL.Models.User; + +namespace API.Controllers +{ + [ApiController] + [Route("api/v1/[controller]")] + public class SignupController : CRUDBase + { + public SignupController(ILogger logger, UserService userService, SignupService service) : base(logger, userService, service) + { + } + + [HttpPost] + public override ActionResult add(SignupDTO createDTO) + { + MUser? user = getUser(User); + if (user == null) + return Unauthorized(); + + // todo + createDTO.userId = user.id; + if (createDTO.userId != user.id) + { + return Forbid(); + } + + Signup? result = Service.add(createDTO, user); + if (result == null) + return Forbid(); + + SignupDTO dto = new SignupDTO(); + dto.adaptFromModel(result); + + return Ok(dto); + } + + [HttpDelete("event/{eventId}")] + public virtual ActionResult delete(ulong eventId) + { + MUser? user = getUser(User); + if (user == null) + return Unauthorized(); + + Signup? result = Service.getNoAuthentication(x => x.userId == user.id && x.eventId == eventId).FirstOrDefault(); + if (result == null) + return Forbid(); + + AuditSignup? auditModel = Service.delete(result, user); + if (auditModel == null) + return Forbid(); + + return NoContent(); + } + } +} diff --git a/API/DTO/Base/SignupDTO.cs b/API/DTO/Base/SignupDTO.cs new file mode 100644 index 0000000..b72b632 --- /dev/null +++ b/API/DTO/Base/SignupDTO.cs @@ -0,0 +1,33 @@ +using DAL.Models; + +namespace API.DTO.Base.Update +{ + public class SignupDTO : IAdaptable + { + public ulong id { get; set; } + public ulong eventId { get; set; } + public ulong userId { get; set; } + + public DateTime updated { get; set; } + public ulong updater { get; set; } + public Signup adaptToModel() + { + return new Signup + { + id = id, + eventId = eventId, + userId = userId, + updated = updated, + updater = updater + }; + } + public void adaptFromModel(in Signup model) + { + id = model.id; + eventId = model.eventId; + userId = model.userId; + updated = model.updated; + updater = model.updater; + } + } +} diff --git a/API/DTO/Base/Update/SignupUpdateDTO.cs b/API/DTO/Base/Update/SignupUpdateDTO.cs new file mode 100644 index 0000000..9a1179f --- /dev/null +++ b/API/DTO/Base/Update/SignupUpdateDTO.cs @@ -0,0 +1,16 @@ +using DAL.Models; + +namespace API.DTO.Base.Update +{ + public class SignupUpdateDTO : IUpdateAdaptable + { + public ulong? eventId { get; set; } + public ulong? userId { get; set; } + + public void adaptModel(ref Signup model) + { + if (eventId != null) model.eventId = (ulong)eventId; + if (userId != null) model.userId = (ulong)userId; + } + } +} diff --git a/API/Program.cs b/API/Program.cs index 0e8554d..cc40416 100644 --- a/API/Program.cs +++ b/API/Program.cs @@ -56,6 +56,7 @@ namespace API builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); + builder.Services.AddTransient(); builder.Services.AddTransient(options => { ILogger logger = options.GetRequiredService>(); @@ -76,6 +77,7 @@ namespace API builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); + builder.Services.AddTransient(); builder.Services.AddTransient(); @@ -96,11 +98,12 @@ namespace API }); - builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options => - { - options.Cookie.SameSite = SameSiteMode.None; - options.Cookie.SecurePolicy = CookieSecurePolicy.Always; - }); + builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(); + // builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options => + // { + // options.Cookie.SameSite = SameSiteMode.None; + // options.Cookie.SecurePolicy = CookieSecurePolicy.Always; + // }); builder.Services.AddLazyResolution(); @@ -114,7 +117,7 @@ namespace API app.UseCookiePolicy(new CookiePolicyOptions { - MinimumSameSitePolicy = SameSiteMode.None + MinimumSameSitePolicy = SameSiteMode.Strict }); app.UseAuthorization(); diff --git a/API/Services/ServiceBase.cs b/API/Services/ServiceBase.cs index 7e1c8fc..ef3eb8d 100644 --- a/API/Services/ServiceBase.cs +++ b/API/Services/ServiceBase.cs @@ -14,7 +14,7 @@ namespace API.Services where TAudit : AuditModel where TDTO : IAdaptable { - private readonly TAuthentication _auth; + public readonly TAuthentication _auth; private readonly ILogger _logger; public readonly SASGContext Context; diff --git a/API/Services/SignupService.cs b/API/Services/SignupService.cs new file mode 100644 index 0000000..ccc13b1 --- /dev/null +++ b/API/Services/SignupService.cs @@ -0,0 +1,16 @@ +using API.Authentication.Interfaces; +using API.DTO.Base.Update; +using DAL.Contexts; +using DAL.Models; +using DAL.Models.Audits; + +namespace API.Services +{ + public class SignupService : ServiceBase + { + public SignupService(ILogger logger, SASGContext context, ISignupAuthentication auth) : base(logger, context, auth) + { + } + + } +} diff --git a/DAL/Contexts/SASGContext.cs b/DAL/Contexts/SASGContext.cs index 442ccab..2f46728 100644 --- a/DAL/Contexts/SASGContext.cs +++ b/DAL/Contexts/SASGContext.cs @@ -24,6 +24,7 @@ namespace DAL.Contexts public virtual DbSet images { get; set; } public virtual DbSet permissions { get; set; } public virtual DbSet savedEvents { get; set; } + public virtual DbSet signups { get; set; } public virtual DbSet users { get; set; } public virtual DbSet auditColors { get; set; } public virtual DbSet auditEvents { get; set; } @@ -32,6 +33,7 @@ namespace DAL.Contexts public virtual DbSet auditPermissions { get; set; } public virtual DbSet auditSavedEvents { get; set; } public virtual DbSet auditUsers { get; set; } + public virtual DbSet auditSignups { get; set; } protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { @@ -98,6 +100,16 @@ namespace DAL.Contexts .HasForeignKey(e => e.updater).HasConstraintName("events_users_id_fk"); entity.Property(e => e.hashingType).HasConversion(); }); + + builder.Entity(entity => + { + entity.HasOne(e => e.eventIdRelation).WithMany() + .HasForeignKey(e => e.eventId).HasConstraintName("signup_events_id_fk"); + entity.HasOne(e => e.userIdRelation).WithMany() + .HasForeignKey(e => e.userId).HasConstraintName("signup_users_id_fk"); + entity.HasOne(e => e.updaterRelation).WithMany() + .HasForeignKey(e => e.updater).HasConstraintName("events_users_id_fk2"); + }); } } } diff --git a/DAL/Models/Audits/AuditSignup.cs b/DAL/Models/Audits/AuditSignup.cs new file mode 100644 index 0000000..33d77cd --- /dev/null +++ b/DAL/Models/Audits/AuditSignup.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DAL.Models.Audits +{ + [Table("audit_signup")] + [Index("id", Name = "audit_signup_originalId_index")] + public class AuditSignup : AuditModel + { + [Column("eventId")] + public ulong eventId { get; set; } + + [Column("userId")] + public ulong userId { get; set; } + + public override Signup adaptToModel() + { + return new Signup + { + id = originalId, + eventId = eventId, + userId = userId, + updated = updated, + updater = updater + }; + } + } +} diff --git a/DAL/Models/Signup.cs b/DAL/Models/Signup.cs new file mode 100644 index 0000000..2c9affe --- /dev/null +++ b/DAL/Models/Signup.cs @@ -0,0 +1,39 @@ +using DAL.Models.Audits; +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DAL.Models +{ + [Table("signup")] + [Index("eventId", Name = "signup_event_id_fk")] + [Index("userId", Name = "signup_users_id_fk")] + [Index("updater", Name = "signup_users_id_fk_2")] + public class Signup : Model + { + [Column("eventId")] + public ulong eventId { get; set; } + + [Column("userid")] + public ulong userId { get; set; } + + public Event eventIdRelation { get; set; } = null!; + + public User userIdRelation { get; set; } = null!; + + public override AuditSignup adaptToAudit() + { + return new AuditSignup + { + id = id, + eventId = eventId, + userId = userId, + }; + } + + public override void updateModel(ref Signup dest) + { + dest.eventId = eventId; + dest.userId = userId; + } + } +} diff --git a/Setup/Filler/Grants.sql b/Setup/Filler/Grants.sql index 1c96164..a420cfd 100644 --- a/Setup/Filler/Grants.sql +++ b/Setup/Filler/Grants.sql @@ -177,4 +177,28 @@ VALUES ('api.user.update.permission', 1, NOW(), 1); INSERT INTO san_antonio_senior_golf.grants (name, permissionId, updated, updater) VALUES ('api.user.delete.any', 1, NOW(), 1); +INSERT INTO san_antonio_senior_golf.grants (name, permissionId, updated, updater) +VALUES ('api.signup.get.all', 1, NOW(), 1); + +INSERT INTO san_antonio_senior_golf.grants (name, permissionId, updated, updater) +VALUES ('api.signup.get.any', 1, NOW(), 1); + +INSERT INTO san_antonio_senior_golf.grants (name, permissionId, updated, updater) +VALUES ('api.signup.get', 1, NOW(), 1); + +INSERT INTO san_antonio_senior_golf.grants (name, permissionId, updated, updater) +VALUES ('api.signup.add', 1, NOW(), 1); + +INSERT INTO san_antonio_senior_golf.grants (name, permissionId, updated, updater) +VALUES ('api.signup.update.any', 1, NOW(), 1); + +INSERT INTO san_antonio_senior_golf.grants (name, permissionId, updated, updater) +VALUES ('api.signup.update', 1, NOW(), 1); + +INSERT INTO san_antonio_senior_golf.grants (name, permissionId, updated, updater) +VALUES ('api.signup.delete.any', 1, NOW(), 1); + +INSERT INTO san_antonio_senior_golf.grants (name, permissionId, updated, updater) +VALUES ('api.signup.delete', 1, NOW(), 1); + SET FOREIGN_KEY_CHECKS = 1;