diff options
Diffstat (limited to 'server/src/Data')
26 files changed, 679 insertions, 0 deletions
diff --git a/server/src/Data/AppDbContext.cs b/server/src/Data/AppDbContext.cs new file mode 100644 index 0000000..3f949dd --- /dev/null +++ b/server/src/Data/AppDbContext.cs @@ -0,0 +1,58 @@ +namespace IOL.GreatOffice.Api.Data; + +public class AppDbContext : DbContext +{ + public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } + public DbSet<User> Users { get; set; } + public DbSet<ForgotPasswordRequest> ForgotPasswordRequests { get; set; } + public DbSet<TimeLabel> TimeLabels { get; set; } + public DbSet<TimeEntry> TimeEntries { get; set; } + public DbSet<TimeCategory> TimeCategories { get; set; } + public DbSet<GithubUserMapping> GithubUserMappings { get; set; } + public DbSet<ApiAccessToken> AccessTokens { get; set; } + public DbSet<Tenant> Tenants { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) { + modelBuilder.Entity<User>(e => { + e.ToTable("users"); + }); + + modelBuilder.Entity<ForgotPasswordRequest>(e => { + e.HasOne(c => c.User); + e.ToTable("forgot_password_requests"); + }); + + modelBuilder.Entity<TimeCategory>(e => { + e.HasOne(c => c.User); + e.ToTable("time_categories"); + }); + + modelBuilder.Entity<TimeLabel>(e => { + e.HasOne(c => c.User); + e.ToTable("time_labels"); + }); + + modelBuilder.Entity<TimeEntry>(e => { + e.HasOne(c => c.User); + e.HasOne(c => c.Category); + e.HasMany(c => c.Labels); + e.ToTable("time_entries"); + }); + + modelBuilder.Entity<GithubUserMapping>(e => { + e.HasOne(c => c.User); + e.HasKey(c => c.GithubId); + e.ToTable("github_user_mappings"); + }); + + modelBuilder.Entity<ApiAccessToken>(e => { + e.ToTable("api_access_tokens"); + }); + + modelBuilder.Entity<Tenant>(e => { + e.ToTable("tenants"); + }); + + base.OnModelCreating(modelBuilder); + } +} diff --git a/server/src/Data/Database/ApiAccessToken.cs b/server/src/Data/Database/ApiAccessToken.cs new file mode 100644 index 0000000..3eff5f3 --- /dev/null +++ b/server/src/Data/Database/ApiAccessToken.cs @@ -0,0 +1,31 @@ +namespace IOL.GreatOffice.Api.Data.Database; + +public class ApiAccessToken : Base +{ + public User User { get; set; } + public DateTime ExpiryDate { get; set; } + public bool AllowRead { get; set; } + public bool AllowCreate { get; set; } + public bool AllowUpdate { get; set; } + public bool AllowDelete { get; set; } + public bool HasExpired => ExpiryDate < DateTime.UtcNow; + public ApiAccessTokenDto AsDto => new(this); + + public class ApiAccessTokenDto + { + public ApiAccessTokenDto(ApiAccessToken source) { + ExpiryDate = source.ExpiryDate; + AllowRead = source.AllowRead; + AllowCreate = source.AllowCreate; + AllowUpdate = source.AllowUpdate; + AllowDelete = source.AllowDelete; + } + + public DateTime ExpiryDate { get; set; } + public bool AllowRead { get; set; } + public bool AllowCreate { get; set; } + public bool AllowUpdate { get; set; } + public bool AllowDelete { get; set; } + public bool HasExpired => ExpiryDate < DateTime.UtcNow; + } +} diff --git a/server/src/Data/Database/Base.cs b/server/src/Data/Database/Base.cs new file mode 100644 index 0000000..2439668 --- /dev/null +++ b/server/src/Data/Database/Base.cs @@ -0,0 +1,14 @@ +namespace IOL.GreatOffice.Api.Data.Database; + +public class Base +{ + protected Base() { + Id = Guid.NewGuid(); + CreatedAt = DateTime.UtcNow; + } + + public Guid Id { get; init; } + public DateTime CreatedAt { get; init; } + public DateTime? ModifiedAt { get; private set; } + public void Modified() => ModifiedAt = DateTime.UtcNow; +} diff --git a/server/src/Data/Database/BaseWithOwner.cs b/server/src/Data/Database/BaseWithOwner.cs new file mode 100644 index 0000000..eb4438d --- /dev/null +++ b/server/src/Data/Database/BaseWithOwner.cs @@ -0,0 +1,24 @@ +namespace IOL.GreatOffice.Api.Data.Database; + +/// <summary> +/// Base class for all entities. +/// </summary> +public class BaseWithOwner : Base +{ + protected BaseWithOwner() { } + + protected BaseWithOwner(Guid userId) { + UserId = userId; + } + + public Guid UserId { get; init; } + public User User { get; init; } + public Guid TenantId { get; set; } + public Tenant Tenant { get; init; } + public Guid ModifiedById { get; init; } + public User ModifiedBy { get; set; } + public Guid CreatedById { get; init; } + public User CreatedBy { get; set; } + public Guid DeletedById { get; init; } + public User DeletedBy { get; set; } +} diff --git a/server/src/Data/Database/ForgotPasswordRequest.cs b/server/src/Data/Database/ForgotPasswordRequest.cs new file mode 100644 index 0000000..164f09d --- /dev/null +++ b/server/src/Data/Database/ForgotPasswordRequest.cs @@ -0,0 +1,23 @@ +namespace IOL.GreatOffice.Api.Data.Database; + +public class ForgotPasswordRequest +{ + public ForgotPasswordRequest() { } + + public ForgotPasswordRequest(User user) { + CreatedAt = DateTime.UtcNow; + Id = Guid.NewGuid(); + User = user; + } + + public Guid Id { get; set; } + public Guid UserId { get; set; } + public User User { get; set; } + public DateTime CreatedAt { get; set; } + + [NotMapped] + public DateTime ExpirationDate => CreatedAt.AddMinutes(15); + + [NotMapped] + public bool IsExpired => DateTime.Compare(ExpirationDate, DateTime.UtcNow) < 0; +} diff --git a/server/src/Data/Database/GithubUserMapping.cs b/server/src/Data/Database/GithubUserMapping.cs new file mode 100644 index 0000000..dbdb2b7 --- /dev/null +++ b/server/src/Data/Database/GithubUserMapping.cs @@ -0,0 +1,9 @@ +namespace IOL.GreatOffice.Api.Data.Database; + +public class GithubUserMapping +{ + public User User { get; set; } + public string GithubId { get; set; } + public string Email { get; set; } + public string RefreshToken { get; set; } +} diff --git a/server/src/Data/Database/Tenant.cs b/server/src/Data/Database/Tenant.cs new file mode 100644 index 0000000..3028d13 --- /dev/null +++ b/server/src/Data/Database/Tenant.cs @@ -0,0 +1,10 @@ +namespace IOL.GreatOffice.Api.Data.Database; + +public class Tenant : BaseWithOwner +{ + public string Name { get; set; } + public string Description { get; set; } + public string ContactEmail { get; set; } + public Guid MasterUserId { get; set; } + public string MasterUserPassword { get; set; } +} diff --git a/server/src/Data/Database/TimeCategory.cs b/server/src/Data/Database/TimeCategory.cs new file mode 100644 index 0000000..69c6957 --- /dev/null +++ b/server/src/Data/Database/TimeCategory.cs @@ -0,0 +1,31 @@ +namespace IOL.GreatOffice.Api.Data.Database; + +public class TimeCategory : BaseWithOwner +{ + public TimeCategory() { } + public TimeCategory(Guid userId) : base(userId) { } + public string Name { get; set; } + public string Color { get; set; } + public TimeCategoryDto AsDto => new(this); + + public class TimeCategoryDto + { + public TimeCategoryDto() { } + + public TimeCategoryDto(TimeCategory sourceEntry = default) { + if (sourceEntry == default) { + return; + } + + Id = sourceEntry.Id; + ModifiedAt = sourceEntry.ModifiedAt; + Name = sourceEntry.Name; + Color = sourceEntry.Color; + } + + public Guid Id { get; set; } + public DateTime? ModifiedAt { get; set; } + public string Name { get; set; } + public string Color { get; set; } + } +} diff --git a/server/src/Data/Database/TimeEntry.cs b/server/src/Data/Database/TimeEntry.cs new file mode 100644 index 0000000..46c62e1 --- /dev/null +++ b/server/src/Data/Database/TimeEntry.cs @@ -0,0 +1,45 @@ +namespace IOL.GreatOffice.Api.Data.Database; + +public class TimeEntry : BaseWithOwner +{ + public TimeEntry() { } + public TimeEntry(Guid userId) : base(userId) { } + public DateTime Start { get; set; } + public DateTime Stop { get; set; } + public string Description { get; set; } + public ICollection<TimeLabel> Labels { get; set; } + public TimeCategory Category { get; set; } + public TimeEntryDto AsDto => new(this); + + public class TimeEntryDto + { + public TimeEntryDto() { } + + public TimeEntryDto(TimeEntry sourceEntry = default) { + if (sourceEntry == default) { + return; + } + + Id = sourceEntry.Id; + ModifiedAt = sourceEntry.ModifiedAt; + Stop = sourceEntry.Stop; + Start = sourceEntry.Start; + Description = sourceEntry.Description; + if (sourceEntry.Labels != default) { + Labels = sourceEntry.Labels + .Select(t => t.AsDto) + .ToList(); + } + + Category = sourceEntry.Category.AsDto; + } + + public Guid? Id { get; set; } + public DateTime? ModifiedAt { get; set; } + public DateTime Start { get; set; } + public DateTime Stop { get; set; } + public string Description { get; set; } + public List<TimeLabel.TimeLabelDto> Labels { get; set; } + public TimeCategory.TimeCategoryDto Category { get; set; } + } +} diff --git a/server/src/Data/Database/TimeLabel.cs b/server/src/Data/Database/TimeLabel.cs new file mode 100644 index 0000000..55e20b0 --- /dev/null +++ b/server/src/Data/Database/TimeLabel.cs @@ -0,0 +1,31 @@ +namespace IOL.GreatOffice.Api.Data.Database; + +public class TimeLabel : BaseWithOwner +{ + public TimeLabel() { } + public TimeLabel(Guid userId) : base(userId) { } + public string Name { get; set; } + public string Color { get; set; } + + [NotMapped] + public TimeLabelDto AsDto => new(this); + + public class TimeLabelDto + { + public TimeLabelDto() { } + + public TimeLabelDto(TimeLabel sourceEntry) { + Id = sourceEntry.Id; + CreatedAt = sourceEntry.CreatedAt; + ModifiedAt = sourceEntry.ModifiedAt; + Name = sourceEntry.Name; + Color = sourceEntry.Color; + } + + public Guid Id { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime? ModifiedAt { get; set; } + public string Name { get; set; } + public string Color { get; set; } + } +} diff --git a/server/src/Data/Database/User.cs b/server/src/Data/Database/User.cs new file mode 100644 index 0000000..c5063f6 --- /dev/null +++ b/server/src/Data/Database/User.cs @@ -0,0 +1,29 @@ +namespace IOL.GreatOffice.Api.Data.Database; + +public class User : Base +{ + public User() { } + + public User(string username) { + Username = username; + } + + public string Username { get; set; } + public string Password { get; set; } + + + public void HashAndSetPassword(string password) { + Password = PasswordHelper.HashPassword(password); + } + + public bool VerifyPassword(string password) { + return PasswordHelper.Verify(password, Password); + } + + public IEnumerable<Claim> DefaultClaims() { + return new Claim[] { + new(AppClaims.USER_ID, Id.ToString()), + new(AppClaims.NAME, Username), + }; + } +} diff --git a/server/src/Data/Dtos/TimeQueryDto.cs b/server/src/Data/Dtos/TimeQueryDto.cs new file mode 100644 index 0000000..f734cb1 --- /dev/null +++ b/server/src/Data/Dtos/TimeQueryDto.cs @@ -0,0 +1,34 @@ + +namespace IOL.GreatOffice.Api.Data.Dtos; + +public class TimeQueryDto +{ + public TimeQueryDto() { + Results = new List<TimeEntry.TimeEntryDto>(); + } + + /// <summary> + /// List of entries. + /// </summary> + public List<TimeEntry.TimeEntryDto> Results { get; set; } + + /// <summary> + /// Curren page. + /// </summary> + public int Page { get; set; } + + /// <summary> + /// Maximum count of entries in a page. + /// </summary> + public int PageSize { get; set; } + + /// <summary> + /// Total count of entries. + /// </summary> + public int TotalSize { get; set; } + + /// <summary> + /// Total count of pages. + /// </summary> + public int TotalPageCount { get; set; } +} diff --git a/server/src/Data/Dtos/UserArchiveDto.cs b/server/src/Data/Dtos/UserArchiveDto.cs new file mode 100644 index 0000000..63b1470 --- /dev/null +++ b/server/src/Data/Dtos/UserArchiveDto.cs @@ -0,0 +1,131 @@ + +namespace IOL.GreatOffice.Api.Data.Dtos; + +/// <summary> +/// Represents a user archive as it is provided to users. +/// </summary> +public class UserArchiveDto +{ + /// <inheritdoc cref="UserArchiveDto"/> + public UserArchiveDto(User user) { + Meta = new MetaDto { + GeneratedAt = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ") + }; + User = new UserDto(user); + Entries = new List<EntryDto>(); + } + + /// <summary> + /// Metadata for the user archive. + /// </summary> + public MetaDto Meta { get; } + + /// <summary> + /// Relevant user data for the archive. + /// </summary> + public UserDto User { get; } + + /// <summary> + /// List of entries that the user has created. + /// </summary> + public List<EntryDto> Entries { get; } + + public void CountEntries() { + Meta.EntryCount = Entries.Count; + } + + /// <summary> + /// Represents a time entry in the data archive. + /// </summary> + public class EntryDto + { + public string CreatedAt { get; init; } + + [JsonIgnore] + public DateTime StartDateTime { get; init; } + + /// <summary> + /// ISO 8601 string of the UTC date the time entry started. + /// </summary> + public string Start => StartDateTime.ToString("yyyy-MM-ddTHH:mm:ssZ"); + + [JsonIgnore] + public DateTime StopDateTime { get; init; } + + /// <summary> + /// ISO 8601 string of the UTC date the time entry stopped. + /// </summary> + public string Stop => StopDateTime.ToString("yyyy-MM-ddTHH:mm:ssZ"); + + /// <summary> + /// Total amount of minutes elapsed from start to stop on this time entry. + /// </summary> + public double Minutes => StopDateTime.Subtract(StartDateTime).TotalMinutes; + + public string Description { get; init; } + + /// <summary> + /// Archive spesific category for this time entry. + /// </summary> + public CategoryDto Category { get; init; } + + /// <summary> + /// Archive spesific list of labels for this time entry. + /// </summary> + public List<LabelDto> Labels { get; init; } + } + + /// <summary> + /// Time entry category as it is written to the user archive. + /// </summary> + public class CategoryDto + { + public string Name { get; init; } + public string Color { get; init; } + } + + /// <summary> + /// Time entry label as it is written to the user archive. + /// </summary> + public class LabelDto + { + public string Name { get; init; } + public string Color { get; init; } + } + + + /// <summary> + /// Represents the user who this archive's data is based on. + /// </summary> + public class UserDto + { + /// <inheritdoc cref="UserDto"/> + public UserDto(User user) { + Username = user.Username; + CreatedAt = user.CreatedAt; + } + + /// <summary> + /// UTC date this user was created. + /// </summary> + public DateTime CreatedAt { get; } + + public string Username { get; } + } + + /// <summary> + /// Represents the meta object which contains metdata for this archive. + /// </summary> + public class MetaDto + { + /// <summary> + /// ISO 8601 UTC date string for when this archive was created. + /// </summary> + public string GeneratedAt { get; init; } + + /// <summary> + /// Amount of entries in the archive. + /// </summary> + public int EntryCount { get; set; } + } +} diff --git a/server/src/Data/Enums/TimeEntryQueryDuration.cs b/server/src/Data/Enums/TimeEntryQueryDuration.cs new file mode 100644 index 0000000..af70ca6 --- /dev/null +++ b/server/src/Data/Enums/TimeEntryQueryDuration.cs @@ -0,0 +1,37 @@ +namespace IOL.GreatOffice.Api.Data.Enums; + +/// <summary> +/// Specify a duration filter for time entry queries. +/// </summary> +public enum TimeEntryQueryDuration +{ + /// <summary> + /// Only query entries created today. + /// </summary> + TODAY = 0, + + /// <summary> + /// Only query entries created this week. + /// </summary> + THIS_WEEK = 1, + + /// <summary> + /// Only query entries created this month. + /// </summary> + THIS_MONTH = 2, + + /// <summary> + /// Only query entries created this year. + /// </summary> + THIS_YEAR = 3, + + /// <summary> + /// Only query entries created at a spesific date. + /// </summary> + SPECIFIC_DATE = 4, + + /// <summary> + /// Only query entries created between two dates. + /// </summary> + DATE_RANGE = 5, +} diff --git a/server/src/Data/Exceptions/ForgotPasswordRequestNotFoundException.cs b/server/src/Data/Exceptions/ForgotPasswordRequestNotFoundException.cs new file mode 100644 index 0000000..02474b4 --- /dev/null +++ b/server/src/Data/Exceptions/ForgotPasswordRequestNotFoundException.cs @@ -0,0 +1,21 @@ +namespace IOL.GreatOffice.Api.Data.Exceptions; + +[Serializable] +public class ForgotPasswordRequestNotFoundException : Exception +{ + // + // For guidelines regarding the creation of new exception types, see + // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp + // and + // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp + // + + public ForgotPasswordRequestNotFoundException() { } + public ForgotPasswordRequestNotFoundException(string message) : base(message) { } + public ForgotPasswordRequestNotFoundException(string message, Exception inner) : base(message, inner) { } + + protected ForgotPasswordRequestNotFoundException( + SerializationInfo info, + StreamingContext context + ) : base(info, context) { } +} diff --git a/server/src/Data/Exceptions/UserNotFoundException.cs b/server/src/Data/Exceptions/UserNotFoundException.cs new file mode 100644 index 0000000..06b57a9 --- /dev/null +++ b/server/src/Data/Exceptions/UserNotFoundException.cs @@ -0,0 +1,19 @@ +namespace IOL.GreatOffice.Api.Data.Exceptions; + +[Serializable] +public class UserNotFoundException : Exception +{ + // For guidelines regarding the creation of new exception types, see + // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp + // and + // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp + + public UserNotFoundException() { } + public UserNotFoundException(string message) : base(message) { } + public UserNotFoundException(string message, Exception inner) : base(message, inner) { } + + protected UserNotFoundException( + SerializationInfo info, + StreamingContext context + ) : base(info, context) { } +} diff --git a/server/src/Data/Models/ApiSpecDocument.cs b/server/src/Data/Models/ApiSpecDocument.cs new file mode 100644 index 0000000..1c7d936 --- /dev/null +++ b/server/src/Data/Models/ApiSpecDocument.cs @@ -0,0 +1,9 @@ +namespace IOL.GreatOffice.Api.Data.Models; + +public class ApiSpecDocument +{ + public string VersionName { get; set; } + public string SwaggerPath { get; set; } + public ApiVersion Version { get; set; } + public OpenApiInfo OpenApiInfo { get; set; } +} diff --git a/server/src/Data/Models/AppPath.cs b/server/src/Data/Models/AppPath.cs new file mode 100644 index 0000000..e47e48c --- /dev/null +++ b/server/src/Data/Models/AppPath.cs @@ -0,0 +1,23 @@ +namespace IOL.GreatOffice.Api.Data.Models; + +public sealed record AppPath +{ + public string HostPath { get; init; } + public string WebPath { get; init; } + + public string GetHostPathForFilename(string filename, string fallback = "") { + if (filename.IsNullOrWhiteSpace()) { + return fallback; + } + + return Path.Combine(HostPath, filename); + } + + public string GetWebPathForFilename(string filename, string fallback = "") { + if (filename.IsNullOrWhiteSpace()) { + return fallback; + } + + return Path.Combine(WebPath, filename); + } +} diff --git a/server/src/Data/Models/LoggedInUserModel.cs b/server/src/Data/Models/LoggedInUserModel.cs new file mode 100644 index 0000000..4a5bef9 --- /dev/null +++ b/server/src/Data/Models/LoggedInUserModel.cs @@ -0,0 +1,8 @@ +namespace IOL.GreatOffice.Api.Data.Models; + +public class LoggedInUserModel +{ + public LoggedInUserModel() { } + public Guid Id { get; set; } + public string Username { get; set; } +} diff --git a/server/src/Data/Results/ErrorResult.cs b/server/src/Data/Results/ErrorResult.cs new file mode 100644 index 0000000..fd2fd6a --- /dev/null +++ b/server/src/Data/Results/ErrorResult.cs @@ -0,0 +1,12 @@ +namespace IOL.GreatOffice.Api.Data.Results; + +public class ErrorResult +{ + public ErrorResult(string title = default, string text = default) { + Title = title; + Text = text; + } + + public string Title { get; set; } + public string Text { get; set; } +} diff --git a/server/src/Data/Static/AppClaims.cs b/server/src/Data/Static/AppClaims.cs new file mode 100644 index 0000000..8b6d3a8 --- /dev/null +++ b/server/src/Data/Static/AppClaims.cs @@ -0,0 +1,8 @@ +namespace IOL.GreatOffice.Api.Data.Static; + +public static class AppClaims +{ + public const string USER_ID = "user_id"; + public const string NAME = "name"; + public const string GITHUB_ACCESS_TOKEN = ""; +} diff --git a/server/src/Data/Static/AppConstants.cs b/server/src/Data/Static/AppConstants.cs new file mode 100644 index 0000000..61e5cd5 --- /dev/null +++ b/server/src/Data/Static/AppConstants.cs @@ -0,0 +1,11 @@ +namespace IOL.GreatOffice.Api.Data.Static; + +public static class AppConstants +{ + public const string API_NAME = "Great Office API"; + public const string BASIC_AUTH_SCHEME = "BasicAuthenticationScheme"; + public const string TOKEN_ALLOW_READ = "TOKEN_ALLOW_READ"; + public const string TOKEN_ALLOW_CREATE = "TOKEN_ALLOW_CREATE"; + public const string TOKEN_ALLOW_UPDATE = "TOKEN_ALLOW_UPDATE"; + public const string TOKEN_ALLOW_DELETE = "TOKEN_ALLOW_DELETE"; +} diff --git a/server/src/Data/Static/AppEnvironmentVariables.cs b/server/src/Data/Static/AppEnvironmentVariables.cs new file mode 100644 index 0000000..a734146 --- /dev/null +++ b/server/src/Data/Static/AppEnvironmentVariables.cs @@ -0,0 +1,27 @@ +namespace IOL.GreatOffice.Api.Data.Static; + +public static class AppEnvironmentVariables +{ + public const string DB_HOST = "DB_HOST"; + public const string DB_PORT = "DB_PORT"; + public const string DB_USER = "DB_USER"; + public const string DB_PASSWORD = "DB_PASSWORD"; + public const string DB_NAME = "DB_NAME"; + public const string QUARTZ_DB_HOST = "QUARTZ_DB_HOST"; + public const string QUARTZ_DB_PORT = "QUARTZ_DB_PORT"; + public const string QUARTZ_DB_USER = "QUARTZ_DB_USER"; + public const string QUARTZ_DB_PASSWORD = "QUARTZ_DB_PASSWORD"; + public const string QUARTZ_DB_NAME = "QUARTZ_DB_NAME"; + public const string SEQ_API_KEY = "SEQ_API_KEY"; + public const string SEQ_API_URL = "SEQ_API_URL"; + public const string SMTP_HOST = "SMTP_HOST"; + public const string SMTP_PORT = "SMTP_PORT"; + public const string SMTP_USER = "SMTP_USER"; + public const string SMTP_PASSWORD = "SMTP_PASSWORD"; + public const string EMAIL_FROM_ADDRESS = "EMAIL_FROM_ADDRESS"; + public const string EMAIL_FROM_DISPLAY_NAME = "EMAIL_FROM_DISPLAY_NAME"; + public const string ACCOUNTS_URL = "ACCOUNTS_URL"; + public const string GITHUB_CLIENT_ID = "GH_CLIENT_ID"; + public const string GITHUB_CLIENT_SECRET = "GH_CLIENT_SECRET"; + public const string APP_AES_KEY = "APP_AES_KEY"; +} diff --git a/server/src/Data/Static/AppHeaders.cs b/server/src/Data/Static/AppHeaders.cs new file mode 100644 index 0000000..41a3085 --- /dev/null +++ b/server/src/Data/Static/AppHeaders.cs @@ -0,0 +1,6 @@ +namespace IOL.GreatOffice.Api.Data.Static; + +public static class AppHeaders +{ + public const string BROWSER_TIME_ZONE = "X-TimeZone"; +} diff --git a/server/src/Data/Static/AppPaths.cs b/server/src/Data/Static/AppPaths.cs new file mode 100644 index 0000000..a24f5af --- /dev/null +++ b/server/src/Data/Static/AppPaths.cs @@ -0,0 +1,17 @@ + +namespace IOL.GreatOffice.Api.Data.Static; + +public static class AppPaths +{ + public static AppPath AppData => new() { + HostPath = Path.Combine(Directory.GetCurrentDirectory(), "AppData") + }; + + public static AppPath DataProtectionKeys => new() { + HostPath = Path.Combine(Directory.GetCurrentDirectory(), "AppData", "dp-keys") + }; + + public static AppPath Frontend => new() { + HostPath = Path.Combine(Directory.GetCurrentDirectory(), "Frontend") + }; +} diff --git a/server/src/Data/Static/JsonSettings.cs b/server/src/Data/Static/JsonSettings.cs new file mode 100644 index 0000000..a163c11 --- /dev/null +++ b/server/src/Data/Static/JsonSettings.cs @@ -0,0 +1,11 @@ +namespace IOL.GreatOffice.Api.Data.Static; + +public static class JsonSettings +{ + public static Action<JsonOptions> Default { get; } = options => { + options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; + options.JsonSerializerOptions.PropertyNameCaseInsensitive = true; + options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString; + options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + }; +} |
