Compare commits

...

52 Commits

Author SHA1 Message Date
93ee75d021 Added functionality to change password 2024-12-19 19:33:45 -06:00
0b88ebd2e8 Missing permission for users to remove their own signup 2024-12-19 16:00:48 -06:00
cb5c5b6b4f Ability to set user permissionId for registration 2024-10-29 19:14:58 -05:00
777fb1c4c9 EventUpdateDTO when UnSettable 2024-10-29 19:14:35 -05:00
4fc88d90ce SignupController getForEvent, delete -> deleteForEvent rename 2024-10-29 19:14:11 -05:00
d48186d4d6 SignupAuthentication canAddOthers for admin 2024-10-29 19:13:28 -05:00
048ccd7c4c GrantManager getValues off by one 2024-10-29 19:12:29 -05:00
eac9c784fb EventController getPeriod speed improvements 2024-10-29 19:11:53 -05:00
e62f390942 Added grants getMine 2024-08-31 20:59:42 -05:00
787cdf5c6d event isSignedUp 2024-08-31 18:38:43 -05:00
f212f85d00 Added signup support 2024-08-31 18:38:07 -05:00
fe1213ed90 Deleted web. Added when to event 2024-08-30 00:25:46 -05:00
ea3799e9b0 Razor web app boilerplate 2024-08-19 17:08:14 -05:00
374b8c64c9 Added grantManager and authentication now uses GrantManager.cs 2024-08-19 16:08:35 -05:00
63b95b7ee6 Added basic setup program to get initial data into database 2024-07-15 18:08:11 -05:00
13f92d49cc Auditing is now the responsibility of the database. Removed foregin key from audit tables to parent 2024-07-15 17:51:03 -05:00
a07f5f5869 Removed YesAuthentication 2024-07-15 13:24:59 -05:00
d8b98ac5cc added UserAuthentication 2024-07-15 13:23:58 -05:00
4afb3b0c54 Added SavedEventAuthentication 2024-07-13 13:08:59 -05:00
588abd2712 Added PermissionAuthentication 2024-07-13 12:58:35 -05:00
d5a7ffc596 Added ImageAuthentication 2024-07-13 12:51:45 -05:00
71cabbd548 Added GrantAuthentication 2024-07-13 12:44:46 -05:00
7ae98f4bb4 Added EventAuthentication 2024-07-12 23:12:04 -05:00
58cf1cd74c ColorAuthentication no longer is YesAuthentication 2024-07-12 22:44:58 -05:00
0cdc5ebb20 Added functions for getting grants. 2024-07-12 22:44:46 -05:00
18ab0b592f Program now uses Authentication and Authorization 2024-07-12 18:05:54 -05:00
1dd4d3dca7 Added register user 2024-07-12 17:27:01 -05:00
d58eb8d973 Made user updater and updaterrelation nullable 2024-07-12 17:26:41 -05:00
e2140d83f2 Changed phone number to use PhoneNumber.cs implicit string 2024-07-10 18:35:53 -05:00
1086396ccd Added authcontroller and logins 2024-07-09 18:03:42 -05:00
ca059ce75d Added hashing algorithm and factory 2024-07-09 18:03:05 -05:00
8b6bcc7c37 Package updates & downgrades to 8.xx 2024-07-09 18:01:38 -05:00
a44fb7b278 Added keys to audit tables 2024-07-09 18:01:12 -05:00
6876b623ac Created remaining CRUD controllers 2024-05-20 15:11:13 -05:00
2a99a5ba62 Created missing UpdateDTOS 2024-05-20 15:00:52 -05:00
e5522ed559 Code cleanup 2024-05-20 14:12:46 -05:00
d5642e4744 implemented adaptFromModel into remaining DTOS 2024-05-20 14:10:46 -05:00
08efea943c Created ColorController 2024-05-20 10:47:04 -05:00
cce57a4aec Created base class for CRUD api calls 2024-05-20 10:46:56 -05:00
9fb3e52079 Added authentication services to program 2024-05-20 10:46:31 -05:00
bce57e4cf0 Added adaptFromModel to IAdaptable 2024-05-20 10:46:15 -05:00
890c521675 Added ColorUpdateDTO.cs 2024-05-20 10:45:46 -05:00
8c58bb2fa3 Added ColorAuthentication.cs 2024-05-20 10:44:18 -05:00
71eea092c7 XML Documentation generated 2024-05-20 10:44:00 -05:00
03a72c365d Added update methods to models 2024-04-24 16:04:15 -05:00
27846f596e Created services for remaining database models 2024-04-22 18:04:14 -05:00
10cce72fbc Added DTO for remaining models 2024-04-22 17:55:47 -05:00
99b3f65c97 Updated models to use inheritance 2024-04-22 17:34:27 -05:00
f7b337e25a Created color service using ServiceBase 2024-04-22 16:54:28 -05:00
0b2c77d4cc Added api project boilerplate 2024-04-16 18:38:11 -05:00
37536443d3 Deleted website and unit tests project 2024-04-16 16:22:47 -05:00
46b57505ef Added DAL 2024-04-16 16:17:48 -05:00
135 changed files with 3962 additions and 1492 deletions

12
.gitignore vendored
View File

@ -1,4 +1,8 @@
/website/bin/ /DAL/bin/
/website/obj/ /DAL/obj/
/unitTests/bin/ /API/bin/
/unitTests/obj/ /API/obj/
/API/appsettings.*
/Setup/bin/
/Setup/obj/
/Setup/appsettings.*

View File

@ -6,6 +6,12 @@
<synchronize>true</synchronize> <synchronize>true</synchronize>
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver> <jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mysql://192.168.1.52:5618</jdbc-url> <jdbc-url>jdbc:mysql://192.168.1.52:5618</jdbc-url>
<jdbc-additional-properties>
<property name="com.intellij.clouds.kubernetes.db.host.port" />
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
<property name="com.intellij.clouds.kubernetes.db.resource.type" value="Deployment" />
<property name="com.intellij.clouds.kubernetes.db.container.port" />
</jdbc-additional-properties>
<working-dir>$ProjectFileDir$</working-dir> <working-dir>$ProjectFileDir$</working-dir>
<driver-properties> <driver-properties>
<property name="serverTimezone" value="UTC" /> <property name="serverTimezone" value="UTC" />
@ -19,5 +25,18 @@
<jdbc-url>jdbc:sqlite:$USER_HOME$/.local/share/scoreSphere/core.sqlite</jdbc-url> <jdbc-url>jdbc:sqlite:$USER_HOME$/.local/share/scoreSphere/core.sqlite</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir> <working-dir>$ProjectFileDir$</working-dir>
</data-source> </data-source>
<data-source source="LOCAL" name="SASG" uuid="65a22a18-3e0c-46e8-afbf-198b2bbb4f78">
<driver-ref>mysql.8</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mysql://localhost:5618</jdbc-url>
<jdbc-additional-properties>
<property name="com.intellij.clouds.kubernetes.db.host.port" />
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
<property name="com.intellij.clouds.kubernetes.db.resource.type" value="Deployment" />
<property name="com.intellij.clouds.kubernetes.db.container.port" />
</jdbc-additional-properties>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component> </component>
</project> </project>

View File

@ -1,14 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="PublishConfigData" serverName="boysserver" remoteFilesAllowedToDisappearOnAutoupload="false"> <component name="PublishConfigData" serverName="temp" remoteFilesAllowedToDisappearOnAutoupload="false" />
<serverData>
<paths name="boysserver">
<serverdata>
<mappings>
<mapping deploy="/" local="$PROJECT_DIR$" web="/" />
</mappings>
</serverdata>
</paths>
</serverData>
</component>
</project> </project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SqlDialectMappings">
<file url="file://$PROJECT_DIR$/Setup/Filler/Permissions.sql" dialect="MySQL" />
</component>
</project>

View File

@ -2,6 +2,8 @@
<project version="4"> <project version="4">
<component name="SshConfigs"> <component name="SshConfigs">
<configs> <configs>
<sshConfig host="4.72.148.132.host.secureserver.net" id="803b7675-648e-4d0f-8433-0abf8725c35f" keyPath="$USER_HOME$/.ssh/dotnetSanAntonioSeniorGolf" port="22" nameFormat="DESCRIPTIVE" username="dotnet" useOpenSSHConfig="false" />
<sshConfig host="4.72.148.132.host.secureserver.net" id="7db7f912-3e0a-4cfc-90fe-563abe88fa2c" keyPath="$USER_HOME$/.ssh/sanantonioseniorgolf" port="22" nameFormat="DESCRIPTIVE" username="oaksana" useOpenSSHConfig="true" />
<sshConfig host="192.168.1.52" id="e58264ea-75c0-4f9e-aa5c-b6ece113fffb" keyPath="$USER_HOME$/.ssh/dotnet" port="22" nameFormat="DESCRIPTIVE" username="dotnet" /> <sshConfig host="192.168.1.52" id="e58264ea-75c0-4f9e-aa5c-b6ece113fffb" keyPath="$USER_HOME$/.ssh/dotnet" port="22" nameFormat="DESCRIPTIVE" username="dotnet" />
</configs> </configs>
</component> </component>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="WebServers">
<option name="servers">
<webServer id="a7501199-1083-42a2-9cb8-0a02a845371d" name="temp" url="http://signup.sanantonioseniorgolf.com/">
<fileTransfer rootFolder="/home/dotnet/signupBackend.rewrite/API" accessType="SFTP" host="4.72.148.132.host.secureserver.net" port="22" sshConfigId="803b7675-648e-4d0f-8433-0abf8725c35f" sshConfig="dotnet@4.72.148.132.host.secureserver.net:22 key" keyPair="true">
<advancedOptions>
<advancedOptions dataProtectionLevel="Private" keepAliveTimeout="0" passiveMode="true" shareSSLContext="true" />
</advancedOptions>
</fileTransfer>
</webServer>
</option>
</component>
</project>

23
API/API.csproj Normal file
View File

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.7"/>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.7"/>
<PackageReference Include="Serilog.AspNetCore" Version="8.0.2-dev-00338"/>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DAL\DAL.csproj"/>
</ItemGroup>
</Project>

View File

@ -0,0 +1,44 @@
using API.Authentication.GrantNames;
using API.Authentication.Interfaces;
using API.DTO.Base;
using API.Services;
using API.Services.Interfaces;
using DAL.Models;
namespace API.Authentication
{
public class ColorAuthentication : IColorAuthentication
{
private readonly IGrantManager _grantManager;
private readonly ILogger<ColorAuthentication> _logger;
public ColorAuthentication(ILogger<ColorAuthentication> logger, IGrantManager grantManager)
{
_logger = logger;
_grantManager = grantManager;
}
public bool canGetAll(User user)
{
return _grantManager.hasGrant(user.permissionId, ColorGrantNames.CanGetAll);
}
public bool canGet(Color model, User user)
{
return _grantManager.hasGrant(user.permissionId, ColorGrantNames.CanGetAny) ||
_grantManager.getULongValues(user.permissionId, ColorGrantNames.CanGet).Exists(x => x == model.id);
}
public bool canAdd(ColorDTO item, User user)
{
return _grantManager.hasGrant(user.permissionId, ColorGrantNames.CanAdd);
}
public bool canUpdate(Color model, User user)
{
return _grantManager.hasGrant(user.permissionId, ColorGrantNames.CanUpdateAny) ||
_grantManager.getULongValues(user.permissionId, ColorGrantNames.CanUpdate).Exists(x => x == model.id);
}
public bool canDelete(Color model, User user)
{
return _grantManager.hasGrant(user.permissionId, ColorGrantNames.CanDeleteAny) ||
_grantManager.getULongValues(user.permissionId, ColorGrantNames.CanDelete).Exists(x => x == model.id);
}
}
}

View File

@ -0,0 +1,50 @@
using API.Authentication.GrantNames;
using API.Authentication.Interfaces;
using API.DTO.Base;
using API.Services;
using API.Services.Interfaces;
using DAL.Models;
namespace API.Authentication
{
public class EventAuthentication : IEventAuthentication
{
private readonly IGrantManager _grantManager;
private readonly ILogger<EventAuthentication> _logger;
public EventAuthentication(IGrantManager grantManager, ILogger<EventAuthentication> logger)
{
_grantManager = grantManager;
_logger = logger;
}
public bool canGetAll(User user)
{
return _grantManager.hasGrant(user.permissionId, EventGrantNames.CanGetAll);
}
public bool canGet(Event model, User user)
{
return _grantManager.hasGrant(user.permissionId, EventGrantNames.CanGetAny) ||
_grantManager.getULongValues(user.permissionId, EventGrantNames.CanGet).Exists(x => x == model.id);
}
public bool canAdd(EventDTO item, User user)
{
return _grantManager.hasGrant(user.permissionId, EventGrantNames.CanAdd);
}
public bool canUpdate(Event model, User user)
{
return _grantManager.hasGrant(user.permissionId, EventGrantNames.CanUpdateAny) ||
_grantManager.getULongValues(user.permissionId, EventGrantNames.CanUpdate).Exists(x => x == model.id);
}
public bool canDelete(Event model, User user)
{
return _grantManager.hasGrant(user.permissionId, EventGrantNames.CanDeleteAny) ||
_grantManager.getULongValues(user.permissionId, EventGrantNames.CanDelete).Exists(x => x == model.id);
}
public bool canCheckSelfSignup(User user)
{
//todo grants
return true;
}
}
}

View File

@ -0,0 +1,51 @@
using API.Authentication.GrantNames;
using API.Authentication.Interfaces;
using API.DTO.Base;
using API.Services;
using API.Services.Interfaces;
using DAL.Models;
namespace API.Authentication
{
public class GrantAuthentication : IGrantAuthentication
{
private readonly IGrantManager _grantManager;
private readonly ILogger<GrantAuthentication> _logger;
public GrantAuthentication(IGrantManager grantManager, ILogger<GrantAuthentication> logger)
{
_grantManager = grantManager;
_logger = logger;
}
public bool canGetAll(User user)
{
return _grantManager.hasGrant(user.permissionId, GrantGrantNames.CanGetAll);
}
public bool canGet(Grant model, User user)
{
return _grantManager.hasGrant(user.permissionId, GrantGrantNames.CanGetAny) ||
_grantManager.getULongValues(user.permissionId, GrantGrantNames.CanGet).Exists(x => x == model.id);
}
public bool canAdd(GrantDTO item, User user)
{
return _grantManager.hasGrant(user.permissionId, GrantGrantNames.CanAdd) &&
_grantManager.hasGrant(user.permissionId, item.name);
}
public bool canUpdate(Grant model, User user)
{
// Doesn't make sense to update the name of a grant. The updater can just delete and remake.
return false;
}
public bool canDelete(Grant model, User user)
{
return (_grantManager.hasGrant(user.permissionId, GrantGrantNames.CanDeleteAny) ||
_grantManager.getULongValues(user.permissionId, GrantGrantNames.CanDelete).Exists(x => x == model.id))
&& _grantManager.hasGrant(user.permissionId, model.name);
}
public bool canGetMine(User user)
{
return _grantManager.hasGrant(user.permissionId, GrantGrantNames.CanGetSelf);
}
}
}

View File

@ -0,0 +1,14 @@
namespace API.Authentication.GrantNames
{
public static class ColorGrantNames
{
public const string CanGetAll = "api.color.get.all";
public const string CanGetAny = "api.color.get.any";
public const string CanGet = "api.color.get";
public const string CanAdd = "api.color.add";
public const string CanUpdateAny = "api.color.update.any";
public const string CanUpdate = "api.color.update";
public const string CanDeleteAny = "api.color.delete.any";
public const string CanDelete = "api.color.delete";
}
}

View File

@ -0,0 +1,14 @@
namespace API.Authentication.GrantNames
{
public static class EventGrantNames
{
public const string CanGetAll = "api.event.get.all";
public const string CanGetAny = "api.event.get.any";
public const string CanGet = "api.event.get";
public const string CanAdd = "api.event.add";
public const string CanUpdateAny = "api.event.update.any";
public const string CanUpdate = "api.event.update";
public const string CanDeleteAny = "api.event.delete.any";
public const string CanDelete = "api.event.delete";
}
}

View File

@ -0,0 +1,15 @@
namespace API.Authentication.GrantNames
{
public static class GrantGrantNames
{
public const string CanGetSelf = "api.grant.get.self";
public const string CanGetAll = "api.grant.get.all";
public const string CanGetAny = "api.grant.get.any";
public const string CanGet = "api.grant.get";
public const string CanAdd = "api.grant.add";
public const string CanUpdateAny = "api.grant.update.any";
public const string CanUpdate = "api.grant.update";
public const string CanDeleteAny = "api.grant.delete.any";
public const string CanDelete = "api.grant.delete";
}
}

View File

@ -0,0 +1,14 @@
namespace API.Authentication.GrantNames
{
public static class ImageGrantNames
{
public const string CanGetAll = "api.image.get.all";
public const string CanGetAny = "api.image.get.any";
public const string CanGet = "api.image.get";
public const string CanAdd = "api.image.add";
public const string CanUpdateAny = "api.image.update.any";
public const string CanUpdate = "api.image.update";
public const string CanDeleteAny = "api.image.delete.any";
public const string CanDelete = "api.image.delete";
}
}

View File

@ -0,0 +1,14 @@
namespace API.Authentication.GrantNames
{
public static class PermissionGrantNames
{
public const string CanGetAll = "api.permission.get.all";
public const string CanGetAny = "api.permission.get.any";
public const string CanGet = "api.permission.get";
public const string CanAdd = "api.permission.add";
public const string CanUpdateAny = "api.permission.update.any";
public const string CanUpdate = "api.permission.update";
public const string CanDeleteAny = "api.permission.delete.any";
public const string CanDelete = "api.permission.delete";
}
}

View File

@ -0,0 +1,14 @@
namespace API.Authentication.GrantNames
{
public static class SavedEventGrantNames
{
public const string CanGetAll = "api.savedEvent.get.all";
public const string CanGetAny = "api.savedEvent.get.any";
public const string CanGet = "api.savedEvent.get";
public const string CanAdd = "api.savedEvent.add";
public const string CanUpdateAny = "api.savedEvent.update.any";
public const string CanUpdate = "api.savedEvent.update";
public const string CanDeleteAny = "api.savedEvent.delete.any";
public const string CanDelete = "api.savedEvent.delete";
}
}

View File

@ -0,0 +1,16 @@
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";
public const string CanDeleteSelf = "api.signup.delete.self";
public const string CanAddOthers = "api.signup.add.others";
}
}

View File

@ -0,0 +1,20 @@
namespace API.Authentication.GrantNames
{
public static class UserGrantNames
{
public const string CanGetAll = "api.user.get.all";
public const string CanGetAny = "api.user.get.any";
public const string CanGet = "api.user.get";
public const string CanAdd = "api.user.add";
public const string CanUpdateAny = "api.user.update.any";
public const string CanUpdate = "api.user.update";
public const string CanUpdateSelf = "api.user.update.self";
public const string CanUpdateNames = "api.user.update.names";
public const string CanUpdatePhoneNumber = "api.user.update.phoneNumber";
public const string CanUpdatePermission = "api.user.update.permission";
public const string CanDeleteAny = "api.user.delete.any";
public const string CanDelete = "api.user.delete";
public const string CanChangePasswordSelf = "api.user.update.password.self";
public const string CanChangePasswordOthers = "api.user.update.password.others";
}
}

View File

@ -0,0 +1,44 @@
using API.Authentication.GrantNames;
using API.Authentication.Interfaces;
using API.DTO.Base;
using API.Services;
using API.Services.Interfaces;
using DAL.Models;
namespace API.Authentication
{
public class ImageAuthentication : IImageAuthentication
{
private readonly IGrantManager _grantManager;
private readonly ILogger<ImageAuthentication> _logger;
public ImageAuthentication(ILogger<ImageAuthentication> logger, IGrantManager grantManager)
{
_logger = logger;
_grantManager = grantManager;
}
public bool canGetAll(User user)
{
return _grantManager.hasGrant(user.permissionId, ImageGrantNames.CanGetAll);
}
public bool canGet(Image model, User user)
{
return _grantManager.hasGrant(user.permissionId, ImageGrantNames.CanGetAny) ||
_grantManager.getULongValues(user.permissionId, ImageGrantNames.CanGet).Exists(x => x == model.id);
}
public bool canAdd(ImageDTO item, User user)
{
return _grantManager.hasGrant(user.permissionId, ImageGrantNames.CanAdd);
}
public bool canUpdate(Image model, User user)
{
return _grantManager.hasGrant(user.permissionId, ImageGrantNames.CanUpdateAny) ||
_grantManager.getULongValues(user.permissionId, ImageGrantNames.CanUpdate).Exists(x => x == model.id);
}
public bool canDelete(Image model, User user)
{
return _grantManager.hasGrant(user.permissionId, ImageGrantNames.CanDeleteAny) ||
_grantManager.getULongValues(user.permissionId, ImageGrantNames.CanDelete).Exists(x => x == model.id);
}
}
}

View File

@ -0,0 +1,9 @@
using API.DTO.Base;
using DAL.Models;
namespace API.Authentication.Interfaces
{
public interface IColorAuthentication : IGenericAuthentication<ColorDTO, Color>
{
}
}

View File

@ -0,0 +1,10 @@
using API.DTO.Base;
using DAL.Models;
namespace API.Authentication.Interfaces
{
public interface IEventAuthentication : IGenericAuthentication<EventDTO, Event>
{
bool canCheckSelfSignup(User user);
}
}

View File

@ -0,0 +1,13 @@
using DAL.Models;
namespace API.Authentication.Interfaces
{
public interface IGenericAuthentication<in T, in TModel>
{
bool canGetAll(User user);
bool canGet(TModel model, User user);
bool canAdd(T item, User user);
bool canUpdate(TModel model, User user);
bool canDelete(TModel model, User user);
}
}

View File

@ -0,0 +1,10 @@
using API.DTO.Base;
using DAL.Models;
namespace API.Authentication.Interfaces
{
public interface IGrantAuthentication : IGenericAuthentication<GrantDTO, Grant>
{
bool canGetMine(User user);
}
}

View File

@ -0,0 +1,9 @@
using API.DTO.Base;
using DAL.Models;
namespace API.Authentication.Interfaces
{
public interface IImageAuthentication : IGenericAuthentication<ImageDTO, Image>
{
}
}

View File

@ -0,0 +1,9 @@
using API.DTO.Base;
using DAL.Models;
namespace API.Authentication.Interfaces
{
public interface IPermissionAuthentication : IGenericAuthentication<PermissionDTO, Permission>
{
}
}

View File

@ -0,0 +1,9 @@
using API.DTO.Base;
using DAL.Models;
namespace API.Authentication.Interfaces
{
public interface ISavedEventAuthentication : IGenericAuthentication<SavedEventDTO, SavedEvent>
{
}
}

View File

@ -0,0 +1,9 @@
using API.DTO.Base.Update;
using DAL.Models;
namespace API.Authentication.Interfaces
{
public interface ISignupAuthentication : IGenericAuthentication<SignupDTO, Signup>
{
}
}

View File

@ -0,0 +1,10 @@
using API.DTO.Base;
using DAL.Models;
namespace API.Authentication.Interfaces
{
public interface IUserAuthentication : IGenericAuthentication<UserDTO, User>
{
bool canChangePassword(User destUser, User changingUser, bool oldPasswordMatchNew);
}
}

View File

@ -0,0 +1,45 @@
using API.Authentication.GrantNames;
using API.Authentication.Interfaces;
using API.DTO.Base;
using API.Services;
using API.Services.Interfaces;
using DAL.Models;
namespace API.Authentication
{
public class PermissionAuthentication : IPermissionAuthentication
{
private readonly IGrantManager _grantManager;
private readonly ILogger<PermissionAuthentication> _logger;
public PermissionAuthentication(ILogger<PermissionAuthentication> logger, IGrantManager grantManager)
{
_logger = logger;
_grantManager = grantManager;
}
public bool canGetAll(User user)
{
return _grantManager.hasGrant(user.permissionId, PermissionGrantNames.CanGetAll);
}
public bool canGet(Permission model, User user)
{
return _grantManager.hasGrant(user.permissionId, PermissionGrantNames.CanGetAny) ||
_grantManager.getULongValues(user.permissionId, PermissionGrantNames.CanGet).Exists(x => x == model.id);
}
public bool canAdd(PermissionDTO item, User user)
{
return _grantManager.hasGrant(user.permissionId, PermissionGrantNames.CanAdd);
}
public bool canUpdate(Permission model, User user)
{
return _grantManager.hasGrant(user.permissionId, PermissionGrantNames.CanUpdateAny) ||
_grantManager.getULongValues(user.permissionId, PermissionGrantNames.CanUpdate).Exists(x => x == model.id);
}
public bool canDelete(Permission model, User user)
{
return (_grantManager.hasGrant(user.permissionId, PermissionGrantNames.CanDeleteAny) ||
_grantManager.getULongValues(user.permissionId, PermissionGrantNames.CanDelete).Exists(x => x == model.id))
&& model.id != user.permissionId;
}
}
}

View File

@ -0,0 +1,44 @@
using API.Authentication.GrantNames;
using API.Authentication.Interfaces;
using API.DTO.Base;
using API.Services;
using API.Services.Interfaces;
using DAL.Models;
namespace API.Authentication
{
public class SavedEventAuthentication : ISavedEventAuthentication
{
private readonly IGrantManager _grantManager;
private readonly ILogger<SavedEventAuthentication> _logger;
public SavedEventAuthentication(ILogger<SavedEventAuthentication> logger, IGrantManager grantManager)
{
_logger = logger;
_grantManager = grantManager;
}
public bool canGetAll(User user)
{
return _grantManager.hasGrant(user.permissionId, SavedEventGrantNames.CanGetAll);
}
public bool canGet(SavedEvent model, User user)
{
return _grantManager.hasGrant(user.permissionId, SavedEventGrantNames.CanGetAny) ||
_grantManager.getULongValues(user.permissionId, SavedEventGrantNames.CanGet).Exists(x => x == model.id);
}
public bool canAdd(SavedEventDTO item, User user)
{
return _grantManager.hasGrant(user.permissionId, SavedEventGrantNames.CanAdd);
}
public bool canUpdate(SavedEvent model, User user)
{
return _grantManager.hasGrant(user.permissionId, SavedEventGrantNames.CanUpdateAny) ||
_grantManager.getULongValues(user.permissionId, SavedEventGrantNames.CanUpdate).Exists(x => x == model.id);
}
public bool canDelete(SavedEvent model, User user)
{
return _grantManager.hasGrant(user.permissionId, SavedEventGrantNames.CanDeleteAny) ||
_grantManager.getULongValues(user.permissionId, SavedEventGrantNames.CanDelete).Exists(x => x == model.id);
}
}
}

View File

@ -0,0 +1,49 @@
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<SignupAuthentication> _logger;
public SignupAuthentication(IGrantManager grantManager, ILogger<SignupAuthentication> 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)
{
if (item.userId == user.id)
return _grantManager.hasGrant(user.permissionId, SignupGrantNames.CanAdd);
return _grantManager.hasGrant(user.permissionId, SignupGrantNames.CanAddOthers);
}
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) ||
(model.userId == user.id && _grantManager.hasGrant(user.permissionId, SignupGrantNames.CanDeleteSelf)) ||
_grantManager.getULongValues(user.permissionId, SignupGrantNames.CanDelete).Exists(x => x == model.id);
}
}
}

View File

@ -0,0 +1,90 @@
using API.Authentication.GrantNames;
using API.Authentication.Interfaces;
using API.DTO.Base;
using API.Services;
using API.Services.Interfaces;
using DAL.Models;
namespace API.Authentication
{
public class UserAuthentication : IUserAuthentication
{
private readonly IGrantManager _grantManager;
private readonly ILogger<UserAuthentication> _logger;
public UserAuthentication(ILogger<UserAuthentication> logger, IGrantManager grantManager)
{
_logger = logger;
_grantManager = grantManager;
}
public bool canGetAll(User user)
{
return _grantManager.hasGrant(user.permissionId, UserGrantNames.CanGetAll);
}
public bool canGet(User model, User user)
{
return _grantManager.hasGrant(user.permissionId, UserGrantNames.CanGetAny) ||
_grantManager.getULongValues(user.permissionId, UserGrantNames.CanGet).Exists(x => x == model.id);
}
public bool canAdd(UserDTO item, User user)
{
return _grantManager.hasGrant(user.permissionId, UserGrantNames.CanAdd);
}
// todo this needs to be made much better
public bool canUpdate(User model, User user)
{
User origUser = user;
if (model.id == user.id)
{
if (!_grantManager.hasGrant(user.permissionId, UserGrantNames.CanUpdateSelf)
|| !_grantManager.hasGrant(user.permissionId, UserGrantNames.CanUpdateAny)
)
return false;
// Don't let the user change their own permissionId
if (model.permissionId != user.permissionId)
return false;
origUser = user;
}
// else
// {
// origUser = _userService.getNoAuthentication(model.id) ?? throw new InvalidOperationException("Model is null.");
// }
if (origUser.permissionId != model.permissionId)
{
if (!_grantManager.hasGrant(user.permissionId, UserGrantNames.CanUpdatePermission))
return false;
}
if (origUser.firstName != user.firstName || origUser.lastName != user.lastName)
{
if (!_grantManager.hasGrant(user.permissionId, UserGrantNames.CanUpdateNames))
return false;
}
if (origUser.phoneNumber != user.phoneNumber)
{
if (!_grantManager.hasGrant(user.permissionId, UserGrantNames.CanUpdatePhoneNumber))
return false;
}
return _grantManager.hasGrant(user.permissionId, UserGrantNames.CanUpdateAny)
|| model.id == user.id &&
_grantManager.hasGrant(user.permissionId, UserGrantNames.CanUpdateSelf)
|| _grantManager.getULongValues(user.permissionId, UserGrantNames.CanUpdate).Exists(x => x == model.id);
}
public bool canDelete(User model, User user)
{
return (_grantManager.hasGrant(user.permissionId, UserGrantNames.CanDeleteAny) ||
_grantManager.getULongValues(user.permissionId, UserGrantNames.CanDelete).Exists(x => x == model.id))
&& model.id != user.id;
}
public bool canChangePassword(User destUser, User changingUser, bool oldPasswordMatchNew)
{
return (destUser.id == changingUser.id && _grantManager.hasGrant(changingUser.permissionId, UserGrantNames.CanChangePasswordSelf) && oldPasswordMatchNew) ||
_grantManager.hasGrant(changingUser.permissionId, UserGrantNames.CanChangePasswordOthers);
}
}
}

View File

@ -0,0 +1,107 @@
using API.DTO.Base;
using API.DTO.Base.Update;
using API.DTO.Login;
using API.Errors;
using API.Services;
using API.Services.Interfaces;
using DAL.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
namespace API.Controllers
{
[ApiController]
[Route("api/v1/[controller]")]
public class AuthController : ControllerBase
{
private readonly ILogger<AuthController> _logger;
private readonly IUserManager _userManager;
private readonly UserService _userService;
public AuthController(ILogger<AuthController> logger, IUserManager userManager, UserService userService)
{
_logger = logger;
_userManager = userManager;
_userService = userService;
}
[HttpPost("login")]
public ActionResult<UserDTO> login(UserLoginDTO userLogin)
{
UserDTO? user = _userManager.authenticateUser(userLogin);
if (user == null)
return new UnauthorizedResult();
Claim[] claims =
{
new Claim(ClaimTypes.NameIdentifier, user.id.ToString())
};
ClaimsIdentity claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
//todo confirm if this is accurate
AuthenticationProperties authProperties = new AuthenticationProperties();
HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties);
return Ok(user);
}
[HttpPost("register")]
public ActionResult<UserDTO> register(UserRegisterDTO registerDTO, ulong? permissionId = null)
{
if (registerDTO.password == null)
registerDTO.password = registerDTO.phoneNumber;
if (permissionId != null)
{
User? user = getUser(User);
if (user == null)
return Unauthorized();
UserDTO? createdUser = _userManager.registerUser(registerDTO, user, permissionId);
if (createdUser == null)
return Conflict(Strings.UserExists);
return Ok(createdUser);
}
else {
UserDTO? user = _userManager.registerUser(registerDTO);
if (user == null)
{
return Conflict(Strings.UserExists);
}
return Ok(user);
}
}
[HttpPut("changePassword")]
public ActionResult<UserDTO> changePassword(UserPasswordUpdateDTO passwordUpdateDTO)
{
User? user = getUser(User);
if (user == null)
return Unauthorized();
UserDTO? result = _userManager.changePassword(passwordUpdateDTO, user);
if (result == null)
return Forbid();
return result;
}
[NonAction]
public User? getUser(ClaimsPrincipal user)
{
Claim? idClaim = user.FindFirst(ClaimTypes.NameIdentifier);
if (idClaim == null)
return null;
return _userService.getNoAuthentication(UInt64.Parse(idClaim.Value));
}
}
}

141
API/Controllers/CRUDBase.cs Normal file
View File

@ -0,0 +1,141 @@
using API.Authentication.Interfaces;
using API.DTO;
using API.Services;
using DAL.Models;
using DAL.Models.Audits;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
using MUser = DAL.Models.User;
namespace API.Controllers
{
public class CRUDBase<TLoggerCategory, TDTO, TUpdateDTO, TModel, TAuditModel, TAuthentication, TService> : ControllerBase
where TAuthentication : IGenericAuthentication<TDTO, TModel>
where TModel : Model<TModel, TAuditModel>
where TAuditModel : AuditModel<TModel>
where TDTO : IAdaptable<TModel>, new()
where TUpdateDTO : IUpdateAdaptable<TModel>
where TService : ServiceBase<TService, TDTO, TModel, TAuditModel, TAuthentication>
{
public readonly ILogger<TLoggerCategory> Logger;
public readonly TService Service;
public readonly UserService UserService;
public CRUDBase(ILogger<TLoggerCategory> logger, UserService userService, TService service)
{
Logger = logger;
UserService = userService;
Service = service;
}
[HttpGet]
public virtual ActionResult<List<TDTO>> get()
{
MUser? user = getUser(User);
if (user == null)
return Unauthorized();
IEnumerable<TModel>? result = Service.get(user);
if (result == null)
return Forbid();
List<TDTO> dtos = [];
Parallel.ForEach(result, item =>
{
TDTO dto = new TDTO();
dto.adaptFromModel(item);
dtos.Add(dto);
});
return Ok(dtos);
}
[HttpGet("{id}")]
public virtual ActionResult<TDTO> get(ulong id)
{
MUser? user = getUser(User);
if (user == null)
return Unauthorized();
TModel? result = Service.get(id, user);
if (result == null)
return Forbid();
TDTO dto = new TDTO();
dto.adaptFromModel(result);
return Ok(dto);
}
[HttpPost]
public virtual ActionResult<TDTO> add(TDTO createDTO)
{
MUser? user = getUser(User);
if (user == null)
return Unauthorized();
TModel? result = Service.add(createDTO, user);
if (result == null)
return Forbid();
TDTO dto = new TDTO();
dto.adaptFromModel(result);
return Ok(dto);
}
[HttpPut("{id}")]
public virtual ActionResult<TDTO> update(ulong id, TUpdateDTO updateDTO)
{
MUser? user = getUser(User);
if (user == null)
return Unauthorized();
TModel? result = Service.get(id, user);
if (result == null)
return Forbid();
updateDTO.adaptModel(ref result);
TModel? newResult = Service.update(result, user);
if (newResult == null)
return Forbid();
TDTO dto = new TDTO();
dto.adaptFromModel(newResult);
return Ok(dto);
}
[HttpDelete("{id}")]
public virtual ActionResult delete(ulong id)
{
MUser? user = getUser(User);
if (user == null)
return Unauthorized();
TModel? result = Service.get(id, user);
if (result == null)
return Forbid();
TAuditModel? auditModel = Service.delete(result, user);
if (auditModel == null)
return Forbid();
// todo in the future we should return the audit
return NoContent();
}
[NonAction]
public MUser? getUser(ClaimsPrincipal user)
{
Claim? idClaim = user.FindFirst(ClaimTypes.NameIdentifier);
if (idClaim == null)
return null;
return UserService.getNoAuthentication(UInt64.Parse(idClaim.Value));
}
}
}

View File

@ -0,0 +1,19 @@
using API.Authentication.Interfaces;
using API.DTO.Base;
using API.DTO.Base.Update;
using API.Services;
using DAL.Models;
using DAL.Models.Audits;
using Microsoft.AspNetCore.Mvc;
namespace API.Controllers
{
[ApiController]
[Route("api/v1/[controller]")]
public class ColorController : CRUDBase<ColorController, ColorDTO, ColorUpdateDTO, Color, AuditColor, IColorAuthentication, ColorService>
{
public ColorController(ILogger<ColorController> logger, UserService userService, ColorService service) : base(logger, userService, service)
{
}
}
}

View File

@ -0,0 +1,60 @@
using API.Authentication.Interfaces;
using API.DTO.Base;
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 EventController : CRUDBase<EventController, EventDTO, EventUpdateDTO, Event, AuditEvent, IEventAuthentication, EventService>
{
public EventController(ILogger<EventController> logger, UserService userService, EventService service) : base(logger, userService, service)
{
}
//todo slow
[HttpGet("period")]
public virtual ActionResult<List<EventDTO>> getPeriod(DateTime start, DateTime end)
{
MUser? user = getUser(User);
if (user == null)
return Unauthorized();
IEnumerable<Event>? result = Service.get(user, x => x.when >= start && x.when <= end && x.hidden == false);
if (result == null)
return Forbid();
List<EventDTO> dtos = [];
List<Event> temp = result.ToList();
Parallel.ForEach(temp, item =>
{
EventDTO dto = new EventDTO();
dto.adaptFromModel(item);
dtos.Add(dto);
});
return Ok(dtos);
}
[HttpGet("{eventId}/isSignedUp")]
public ActionResult<bool> isSignedUp(ulong eventId)
{
MUser? user = getUser(User);
if (user == null)
return Unauthorized();
bool? isSignedUp = Service.isSignedUp(user, eventId);
if (isSignedUp == null)
return Forbid();
return isSignedUp;
}
}
}

View File

@ -0,0 +1,43 @@
using API.Authentication.Interfaces;
using API.DTO.Base;
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 GrantController : CRUDBase<GrantController, GrantDTO, GrantUpdateDTO, Grant, AuditGrant, IGrantAuthentication, GrantService>
{
public GrantController(ILogger<GrantController> logger, UserService userService, GrantService service) : base(logger, userService, service)
{
}
[HttpGet("mine")]
public ActionResult<List<GrantDTO>> getMine()
{
MUser? user = getUser(User);
if (user == null)
return Unauthorized();
IEnumerable<Grant>? result = Service.getMine(user);
if (result == null)
return Forbid();
List<GrantDTO> dtos = [];
Parallel.ForEach(result, item =>
{
GrantDTO dto = new GrantDTO();
dto.adaptFromModel(item);
dtos.Add(dto);
});
return Ok(dtos);
}
}
}

View File

@ -0,0 +1,19 @@
using API.Authentication.Interfaces;
using API.DTO.Base;
using API.DTO.Base.Update;
using API.Services;
using DAL.Models;
using DAL.Models.Audits;
using Microsoft.AspNetCore.Mvc;
namespace API.Controllers
{
[ApiController]
[Route("api/v1/[controller]")]
public class ImageController : CRUDBase<ImageController, ImageDTO, ImageUpdateDTO, Image, AuditImage, IImageAuthentication, ImageService>
{
public ImageController(ILogger<ImageController> logger, UserService userService, ImageService service) : base(logger, userService, service)
{
}
}
}

View File

@ -0,0 +1,19 @@
using API.Authentication.Interfaces;
using API.DTO.Base;
using API.DTO.Base.Update;
using API.Services;
using DAL.Models;
using DAL.Models.Audits;
using Microsoft.AspNetCore.Mvc;
namespace API.Controllers
{
[ApiController]
[Route("api/v1/[controller]")]
public class PermissionController : CRUDBase<PermissionController, PermissionDTO, PermissionUpdateDTO, Permission, AuditPermission, IPermissionAuthentication, PermissionService>
{
public PermissionController(ILogger<PermissionController> logger, UserService userService, PermissionService service) : base(logger, userService, service)
{
}
}
}

View File

@ -0,0 +1,19 @@
using API.Authentication.Interfaces;
using API.DTO.Base;
using API.DTO.Base.Update;
using API.Services;
using DAL.Models;
using DAL.Models.Audits;
using Microsoft.AspNetCore.Mvc;
namespace API.Controllers
{
[ApiController]
[Route("api/v1/[controller]")]
public class SavedEventController : CRUDBase<SavedEventController, SavedEventDTO, SavedEventUpdateDTO, SavedEvent, AuditSavedEvent, ISavedEventAuthentication, SavedEventService>
{
public SavedEventController(ILogger<SavedEventController> logger, UserService userService, SavedEventService service) : base(logger, userService, service)
{
}
}
}

View File

@ -0,0 +1,84 @@
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<SignupController, SignupDTO, SignupUpdateDTO, Signup, AuditSignup, ISignupAuthentication, SignupService>
{
public SignupController(ILogger<SignupController> logger, UserService userService, SignupService service) : base(logger, userService, service)
{
}
[HttpGet("forEvent/{eventId}")]
public ActionResult<SignupDTO> getForEvent(ulong eventId)
{
MUser? user = getUser(User);
if (user == null)
return Unauthorized();
IEnumerable<Signup>? result = Service.get(user, e => e.eventId == eventId);
if (result == null)
return Forbid();
List<SignupDTO> dtos = [];
Parallel.ForEach(result, item =>
{
SignupDTO dto = new SignupDTO();
dto.adaptFromModel(item);
dtos.Add(dto);
});
return Ok(dtos);
}
[HttpPost("autoUser")]
public ActionResult<SignupDTO> 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 ActionResult deleteForEvent(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();
}
}
}

View File

@ -0,0 +1,19 @@
using API.Authentication.Interfaces;
using API.DTO.Base;
using API.DTO.Base.Update;
using API.Services;
using DAL.Models;
using DAL.Models.Audits;
using Microsoft.AspNetCore.Mvc;
namespace API.Controllers
{
[ApiController]
[Route("api/v1/[controller]")]
public class UserController : CRUDBase<UserController, UserDTO, UserUpdateDTO, User, AuditUser, IUserAuthentication, UserService>
{
public UserController(ILogger<UserController> logger, UserService userService, UserService service) : base(logger, userService, service)
{
}
}
}

42
API/DTO/Base/ColorDTO.cs Normal file
View File

@ -0,0 +1,42 @@
using DAL.Models;
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Base
{
public class ColorDTO : IAdaptable<Color>
{
public ulong id { get; set; }
public byte red { get; set; }
public byte blue { get; set; }
public byte green { get; set; }
[MaxLength(64)]
public string name { get; set; } = null!;
public DateTime updated { get; set; }
public ulong updater { get; set; }
public Color adaptToModel()
{
return new Color
{
id = id,
red = red,
blue = blue,
green = green,
name = name,
updated = updated,
updater = updater
};
}
public void adaptFromModel(in Color model)
{
id = model.id;
red = model.red;
blue = model.blue;
green = model.green;
name = model.name;
updated = model.updated;
updater = model.updater;
}
}
}

52
API/DTO/Base/EventDTO.cs Normal file
View File

@ -0,0 +1,52 @@
using DAL.Models;
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Base
{
public class EventDTO : IAdaptable<Event>
{
public ulong id { get; set; }
public ulong savedEventId { get; set; }
[MaxLength(64)]
public string? name { get; set; }
public ulong? bgColorId { get; set; }
public ulong? fgColorId { get; set; }
public ulong? imageId { get; set; }
public DateTime when { get; set; }
public bool hidden { get; set; }
public DateTime updated { get; set; }
public ulong updater { get; set; }
public Event adaptToModel()
{
return new Event
{
id = id,
savedEventId = savedEventId,
name = name,
bgColorId = bgColorId,
fgColorId = fgColorId,
imageId = imageId,
when = when,
hidden = hidden,
updated = updated,
updater = updater
};
}
public void adaptFromModel(in Event model)
{
id = model.id;
savedEventId = model.savedEventId;
name = model.name;
bgColorId = model.bgColorId;
fgColorId = model.fgColorId;
imageId = model.imageId;
when = model.when;
hidden = model.hidden;
updated = model.updated;
updater = model.updater;
}
}
}

39
API/DTO/Base/GrantDTO.cs Normal file
View File

@ -0,0 +1,39 @@
using DAL.Models;
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Base
{
public class GrantDTO : IAdaptable<Grant>
{
public ulong id { get; set; }
[MaxLength(128)]
public string name { get; set; } = null!;
public ulong permissionId { get; set; }
public DateTime updated { get; set; }
public ulong updater { get; set; }
public Grant adaptToModel()
{
return new Grant
{
id = id,
name = name,
permissionId = permissionId,
updated = updated,
updater = updater
};
}
public void adaptFromModel(in Grant model)
{
id = model.id;
name = model.name;
permissionId = model.permissionId;
updated = model.updated;
updater = model.updater;
}
}
}

40
API/DTO/Base/ImageDTO.cs Normal file
View File

@ -0,0 +1,40 @@
using DAL.Models;
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Base
{
public class ImageDTO : IAdaptable<Image>
{
public ulong id { get; set; }
[MaxLength(64)]
public string name { get; set; } = null!;
[MaxLength(128)]
public string filename { get; set; } = null!;
public DateTime updated { get; set; }
public ulong updater { get; set; }
public Image adaptToModel()
{
return new Image
{
id = id,
name = name,
filename = filename,
updated = updated,
updater = updater
};
}
public void adaptFromModel(in Image model)
{
id = model.id;
name = model.name;
filename = model.filename;
updated = model.updated;
updater = model.updater;
}
}
}

View File

@ -0,0 +1,35 @@
using DAL.Models;
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Base
{
public class PermissionDTO : IAdaptable<Permission>
{
public ulong id { get; set; }
[MaxLength(64)]
public string name { get; set; } = null!;
public DateTime updated { get; set; }
public ulong updater { get; set; }
public Permission adaptToModel()
{
return new Permission
{
id = id,
name = name,
updated = updated,
updater = updater
};
}
public void adaptFromModel(in Permission model)
{
id = model.id;
name = model.name;
updated = model.updated;
updater = model.updater;
}
}
}

View File

@ -0,0 +1,47 @@
using DAL.Models;
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Base
{
public class SavedEventDTO : IAdaptable<SavedEvent>
{
public ulong id { get; set; }
[MaxLength(64)]
public string name { get; set; } = null!;
public ulong bgColorId { get; set; }
public ulong fgColorId { get; set; }
public ulong? imageId { get; set; }
public DateTime updated { get; set; }
public ulong updater { get; set; }
public SavedEvent adaptToModel()
{
return new SavedEvent
{
id = id,
name = name,
bgColorId = bgColorId,
fgColorId = fgColorId,
imageId = imageId,
updated = updated,
updater = updater
};
}
public void adaptFromModel(in SavedEvent model)
{
id = model.id;
name = model.name;
bgColorId = model.bgColorId;
fgColorId = model.fgColorId;
imageId = model.imageId;
updated = model.updated;
updater = model.updater;
}
}
}

33
API/DTO/Base/SignupDTO.cs Normal file
View File

@ -0,0 +1,33 @@
using DAL.Models;
namespace API.DTO.Base.Update
{
public class SignupDTO : IAdaptable<Signup>
{
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;
}
}
}

View File

@ -0,0 +1,23 @@
using DAL.Models;
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Base.Update
{
public class ColorUpdateDTO : IUpdateAdaptable<Color>
{
public byte? red { get; set; }
public byte? blue { get; set; }
public byte? green { get; set; }
[MaxLength(64)]
public string? name { get; set; }
public void adaptModel(ref Color model)
{
if (red != null) model.red = (byte)red;
if (blue != null) model.blue = (byte)blue;
if (green != null) model.green = (byte)green;
if (name != null) model.name = name;
}
}
}

View File

@ -0,0 +1,29 @@
using DAL.Models;
namespace API.DTO.Base.Update
{
public class EventUpdateDTO : IUpdateAdaptable<Event>
{
public ulong? savedEventId { get; set; }
// [MaxLength(64)]
public UnSettable<string?>? name { get; set; }
public UnSettable<ulong?>? bgColorId { get; set; }
public UnSettable<ulong?>? fgColorId { get; set; }
public UnSettable<ulong?>? imageId { get; set; }
public DateTime? when { get; set; }
public bool? hidden { get; set; }
public void adaptModel(ref Event model)
{
if (savedEventId != null) model.savedEventId = (ulong)savedEventId;
if (name != null) model.name = name.Value.value;
if (bgColorId != null) model.bgColorId = bgColorId.Value.value;
if (fgColorId != null) model.fgColorId = fgColorId.Value.value;
if (imageId != null) model.imageId = imageId.Value.value;
if (when != null) model.when = (DateTime)when;
if (hidden != null) model.hidden = (bool)hidden;
}
}
}

View File

@ -0,0 +1,19 @@
using DAL.Models;
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Base.Update
{
public class GrantUpdateDTO : IUpdateAdaptable<Grant>
{
[MaxLength(128)]
public string? name { get; set; }
public ulong? permissionId { get; set; }
public void adaptModel(ref Grant model)
{
if (name != null) model.name = name;
if (permissionId != null) model.permissionId = (ulong)permissionId;
}
}
}

View File

@ -0,0 +1,20 @@
using DAL.Models;
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Base.Update
{
public class ImageUpdateDTO : IUpdateAdaptable<Image>
{
[MaxLength(64)]
public string? name { get; set; }
[MaxLength(128)]
public string? filename { get; set; }
public void adaptModel(ref Image model)
{
if (name != null) model.name = name;
if (filename != null) model.filename = filename;
}
}
}

View File

@ -0,0 +1,16 @@
using DAL.Models;
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Base.Update
{
public class PermissionUpdateDTO : IUpdateAdaptable<Permission>
{
[MaxLength(64)]
public string? name { get; set; }
public void adaptModel(ref Permission model)
{
if (name != null) model.name = name;
}
}
}

View File

@ -0,0 +1,25 @@
using DAL.Models;
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Base.Update
{
public class SavedEventUpdateDTO : IUpdateAdaptable<SavedEvent>
{
[MaxLength(64)]
public string? name { get; set; }
public ulong? bgColorId { get; set; }
public ulong? fgColorId { get; set; }
public UnSettable<ulong?>? imageId { get; set; }
public void adaptModel(ref SavedEvent model)
{
if (name != null) model.name = name;
if (bgColorId != null) model.bgColorId = (ulong)bgColorId;
if (fgColorId != null) model.fgColorId = (ulong)fgColorId;
if (imageId != null) model.imageId = imageId.Value.value;
}
}
}

View File

@ -0,0 +1,16 @@
using DAL.Models;
namespace API.DTO.Base.Update
{
public class SignupUpdateDTO : IUpdateAdaptable<Signup>
{
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;
}
}
}

View File

@ -0,0 +1,16 @@
using DAL.Values;
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Base.Update
{
public class UserPasswordUpdateDTO
{
public PhoneNumber phoneNumber { get; set; } = null!;
[MaxLength(100)]
public string? oldPassword { get; set; }
[MaxLength(100)]
public string newPassword { get; set; } = null!;
}
}

View File

@ -0,0 +1,27 @@
using DAL.Models;
using DAL.Values;
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Base.Update
{
public class UserUpdateDTO : IUpdateAdaptable<User>
{
[MaxLength(64)]
public string? firstName { get; set; }
[MaxLength(64)]
public string? lastName { get; set; }
public PhoneNumber? phoneNumber { get; set; }
public ulong? permissionId { get; set; }
public void adaptModel(ref User model)
{
if (firstName != null) model.firstName = firstName;
if (lastName != null) model.lastName = lastName;
if (phoneNumber != null) model.phoneNumber = phoneNumber;
if (permissionId != null) model.permissionId = (ulong)permissionId;
}
}
}

49
API/DTO/Base/UserDTO.cs Normal file
View File

@ -0,0 +1,49 @@
using DAL.Models;
using DAL.Values;
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Base
{
public class UserDTO : IAdaptable<User>
{
public ulong id { get; set; }
[MaxLength(64)]
public string firstName { get; set; } = null!;
[MaxLength(64)]
public string lastName { get; set; } = null!;
public PhoneNumber phoneNumber { get; set; } = null!;
public ulong permissionId { get; set; }
public DateTime updated { get; set; }
public ulong? updater { get; set; }
public User adaptToModel()
{
return new User
{
id = id,
firstName = firstName,
lastName = lastName,
phoneNumber = phoneNumber,
permissionId = permissionId,
updated = updated,
updater = updater
};
}
public void adaptFromModel(in User model)
{
id = model.id;
firstName = model.firstName;
lastName = model.lastName;
phoneNumber = model.phoneNumber;
permissionId = model.permissionId;
updated = model.updated;
updater = model.updater;
}
}
}

8
API/DTO/IAdaptable.cs Normal file
View File

@ -0,0 +1,8 @@
namespace API.DTO
{
public interface IAdaptable<TModel>
{
TModel adaptToModel();
void adaptFromModel(in TModel model);
}
}

View File

@ -0,0 +1,7 @@
namespace API.DTO
{
public interface IUpdateAdaptable<TModel>
{
void adaptModel(ref TModel model);
}
}

View File

@ -0,0 +1,13 @@
using DAL.Values;
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Login
{
public class UserLoginDTO
{
public PhoneNumber phoneNumber { get; set; } = null!;
[MaxLength(100)]
public string password { get; set; } = null!;
}
}

View File

@ -0,0 +1,19 @@
using DAL.Values;
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Login
{
public class UserRegisterDTO
{
[MaxLength(64)]
public string firstName { get; set; } = null!;
[MaxLength(64)]
public string lastName { get; set; } = null!;
public PhoneNumber phoneNumber { get; set; } = null!;
[MaxLength(1000)]
public string? password { get; set; }
}
}

7
API/DTO/UnSettable.cs Normal file
View File

@ -0,0 +1,7 @@
namespace API.DTO
{
public struct UnSettable<T>
{
public T value { get; set; }
}
}

7
API/Errors/Strings.cs Normal file
View File

@ -0,0 +1,7 @@
namespace API.Errors
{
public static class Strings
{
public const string UserExists = "User with that phone number or first and last name already exists.\nIf you would like to change your phone number please login.";
}
}

View File

@ -0,0 +1,19 @@
using API.Hashing.Interfaces;
using DAL.Models;
namespace API.Hashing
{
public class HashingFactory : IHashingFactory
{
public IHashingAlgorithm? getAlgorithm(HashingType type)
{
switch (type)
{
case HashingType.PBKDF2_SHA512_64_250000:
return new Pbkdf2();
default:
return null;
}
}
}
}

View File

@ -0,0 +1,9 @@
namespace API.Hashing.Interfaces
{
public interface IHashingAlgorithm
{
public string hash(string password, out byte[] salt);
public string hash(string password, byte[] salt);
}
}

View File

@ -0,0 +1,9 @@
using DAL.Models;
namespace API.Hashing.Interfaces
{
public interface IHashingFactory
{
public IHashingAlgorithm? getAlgorithm(HashingType type);
}
}

28
API/Hashing/Pbkdf2.cs Normal file
View File

@ -0,0 +1,28 @@
using API.Hashing.Interfaces;
using System.Security.Cryptography;
using System.Text;
namespace API.Hashing
{
public class Pbkdf2 : IHashingAlgorithm
{
private const int KeySize = 512;
private const int Iterations = 250000;
private readonly HashAlgorithmName _algorithmName = HashAlgorithmName.SHA512;
public string hash(string password, out byte[] salt)
{
salt = RandomNumberGenerator.GetBytes(KeySize);
byte[] hash = Rfc2898DeriveBytes.Pbkdf2(Encoding.UTF8.GetBytes(password), salt, Iterations, _algorithmName, KeySize);
return Convert.ToHexString(hash);
}
public string hash(string password, byte[] salt)
{
byte[] hash = Rfc2898DeriveBytes.Pbkdf2(Encoding.UTF8.GetBytes(password), salt, Iterations, _algorithmName, KeySize);
return Convert.ToHexString(hash);
}
}
}

141
API/Program.cs Normal file
View File

@ -0,0 +1,141 @@
using API.Authentication;
using API.Authentication.Interfaces;
using API.Hashing;
using API.Hashing.Interfaces;
using API.Services;
using API.Services.Interfaces;
using DAL.Contexts;
using DAL.Models;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.EntityFrameworkCore;
using Serilog;
using System.Reflection;
using ConfigurationManager = Microsoft.Extensions.Configuration.ConfigurationManager;
using InvalidOperationException = System.InvalidOperationException;
namespace API
{
internal static class Program
{
public static IServiceCollection AddLazyResolution(this IServiceCollection services)
{
return services.AddTransient(
typeof(Lazy<>),
typeof(LazilyResolved<>));
}
private class LazilyResolved<T> : Lazy<T>
{
public LazilyResolved(IServiceProvider serviceProvider)
: base(serviceProvider.GetRequiredService<T>)
{
}
}
public static void Main(string[] args)
{
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
ConfigurationManager configManager = builder.Configuration;
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
string xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
string xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
options.IncludeXmlComments(xmlPath, true);
});
builder.Host.UseSerilog((context, configuration) => configuration.ReadFrom.Configuration(context.Configuration));
builder.Services.AddDbContext<SASGContext>(options => { options.UseMySQL(builder.Configuration["connectionString"] ?? throw new InvalidOperationException("Connection String is null")); });
builder.Services.AddTransient<ColorService>();
builder.Services.AddTransient<EventService>();
builder.Services.AddTransient<GrantService>();
builder.Services.AddTransient<ImageService>();
builder.Services.AddTransient<PermissionService>();
builder.Services.AddTransient<SavedEventService>();
builder.Services.AddTransient<SignupService>();
builder.Services.AddTransient<UserService>(options =>
{
ILogger<UserService> logger = options.GetRequiredService<ILogger<UserService>>();
SASGContext context = options.GetRequiredService<SASGContext>();
IUserAuthentication authentication = options.GetRequiredService<IUserAuthentication>();
PermissionService permissionService = options.GetRequiredService<PermissionService>();
ulong defaultUserPermission = UInt64.Parse(builder.Configuration["defaultUserPermission"] ?? throw new InvalidOperationException("defaultUserPermission is null"));
return new UserService(logger, context, authentication, permissionService, defaultUserPermission);
});
builder.Services.AddTransient<IColorAuthentication, ColorAuthentication>();
builder.Services.AddTransient<IEventAuthentication, EventAuthentication>();
builder.Services.AddTransient<IGrantAuthentication, GrantAuthentication>();
builder.Services.AddTransient<IImageAuthentication, ImageAuthentication>();
builder.Services.AddTransient<IColorAuthentication, ColorAuthentication>();
builder.Services.AddTransient<IPermissionAuthentication, PermissionAuthentication>();
builder.Services.AddTransient<ISavedEventAuthentication, SavedEventAuthentication>();
builder.Services.AddTransient<IUserAuthentication, UserAuthentication>();
builder.Services.AddTransient<ISignupAuthentication, SignupAuthentication>();
builder.Services.AddTransient<IHashingFactory, HashingFactory>();
builder.Services.AddTransient<IHashingAlgorithm, Pbkdf2>();
builder.Services.AddTransient<IGrantManager, GrantManager>();
builder.Services.AddTransient<IUserManager, UserManager>(options =>
{
UserService userService = options.GetRequiredService<UserService>();
IHashingFactory hashingFactory = options.GetRequiredService<IHashingFactory>();
ILogger<UserManager> logger = options.GetRequiredService<ILogger<UserManager>>();
HashingType hashingType;
if (!Enum.TryParse(builder.Configuration["preferredHashingType"], out hashingType))
throw new InvalidOperationException($"preferredHashingType not one of {String.Join(", ", Enum.GetNames(typeof(HashingType)))}");
return new UserManager(userService, hashingFactory, logger, hashingType);
});
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
{
options.Events.OnRedirectToAccessDenied = context =>
{
context.Response.StatusCode = 403;
return Task.CompletedTask;
};
});
// builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
// {
// options.Cookie.SameSite = SameSiteMode.None;
// options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
// });
builder.Services.AddLazyResolution();
WebApplication app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseCookiePolicy(new CookiePolicyOptions
{
MinimumSameSitePolicy = SameSiteMode.Strict
});
app.UseAuthorization();
app.UseCors(builder => {
builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
});
app.UseHttpsRedirection();
app.MapControllers();
app.Run();
}
}
}

View File

@ -4,11 +4,31 @@
"windowsAuthentication": false, "windowsAuthentication": false,
"anonymousAuthentication": true, "anonymousAuthentication": true,
"iisExpress": { "iisExpress": {
"applicationUrl": "http://localhost:18853", "applicationUrl": "http://localhost:36321",
"sslPort": 44359 "sslPort": 44359
} }
}, },
"profiles": { "profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5279",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7089;http://localhost:5279",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": { "IIS Express": {
"commandName": "IISExpress", "commandName": "IISExpress",
"launchBrowser": true, "launchBrowser": true,
@ -16,16 +36,6 @@
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} }
},
"sanAntonioSeniorGolf": {
"commandName": "Project",
"dotnetRunMessages": "true",
"launchBrowser": true,
"launchUrl": "api/website/index.html",
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
} }
} }
} }

View File

@ -0,0 +1,15 @@
using API.Authentication.Interfaces;
using API.DTO.Base;
using DAL.Contexts;
using DAL.Models;
using DAL.Models.Audits;
namespace API.Services
{
public class ColorService : ServiceBase<ColorService, ColorDTO, Color, AuditColor, IColorAuthentication>
{
public ColorService(ILogger<ColorService> logger, SASGContext context, IColorAuthentication auth) : base(logger, context, auth)
{
}
}
}

View File

@ -0,0 +1,23 @@
using API.Authentication.Interfaces;
using API.DTO.Base;
using DAL.Contexts;
using DAL.Models;
using DAL.Models.Audits;
namespace API.Services
{
public class EventService : ServiceBase<EventService, EventDTO, Event, AuditEvent, IEventAuthentication>
{
public EventService(ILogger<EventService> logger, SASGContext context, IEventAuthentication auth) : base(logger, context, auth)
{
}
public bool? isSignedUp(User user, ulong eventId)
{
if (!_auth.canCheckSelfSignup(user))
return null;
return Context.Set<Signup>().Any(x => x.userId == user.id && x.eventId == eventId);
}
}
}

View File

@ -0,0 +1,85 @@
using API.Services.Interfaces;
using DAL.Contexts;
using DAL.Models;
using System.Linq.Expressions;
namespace API.Services
{
public class GrantManager : IGrantManager
{
private readonly SASGContext _context;
private ILogger<GrantManager> _logger;
public GrantManager(ILogger<GrantManager> logger, SASGContext context)
{
_logger = logger;
_context = context;
}
public bool hasGrant(ulong permissionId, string grantName)
{
return getGrant(x => x.permissionId == permissionId && x.name.Equals(grantName)).Any();
}
public List<string> getValues(ulong permissionId, string grantName)
{
List<Grant> grants = getGrant(x => x.permissionId == permissionId && x.name.StartsWith(grantName + ".")).ToList();
List<string> values = [];
foreach (Grant grant in grants)
{
string value = grant.name.Substring(grantName.Length + 1);
if (value.Contains('.'))
// Were not looking at a value and instead another grant
continue;
values.Add(value);
}
return values;
}
public List<string> getStringValues(ulong permissionId, string grantName)
{
List<string> values = getValues(permissionId, grantName);
// Get rid of numbers
values = values.Where(x => !Int32.TryParse(x, out int _)).ToList();
return values;
}
public List<int> getIntValues(ulong permissionId, string grantName)
{
List<string> values = getValues(permissionId, grantName);
List<int> intValues = [];
Parallel.ForEach(values, x =>
{
if (Int32.TryParse(x, out int parsed))
intValues.Add(parsed);
});
return intValues;
}
public List<ulong> getULongValues(ulong permissionId, string grantName)
{
List<string> values = getValues(permissionId, grantName);
List<ulong> uLongValues = [];
Parallel.ForEach(values, x =>
{
if (UInt64.TryParse(x, out ulong parsed))
uLongValues.Add(parsed);
});
return uLongValues;
}
private IEnumerable<Grant> getGrant(Expression<Func<Grant, bool>> whereClause)
{
return _context.Set<Grant>().Where(whereClause);
}
}
}

View File

@ -0,0 +1,23 @@
using API.Authentication.Interfaces;
using API.DTO.Base;
using DAL.Contexts;
using DAL.Models;
using DAL.Models.Audits;
namespace API.Services
{
public class GrantService : ServiceBase<GrantService, GrantDTO, Grant, AuditGrant, IGrantAuthentication>
{
public GrantService(ILogger<GrantService> logger, SASGContext context, IGrantAuthentication auth) : base(logger, context, auth)
{
}
public IEnumerable<Grant>? getMine(User user)
{
if (!_auth.canGetMine(user))
return null;
return Context.Set<Grant>().Where(x => x.permissionId == user.permissionId);
}
}
}

View File

@ -0,0 +1,15 @@
using API.Authentication.Interfaces;
using API.DTO.Base;
using DAL.Contexts;
using DAL.Models;
using DAL.Models.Audits;
namespace API.Services
{
public class ImageService : ServiceBase<ImageService, ImageDTO, Image, AuditImage, IImageAuthentication>
{
public ImageService(ILogger<ImageService> logger, SASGContext context, IImageAuthentication auth) : base(logger, context, auth)
{
}
}
}

View File

@ -0,0 +1,16 @@
using DAL.Models;
using System.Linq.Expressions;
namespace API.Services.Interfaces
{
public interface IGenericService<in T, TModel, out TAudit>
{
TModel? get(ulong id, User user);
IEnumerable<TModel>? get(User user, Expression<Func<TModel, bool>>? whereClause = null);
TModel? getNoAuthentication(ulong id);
IEnumerable<TModel> getNoAuthentication(Expression<Func<TModel, bool>>? whereClause = null);
TModel? add(T item, User user);
TModel? update(TModel model, User user);
TAudit? delete(TModel model, User user);
}
}

View File

@ -0,0 +1,11 @@
namespace API.Services.Interfaces
{
public interface IGrantManager
{
public bool hasGrant(ulong permissionId, string grantName);
public List<string> getValues(ulong permissionId, string grantName);
public List<string> getStringValues(ulong permissionId, string grantName);
public List<int> getIntValues(ulong permissionId, string grantName);
public List<ulong> getULongValues(ulong permissionId, string grantName);
}
}

View File

@ -0,0 +1,16 @@
using API.DTO.Base;
using API.DTO.Base.Update;
using API.DTO.Login;
using DAL.Models;
namespace API.Services.Interfaces
{
public interface IUserManager
{
UserDTO? authenticateUser(UserLoginDTO loginDTO);
UserDTO? registerUser(UserRegisterDTO registerDTO, User? user = null, ulong? permissionId = null);
UserDTO? changePassword(UserPasswordUpdateDTO passwordUpdateDTO, User changingUser);
}
}

View File

@ -0,0 +1,16 @@
using API.Authentication.Interfaces;
using API.DTO.Base;
using DAL.Contexts;
using DAL.Models;
using DAL.Models.Audits;
namespace API.Services
{
public class PermissionService : ServiceBase<PermissionService, PermissionDTO, Permission, AuditPermission, IPermissionAuthentication>
{
public PermissionService(ILogger<PermissionService> logger, SASGContext context, IPermissionAuthentication auth) : base(logger, context, auth)
{
}
}
}

View File

@ -0,0 +1,16 @@
using API.Authentication.Interfaces;
using API.DTO.Base;
using DAL.Contexts;
using DAL.Models;
using DAL.Models.Audits;
namespace API.Services
{
public class SavedEventService : ServiceBase<SavedEventService, SavedEventDTO, SavedEvent, AuditSavedEvent, ISavedEventAuthentication>
{
public SavedEventService(ILogger<SavedEventService> logger, SASGContext context, ISavedEventAuthentication auth) : base(logger, context, auth)
{
}
}
}

108
API/Services/ServiceBase.cs Normal file
View File

@ -0,0 +1,108 @@
using API.Authentication.Interfaces;
using API.DTO;
using API.Services.Interfaces;
using DAL.Contexts;
using DAL.Models;
using DAL.Models.Audits;
using System.Linq.Expressions;
namespace API.Services
{
public class ServiceBase<TLoggerCategory, TDTO, TModel, TAudit, TAuthentication> : IGenericService<TDTO, TModel, TAudit>
where TAuthentication : IGenericAuthentication<TDTO, TModel>
where TModel : Model<TModel, TAudit>
where TAudit : AuditModel<TModel>
where TDTO : IAdaptable<TModel>
{
public readonly TAuthentication _auth;
private readonly ILogger<TLoggerCategory> _logger;
public readonly SASGContext Context;
public ServiceBase(ILogger<TLoggerCategory> logger, SASGContext context, TAuthentication auth)
{
_logger = logger;
Context = context;
_auth = auth;
}
public TModel? get(ulong id, User user)
{
TModel? result = Context.Set<TModel>().Find(id);
if (result == null)
return null;
return _auth.canGet(result, user) ? result : null;
}
public IEnumerable<TModel>? get(User user, Expression<Func<TModel, bool>>? whereClause = null)
{
if (!_auth.canGetAll(user))
return null;
return whereClause != null ? Context.Set<TModel>().Where(whereClause) : Context.Set<TModel>();
}
public TModel? getNoAuthentication(ulong id)
{
return Context.Set<TModel>().Find(id);
}
public IEnumerable<TModel> getNoAuthentication(Expression<Func<TModel, bool>>? whereClause = null)
{
return whereClause != null ? Context.Set<TModel>().Where(whereClause) : Context.Set<TModel>();
}
public TModel? add(TDTO item, User user)
{
if (!_auth.canAdd(item, user))
return null;
TModel model = item.adaptToModel();
model.updater = user.id;
model.updated = DateTime.Now;
Context.Add(model);
Context.SaveChanges();
return model;
}
public TModel? update(TModel model, User user)
{
if (!_auth.canUpdate(model, user))
return null;
TModel? origModel = Context.Set<TModel>().Find(model.id);
if (origModel == null)
return null;
model.updateModel(ref origModel);
origModel.updated = DateTime.Now;
origModel.updater = user.id;
Context.SaveChanges();
return origModel;
}
public TAudit? delete(TModel model, User user)
{
if (!_auth.canDelete(model, user))
return null;
TModel? origModel = Context.Set<TModel>().Find(model.id);
if (origModel == null)
return null;
origModel.updated = DateTime.Now;
origModel.updater = user.id;
Context.SaveChanges();
Context.Remove(origModel);
Context.SaveChanges();
return origModel.adaptToAudit();
}
}
}

View File

@ -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<SignupService, SignupDTO, Signup, AuditSignup, ISignupAuthentication>
{
public SignupService(ILogger<SignupService> logger, SASGContext context, ISignupAuthentication auth) : base(logger, context, auth)
{
}
}
}

133
API/Services/UserManager.cs Normal file
View File

@ -0,0 +1,133 @@
using API.DTO.Base;
using API.DTO.Base.Update;
using API.DTO.Login;
using API.Hashing.Interfaces;
using API.Services.Interfaces;
using DAL.Models;
namespace API.Services
{
public class UserManager : IUserManager
{
private readonly IHashingFactory _hashingFactory;
private readonly ILogger<UserManager> _logger;
private readonly HashingType _preferredHashingType;
private readonly UserService _userService;
public UserManager(UserService userService, IHashingFactory hashingFactory, ILogger<UserManager> logger, HashingType preferredHashingType)
{
_userService = userService;
_hashingFactory = hashingFactory;
_logger = logger;
_preferredHashingType = preferredHashingType;
}
public UserDTO? authenticateUser(UserLoginDTO loginDTO)
{
User? user = _userService.getNoAuthentication(x => x.phoneNumber.Equals(loginDTO.phoneNumber)).FirstOrDefault();
if (user == null)
return null;
IHashingAlgorithm? hashingAlgorithm = _hashingFactory.getAlgorithm(user.hashingType);
if (hashingAlgorithm == null)
{
_logger.Log(LogLevel.Warning, "User id '{id}' has a hashing type '{hashingType}' that isn't recognized by factory '{factory}'. Not logging in.", user.id, user.hashingType, nameof(_hashingFactory));
return null;
}
string hashedPassword = hashingAlgorithm.hash(loginDTO.password, user.salt);
if (!hashedPassword.Equals(user.password))
{
_logger.Log(LogLevel.Information, "Failed login attempt for user id '{id}.", user.id);
return null;
}
if (user.hashingType != _preferredHashingType)
{
// todo The user is logged in at this point. Their hashing type needs to be updated, we need to rehash & salt the password and save it now.
}
UserDTO dto = new UserDTO();
dto.adaptFromModel(user);
return dto;
}
public UserDTO? registerUser(UserRegisterDTO registerDTO, User? user = null, ulong? permissionId = null)
{
if (_userService.getNoAuthentication(x =>
x.phoneNumber.Equals(registerDTO.phoneNumber) ||
x.firstName.Equals(registerDTO.firstName) && x.lastName.Equals(registerDTO.lastName))
.Any())
{
return null;
}
IHashingAlgorithm? hashingAlgorithm = _hashingFactory.getAlgorithm(_preferredHashingType);
if (hashingAlgorithm == null)
{
_logger.Log(LogLevel.Error, "Preferred hashing type '{hashingType}' that isn't recognized by factory '{factory}'.", _preferredHashingType, nameof(_hashingFactory));
return null;
}
byte[] salt;
string hashedPassword = hashingAlgorithm.hash(registerDTO.password, out salt);
User? createdUser = _userService.add(registerDTO, hashedPassword, salt, user, permissionId);
if (createdUser == null)
return null;
UserDTO dto = new UserDTO();
dto.adaptFromModel(createdUser);
return dto;
}
public UserDTO? changePassword(UserPasswordUpdateDTO userPasswordUpdateDTO, User changingUser)
{
User? destUser = _userService.getNoAuthentication(x => x.phoneNumber.Equals(userPasswordUpdateDTO.phoneNumber)).FirstOrDefault();
if (destUser == null)
return null;
IHashingAlgorithm? hashingAlgorithm = _hashingFactory.getAlgorithm(_preferredHashingType);
if (hashingAlgorithm == null){
_logger.Log(LogLevel.Error, "Preferred hashing type '{hashingType}' that isn't recognized by factory '{factory}'.", _preferredHashingType, nameof(_hashingFactory));
return null;
}
byte[] newSalt;
string hashedNewPassword = hashingAlgorithm.hash(userPasswordUpdateDTO.newPassword, out newSalt);
bool oldPasswordMatchNew = false;
if (userPasswordUpdateDTO.oldPassword != null)
{
IHashingAlgorithm? userHashingAlgorithm = _hashingFactory.getAlgorithm(destUser.hashingType);
if (userHashingAlgorithm == null)
{
_logger.Log(LogLevel.Warning, "User id '{id}' has a hashing type '{hashingType}' that isn't recognized by factory '{factory}'. Not logging in.", destUser.id, destUser.hashingType, nameof(_hashingFactory));
return null;
}
string hashedOldPassword = userHashingAlgorithm.hash(userPasswordUpdateDTO.oldPassword, destUser.salt);
if (hashedOldPassword.Equals(destUser.password))
{
oldPasswordMatchNew = true;
}
}
User? updatedUser = _userService.changePassword(destUser, changingUser, hashedNewPassword, newSalt, oldPasswordMatchNew);
if (updatedUser == null)
return null;
UserDTO dto = new UserDTO();
dto.adaptFromModel(updatedUser);
return dto;
}
}
}

View File

@ -0,0 +1,72 @@
using API.Authentication.Interfaces;
using API.DTO.Base;
using API.DTO.Base.Update;
using API.DTO.Login;
using DAL.Contexts;
using DAL.Models;
using DAL.Models.Audits;
namespace API.Services
{
public class UserService : ServiceBase<UserService, UserDTO, User, AuditUser, IUserAuthentication>
{
private readonly ulong _defaultUserPermission;
private readonly PermissionService _permissionService;
public UserService(ILogger<UserService> logger, SASGContext context, IUserAuthentication auth, PermissionService permissionService, ulong defaultUserPermission) : base(logger, context, auth)
{
_permissionService = permissionService;
_defaultUserPermission = defaultUserPermission;
}
public User? add(UserRegisterDTO registerDTO, string hashedPassword, byte[] salt, User? user = null, ulong? permissionId = null)
{
Permission? defaultPermission = _permissionService.getNoAuthentication(_defaultUserPermission);
if (defaultPermission == null)
throw new InvalidOperationException("defaultUserPermission doesn't exist.");
User model = new User
{
firstName = registerDTO.firstName,
lastName = registerDTO.lastName,
phoneNumber = registerDTO.phoneNumber,
password = hashedPassword,
salt = salt,
permissionId = permissionId ?? defaultPermission.id,
updated = DateTime.Now
};
if (permissionId != null && user != null)
{
model.permissionId = permissionId.Value;
model.updater = user.id;
UserDTO userDTO = new UserDTO();
userDTO.adaptFromModel(user);
if (!_auth.canAdd(userDTO, user))
return null;
Context.Add(model);
Context.SaveChanges();
return model;
}
Context.Add(model);
Context.SaveChanges();
return model;
}
public User? changePassword(User destUser, User changingUser, string hashedNewPassword, byte[] newSalt, bool oldPasswordMatchNew)
{
if (!_auth.canChangePassword(destUser, changingUser, oldPasswordMatchNew))
return null;
destUser.password = hashedNewPassword;
destUser.salt = newSalt;
return update(destUser, changingUser);
}
}
}

115
DAL/Contexts/SASGContext.cs Normal file
View File

@ -0,0 +1,115 @@
using DAL.Converters;
using DAL.Models;
using DAL.Models.Audits;
using DAL.Values;
using Microsoft.EntityFrameworkCore;
namespace DAL.Contexts
{
public class SASGContext : DbContext
{
public SASGContext()
{
}
public SASGContext(DbContextOptions<SASGContext> options) : base(options)
{
}
public virtual DbSet<Color> colors { get; set; }
public virtual DbSet<Event> events { get; set; }
public virtual DbSet<Grant> grants { get; set; }
public virtual DbSet<Image> images { get; set; }
public virtual DbSet<Permission> permissions { get; set; }
public virtual DbSet<SavedEvent> savedEvents { get; set; }
public virtual DbSet<Signup> signups { get; set; }
public virtual DbSet<User> users { get; set; }
public virtual DbSet<AuditColor> auditColors { get; set; }
public virtual DbSet<AuditEvent> auditEvents { get; set; }
public virtual DbSet<AuditGrant> auditGrants { get; set; }
public virtual DbSet<AuditImage> auditImages { get; set; }
public virtual DbSet<AuditPermission> auditPermissions { get; set; }
public virtual DbSet<AuditSavedEvent> auditSavedEvents { get; set; }
public virtual DbSet<AuditUser> auditUsers { get; set; }
public virtual DbSet<AuditSignup> auditSignups { get; set; }
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.Properties<PhoneNumber>().HaveConversion<PhoneNumberConverter>();
}
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Color>(entity =>
{
entity.HasOne(e => e.updaterRelation).WithMany()
.HasForeignKey(e => e.updater).HasConstraintName("colors_users_id_fk");
});
builder.Entity<Event>(entity =>
{
entity.HasOne(e => e.bgColorRelation).WithMany()
.HasForeignKey(e => e.bgColorId).HasConstraintName("events_colors_id_fk");
entity.HasOne(e => e.fgColorRelation).WithMany()
.HasForeignKey(e => e.fgColorId).HasConstraintName("events_colors_id_fk_2");
entity.HasOne(e => e.imageRelation).WithMany()
.HasForeignKey(e => e.imageId).HasConstraintName("events_images_id_fk");
entity.HasOne(e => e.savedEventRelation).WithMany()
.HasForeignKey(e => e.savedEventId).HasConstraintName("events_savedEvent_id_fk");
entity.HasOne(e => e.updaterRelation).WithMany()
.HasForeignKey(e => e.updater).HasConstraintName("events_users_id_fk");
});
builder.Entity<Grant>(entity =>
{
entity.HasOne(e => e.permissionRelation).WithMany()
.HasForeignKey(e => e.permissionId).HasConstraintName("grants_permissions_id_fk");
entity.HasOne(e => e.updaterRelation).WithMany()
.HasForeignKey(e => e.updater).HasConstraintName("grants_users_id_fk");
});
builder.Entity<Image>(entity =>
{
entity.HasOne(e => e.updaterRelation).WithMany()
.HasForeignKey(e => e.updater).HasConstraintName("grants_users_id_fk");
});
builder.Entity<Permission>(entity =>
{
entity.HasOne(e => e.updaterRelation).WithMany()
.HasForeignKey(e => e.updater).HasConstraintName("grants_users_id_fk");
});
builder.Entity<SavedEvent>(entity =>
{
entity.HasOne(e => e.bgColorRelation).WithMany()
.HasForeignKey(e => e.bgColorId).HasConstraintName("events_colors_id_fk");
entity.HasOne(e => e.fgColorRelation).WithMany()
.HasForeignKey(e => e.fgColorId).HasConstraintName("events_colors_id_fk_2");
entity.HasOne(e => e.imageRelation).WithMany()
.HasForeignKey(e => e.imageId).HasConstraintName("events_images_id_fk");
entity.HasOne(e => e.updaterRelation).WithMany()
.HasForeignKey(e => e.updater).HasConstraintName("events_users_id_fk");
});
builder.Entity<User>(entity =>
{
entity.HasOne(e => e.updaterRelation).WithMany()
.HasForeignKey(e => e.updater).HasConstraintName("events_users_id_fk");
entity.Property(e => e.hashingType).HasConversion<string>();
});
builder.Entity<Signup>(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");
});
}
}
}

View File

@ -0,0 +1,19 @@
using DAL.Values;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace DAL.Converters
{
public class PhoneNumberConverter : ValueConverter<PhoneNumber, string>
{
public PhoneNumberConverter() : base(
v => v.value,
v => new PhoneNumber
{
value = v
}
)
{
}
}
}

19
DAL/DAL.csproj Normal file
View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.7"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.7"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MySql.EntityFrameworkCore" Version="8.0.5"/>
</ItemGroup>
</Project>

View File

@ -0,0 +1,38 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DAL.Models.Audits
{
[Index("id", Name = "audit_colors_colors_id_fk")]
[Table("audit_colors")]
public class AuditColor : AuditModel<Color>
{
[Column("red")]
public byte red { get; set; }
[Column("blue")]
public byte blue { get; set; }
[Column("green")]
public byte green { get; set; }
[Column("name")]
[MaxLength(64)]
public string name { get; set; } = null!;
public override Color adaptToModel()
{
return new Color
{
id = originalId,
red = red,
blue = blue,
green = green,
name = name,
updated = updated,
updater = updater
};
}
}
}

View File

@ -0,0 +1,49 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DAL.Models.Audits
{
[Table("audit_event")]
[Index("id", Name = "audit_events_events_id_fk")]
public class AuditEvent : AuditModel<Event>
{
[Column("savedEventId")]
public ulong savedEventId { get; set; }
[Column("name")]
[MaxLength(64)]
public string? name { get; set; }
[Column("bgColorId")]
public ulong? bgColorId { get; set; }
[Column("fgColorId")]
public ulong? fgColorId { get; set; }
[Column("imageId")]
public ulong? imageId { get; set; }
[Column("when")]
public DateTime when { get; set; }
[Column("hidden")]
public bool hidden { get; set; }
public override Event adaptToModel()
{
return new Event
{
id = originalId,
savedEventId = savedEventId,
name = name,
bgColorId = bgColorId,
fgColorId = fgColorId,
imageId = imageId,
hidden = hidden,
updated = updated,
updater = updater
};
}
}
}

View File

@ -0,0 +1,30 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DAL.Models.Audits
{
[Table("audit_grants")]
[Index("id", Name = "audit_grants_grants_id_fk")]
public class AuditGrant : AuditModel<Grant>
{
[Column("name")]
[MaxLength(128)]
public string name { get; set; } = null!;
[Column("permissionId")]
public ulong permissionId { get; set; }
public override Grant adaptToModel()
{
return new Grant
{
id = originalId,
name = name,
permissionId = permissionId,
updated = updated,
updater = updater
};
}
}
}

View File

@ -0,0 +1,31 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DAL.Models.Audits
{
[Table("audit_images")]
[Index("id", Name = "audit_images_images_id_fk")]
public class AuditImage : AuditModel<Image>
{
[Column("name")]
[MaxLength(64)]
public string name { get; set; } = null!;
[Column("filename")]
[MaxLength(128)]
public string filename { get; set; } = null!;
public override Image adaptToModel()
{
return new Image
{
id = originalId,
name = name,
filename = filename,
updated = updated,
updater = updater
};
}
}
}

View File

@ -0,0 +1,24 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DAL.Models.Audits
{
public abstract class AuditModel<TModel>
{
[Key]
[Column("id")]
public ulong id { get; set; }
[Column("originalId")]
public ulong originalId { get; set; }
[Column("updated")]
[DataType("datetime")]
public DateTime updated { get; set; }
[Column("updater")]
public ulong updater { get; set; }
public abstract TModel adaptToModel();
}
}

View File

@ -0,0 +1,26 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DAL.Models.Audits
{
[Table("audit_permissions")]
[Index("id", Name = "audit_permissions_permissions_id_fk")]
public class AuditPermission : AuditModel<Permission>
{
[Column("name")]
[MaxLength(64)]
public string name { get; set; } = null!;
public override Permission adaptToModel()
{
return new Permission
{
id = originalId,
name = name,
updated = updated,
updater = updater
};
}
}
}

View File

@ -0,0 +1,38 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DAL.Models.Audits
{
[Table("audit_savedEvents")]
[Index("id", Name = "audit_savedEvents_savedEvents_id_fk")]
public class AuditSavedEvent : AuditModel<SavedEvent>
{
[Column("name")]
[MaxLength(64)]
public string name { get; set; } = null!;
[Column("bgColorId")]
public ulong bgColorId { get; set; }
[Column("fgColorId")]
public ulong fgColorId { get; set; }
[Column("imageId")]
public ulong? imageId { get; set; }
public override SavedEvent adaptToModel()
{
return new SavedEvent
{
id = originalId,
name = name,
bgColorId = bgColorId,
fgColorId = fgColorId,
imageId = imageId,
updated = updated,
updater = updater
};
}
}
}

View File

@ -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<Signup>
{
[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
};
}
}
}

View File

@ -0,0 +1,48 @@
using DAL.Values;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DAL.Models.Audits
{
[Table("audit_users")]
[Index("id", Name = "audit_users_users_id_fk")]
public class AuditUser : AuditModel<User>
{
[Column("firstName")]
[MaxLength(64)]
public string firstName { get; set; } = null!;
[Column("lastName")]
[MaxLength(64)]
public string lastName { get; set; } = null!;
[Column("phoneNumber")]
public PhoneNumber phoneNumber { get; set; } = null!;
[Column("hashingType")]
[MaxLength(64)]
public HashingType hashingType { get; set; }
[Column("permissionId")]
public ulong permissionId { get; set; }
[Column("updater")]
public new ulong? updater { get; set; }
public override User adaptToModel()
{
return new User
{
id = originalId,
firstName = firstName,
lastName = lastName,
phoneNumber = phoneNumber,
hashingType = hashingType,
permissionId = permissionId,
updated = updated,
updater = updater
};
}
}
}

46
DAL/Models/Color.cs Normal file
View File

@ -0,0 +1,46 @@
using DAL.Models.Audits;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DAL.Models
{
[Table("colors")]
[Index("updater", Name = "colors_users_id_fk")]
public class Color : Model<Color, AuditColor>
{
[Column("red")]
public byte red { get; set; }
[Column("blue")]
public byte blue { get; set; }
[Column("green")]
public byte green { get; set; }
[Column("name")]
[MaxLength(64)]
public string name { get; set; } = null!;
public override AuditColor adaptToAudit()
{
return new AuditColor
{
id = id,
red = red,
blue = blue,
green = green,
name = name,
updated = updated,
updater = updater
};
}
public override void updateModel(ref Color dest)
{
dest.red = red;
dest.blue = blue;
dest.green = green;
dest.name = name;
}
}
}

69
DAL/Models/Event.cs Normal file
View File

@ -0,0 +1,69 @@
using DAL.Models.Audits;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DAL.Models
{
[Table("events")]
[Index("updater", Name = "event_users_id_fk")]
[Index("bgColorId", Name = "events_colors_id_fk")]
[Index("fgColorId", Name = "events_colors_id_fk_2")]
[Index("imageId", Name = "events_images_id_fk")]
[Index("savedEventId", Name = "events_savedEvents_id_fk")]
[Index("when", Name = "events_when_index")]
public class Event : Model<Event, AuditEvent>
{
[Column("savedEventId")]
public ulong savedEventId { get; set; }
[Column("name")]
[MaxLength(64)]
public string? name { get; set; }
[Column("bgColorId")]
public ulong? bgColorId { get; set; }
[Column("fgColorId")]
public ulong? fgColorId { get; set; }
[Column("imageId")]
public ulong? imageId { get; set; }
[Column("when")]
public DateTime when { get; set; }
[Column("hidden")]
public bool hidden { get; set; }
public SavedEvent savedEventRelation { get; set; } = null!;
public Color? bgColorRelation { get; set; }
public Color? fgColorRelation { get; set; }
public Image? imageRelation { get; set; }
public override AuditEvent adaptToAudit()
{
return new AuditEvent
{
id = id,
savedEventId = savedEventId,
name = name,
bgColorId = bgColorId,
fgColorId = fgColorId,
imageId = imageId,
hidden = hidden,
updated = updated,
updater = updater
};
}
public override void updateModel(ref Event dest)
{
dest.savedEventId = savedEventId;
dest.name = name;
dest.bgColorId = bgColorId;
dest.fgColorId = fgColorId;
dest.imageId = imageId;
dest.hidden = hidden;
}
}
}

40
DAL/Models/Grant.cs Normal file
View File

@ -0,0 +1,40 @@
using DAL.Models.Audits;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DAL.Models
{
[Table("grants")]
[Index("updater", Name = "grants_users_id_fk")]
[Index("permissionId", Name = "grants_permissions_id_fk")]
[Index("updater", Name = "grants_users_id_fk")]
public class Grant : Model<Grant, AuditGrant>
{
[Column("name")]
[MaxLength(128)]
public string name { get; set; } = null!;
[Column("permissionId")]
public ulong permissionId { get; set; }
public virtual Permission permissionRelation { get; set; } = null!;
public override AuditGrant adaptToAudit()
{
return new AuditGrant
{
id = id,
name = name,
permissionId = permissionId,
updated = updated,
updater = updater
};
}
public override void updateModel(ref Grant dest)
{
dest.name = name;
dest.permissionId = permissionId;
}
}
}

Some files were not shown because too many files have changed in this diff Show More