init backend
This commit is contained in:
32
.gitignore
vendored
Normal file
32
.gitignore
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# .NET
|
||||||
|
dotnet/**/bin/
|
||||||
|
dotnet/**/obj/
|
||||||
|
dotnet/**/*.user
|
||||||
|
dotnet/**/*.vs/
|
||||||
|
dotnet/**/.vs/
|
||||||
|
|
||||||
|
# React/Node
|
||||||
|
react/node_modules/
|
||||||
|
react/dist/
|
||||||
|
react/.env
|
||||||
|
react/.env.local
|
||||||
|
react/.env.*.local
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
|
||||||
|
# Claude Code plans
|
||||||
|
.claude/
|
||||||
77
dotnet/.gitignore
vendored
Normal file
77
dotnet/.gitignore
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# Environment variables with secrets
|
||||||
|
.env
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
|
||||||
|
# Visual Studio cache/options directory
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
.idea/
|
||||||
|
*.sln.iml
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
*.snupkg
|
||||||
|
**/packages/*
|
||||||
|
!**/packages/build/
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
**/.dockerignore
|
||||||
9
dotnet/AipsCore/AipsCore.csproj
Normal file
9
dotnet/AipsCore/AipsCore.csproj
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
5
dotnet/AipsCore/Application/Abstract/Command/ICommand.cs
Normal file
5
dotnet/AipsCore/Application/Abstract/Command/ICommand.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
namespace AipsCore.Application.Abstract.Command;
|
||||||
|
|
||||||
|
public interface ICommand {}
|
||||||
|
|
||||||
|
public interface ICommand<TResult> {}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace AipsCore.Application.Abstract.Command;
|
||||||
|
|
||||||
|
public interface ICommandHandler<in TCommand>
|
||||||
|
where TCommand : ICommand
|
||||||
|
{
|
||||||
|
Task Handle(TCommand command, CancellationToken cancellationToken = default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ICommandHandler<in TCommand, TResult>
|
||||||
|
where TCommand : ICommand<TResult>
|
||||||
|
{
|
||||||
|
Task<TResult> Handle(TCommand command, CancellationToken cancellationToken = default);
|
||||||
|
}
|
||||||
3
dotnet/AipsCore/Application/Abstract/Query/IQuery.cs
Normal file
3
dotnet/AipsCore/Application/Abstract/Query/IQuery.cs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
namespace AipsCore.Application.Abstract.Query;
|
||||||
|
|
||||||
|
public interface IQuery<TResult> {}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace AipsCore.Application.Abstract.Query;
|
||||||
|
|
||||||
|
public interface IQueryHandler<in TQuery, TResult>
|
||||||
|
where TQuery : IQuery<TResult>
|
||||||
|
{
|
||||||
|
Task<TResult> HandleAsync(TQuery query, CancellationToken cancellationToken = default);
|
||||||
|
}
|
||||||
18
dotnet/AipsCore/Domain/Abstract/Rule/AbstractRule.cs
Normal file
18
dotnet/AipsCore/Domain/Abstract/Rule/AbstractRule.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using AipsCore.Domain.Common.Validation;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Abstract.Rule;
|
||||||
|
|
||||||
|
public abstract class AbstractRule : IRule
|
||||||
|
{
|
||||||
|
protected abstract string ErrorCode { get; }
|
||||||
|
protected abstract string ErrorMessage { get; }
|
||||||
|
|
||||||
|
public string ValueObjectName { protected get; set; } = "Unknown";
|
||||||
|
|
||||||
|
public ValidationError GetError()
|
||||||
|
{
|
||||||
|
return new ValidationError(ErrorCode, ErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract bool Validate();
|
||||||
|
}
|
||||||
10
dotnet/AipsCore/Domain/Abstract/Rule/IRule.cs
Normal file
10
dotnet/AipsCore/Domain/Abstract/Rule/IRule.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using AipsCore.Domain.Common.Validation;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Abstract.Rule;
|
||||||
|
|
||||||
|
public interface IRule
|
||||||
|
{
|
||||||
|
ValidationError GetError();
|
||||||
|
bool Validate();
|
||||||
|
string ValueObjectName { set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using AipsCore.Domain.Abstract.Rule;
|
||||||
|
using AipsCore.Domain.Common.Validation;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Abstract.ValueObject;
|
||||||
|
|
||||||
|
public abstract record AbstractValueObject
|
||||||
|
{
|
||||||
|
protected abstract ICollection<IRule> GetValidationRules();
|
||||||
|
|
||||||
|
protected void Validate()
|
||||||
|
{
|
||||||
|
var rules = GetValidationRules();
|
||||||
|
var validator = new Validator(rules, ValueObjectName);
|
||||||
|
|
||||||
|
validator.Validate();
|
||||||
|
|
||||||
|
if (!validator.Success)
|
||||||
|
{
|
||||||
|
throw validator.GetValidationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ValueObjectName => this.GetType().Name;
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using AipsCore.Domain.Abstract;
|
||||||
|
using AipsCore.Domain.Abstract.Rule;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Common.Validation.Rules;
|
||||||
|
|
||||||
|
public class CharsetRule : AbstractRule
|
||||||
|
{
|
||||||
|
private readonly string _stringValue;
|
||||||
|
private readonly char[] _charset;
|
||||||
|
|
||||||
|
protected CharsetRule(string stringValue, char[] charset)
|
||||||
|
{
|
||||||
|
_stringValue = stringValue;
|
||||||
|
_charset = charset;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string ErrorCode => "charset";
|
||||||
|
protected override string ErrorMessage => $"Forbidden characters in '{ValueObjectName}'";
|
||||||
|
|
||||||
|
public override bool Validate()
|
||||||
|
{
|
||||||
|
foreach (char character in _stringValue)
|
||||||
|
{
|
||||||
|
if (!_charset.Contains(character))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
dotnet/AipsCore/Domain/Common/Validation/Rules/EmailRule.cs
Normal file
32
dotnet/AipsCore/Domain/Common/Validation/Rules/EmailRule.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using System.Net.Mail;
|
||||||
|
using AipsCore.Domain.Abstract;
|
||||||
|
using AipsCore.Domain.Abstract.Rule;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Common.Validation.Rules;
|
||||||
|
|
||||||
|
public class EmailRule : AbstractRule
|
||||||
|
{
|
||||||
|
protected override string ErrorCode => "email_invalid";
|
||||||
|
protected override string ErrorMessage => "Email is not in the valid format";
|
||||||
|
|
||||||
|
private readonly string _emailValue;
|
||||||
|
|
||||||
|
public EmailRule(string emailValue)
|
||||||
|
{
|
||||||
|
_emailValue = emailValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Validate()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_ = new MailAddress(_emailValue);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using AipsCore.Domain.Abstract;
|
||||||
|
using AipsCore.Domain.Abstract.Rule;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Common.Validation.Rules;
|
||||||
|
|
||||||
|
public class ExactLength : AbstractRule
|
||||||
|
{
|
||||||
|
private readonly string _stringValue;
|
||||||
|
private readonly int _exactLentgh;
|
||||||
|
protected override string ErrorCode => "exact_length";
|
||||||
|
protected override string ErrorMessage
|
||||||
|
=> $"Length of '{ValueObjectName}' must be {_exactLentgh} characters";
|
||||||
|
|
||||||
|
public ExactLength(string stringValue, int exactLentgh)
|
||||||
|
{
|
||||||
|
_stringValue = stringValue;
|
||||||
|
_exactLentgh = exactLentgh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Validate()
|
||||||
|
{
|
||||||
|
return _stringValue.Length == _exactLentgh;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using AipsCore.Domain.Abstract;
|
||||||
|
using AipsCore.Domain.Abstract.Rule;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Common.Validation.Rules;
|
||||||
|
|
||||||
|
public class MaxLengthRule : AbstractRule
|
||||||
|
{
|
||||||
|
private readonly string _stringValue;
|
||||||
|
private readonly int _maximumLentgh;
|
||||||
|
protected override string ErrorCode => "minimum_length";
|
||||||
|
protected override string ErrorMessage
|
||||||
|
=> $"Length of '{ValueObjectName}' must be at most {_maximumLentgh} characters";
|
||||||
|
|
||||||
|
public MaxLengthRule(string stringValue, int maximumLentgh)
|
||||||
|
{
|
||||||
|
_stringValue = stringValue;
|
||||||
|
_maximumLentgh = maximumLentgh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Validate()
|
||||||
|
{
|
||||||
|
return _stringValue.Length <= _maximumLentgh;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using AipsCore.Domain.Abstract;
|
||||||
|
using AipsCore.Domain.Abstract.Rule;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Common.Validation.Rules;
|
||||||
|
|
||||||
|
public class MinLengthRule : AbstractRule
|
||||||
|
{
|
||||||
|
private readonly string _stringValue;
|
||||||
|
private readonly int _minimumLentgh;
|
||||||
|
protected override string ErrorCode => "minimum_length";
|
||||||
|
protected override string ErrorMessage
|
||||||
|
=> $"Length of '{ValueObjectName}' must be at least {_minimumLentgh} characters";
|
||||||
|
|
||||||
|
public MinLengthRule(string stringValue, int minimumLentgh)
|
||||||
|
{
|
||||||
|
_stringValue = stringValue;
|
||||||
|
_minimumLentgh = minimumLentgh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Validate()
|
||||||
|
{
|
||||||
|
return _stringValue.Length >= _minimumLentgh;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace AipsCore.Domain.Common.Validation;
|
||||||
|
|
||||||
|
public record ValidationError(string Code, string Message);
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Common.Validation;
|
||||||
|
|
||||||
|
public class ValidationException : Exception
|
||||||
|
{
|
||||||
|
public ICollection<ValidationError> ValidationErrors { get; private init; }
|
||||||
|
|
||||||
|
public ValidationException(ICollection<ValidationError> validationErrors)
|
||||||
|
{
|
||||||
|
ValidationErrors = validationErrors;
|
||||||
|
}
|
||||||
|
}
|
||||||
55
dotnet/AipsCore/Domain/Common/Validation/Validator.cs
Normal file
55
dotnet/AipsCore/Domain/Common/Validation/Validator.cs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
using AipsCore.Domain.Abstract;
|
||||||
|
using AipsCore.Domain.Abstract.Rule;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Common.Validation;
|
||||||
|
|
||||||
|
public class Validator
|
||||||
|
{
|
||||||
|
private readonly ICollection<IRule> _validationRules;
|
||||||
|
private readonly string _valueObjectName;
|
||||||
|
|
||||||
|
public Validator(ICollection<IRule> validationRules, string valueObjectName)
|
||||||
|
{
|
||||||
|
_validationRules = validationRules;
|
||||||
|
_valueObjectName = valueObjectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Success { get; private set; } = false;
|
||||||
|
|
||||||
|
private ValidationException? _validationException = null;
|
||||||
|
|
||||||
|
public ValidationException GetValidationException()
|
||||||
|
{
|
||||||
|
if (_validationException is null)
|
||||||
|
{
|
||||||
|
return new ValidationException([]);
|
||||||
|
}
|
||||||
|
return _validationException;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Validate()
|
||||||
|
{
|
||||||
|
List<ValidationError> errors = [];
|
||||||
|
|
||||||
|
foreach (var validationRule in _validationRules)
|
||||||
|
{
|
||||||
|
validationRule.ValueObjectName = _valueObjectName;
|
||||||
|
|
||||||
|
if (!validationRule.Validate())
|
||||||
|
{
|
||||||
|
errors.Add(validationRule.GetError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors.Any())
|
||||||
|
{
|
||||||
|
Success = false;
|
||||||
|
_validationException = new ValidationException(errors.ToArray());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Success = true;
|
||||||
|
_validationException = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
dotnet/AipsCore/Domain/Common/ValueObjects/DomainId.cs
Normal file
22
dotnet/AipsCore/Domain/Common/ValueObjects/DomainId.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using AipsCore.Domain.Abstract;
|
||||||
|
using AipsCore.Domain.Abstract.Rule;
|
||||||
|
using AipsCore.Domain.Abstract.ValueObject;
|
||||||
|
using AipsCore.Domain.Common.Validation;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Common.ValueObjects;
|
||||||
|
|
||||||
|
public record DomainId : AbstractValueObject
|
||||||
|
{
|
||||||
|
public string IdValue { get; init; }
|
||||||
|
|
||||||
|
public DomainId(string IdValue)
|
||||||
|
{
|
||||||
|
this.IdValue = IdValue;
|
||||||
|
Validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override ICollection<IRule> GetValidationRules()
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
26
dotnet/AipsCore/Domain/Common/ValueObjects/Email.cs
Normal file
26
dotnet/AipsCore/Domain/Common/ValueObjects/Email.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using AipsCore.Domain.Abstract;
|
||||||
|
using AipsCore.Domain.Abstract.Rule;
|
||||||
|
using AipsCore.Domain.Abstract.ValueObject;
|
||||||
|
using AipsCore.Domain.Common.Validation;
|
||||||
|
using AipsCore.Domain.Common.Validation.Rules;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Common.ValueObjects;
|
||||||
|
|
||||||
|
public record Email : AbstractValueObject
|
||||||
|
{
|
||||||
|
public string EmailValue { get; init; }
|
||||||
|
|
||||||
|
public Email(string EmailValue)
|
||||||
|
{
|
||||||
|
this.EmailValue = EmailValue;
|
||||||
|
Validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override ICollection<IRule> GetValidationRules()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
[
|
||||||
|
new EmailRule(EmailValue)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
18
dotnet/AipsCore/Domain/Models/User/User.cs
Normal file
18
dotnet/AipsCore/Domain/Models/User/User.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using AipsCore.Domain.Common.ValueObjects;
|
||||||
|
using AipsCore.Domain.Models.User.ValueObjects;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Models.User;
|
||||||
|
|
||||||
|
public class User
|
||||||
|
{
|
||||||
|
public UserId Id { get; private set; }
|
||||||
|
public Email Email { get; private set; }
|
||||||
|
public Username Username { get; private set; }
|
||||||
|
|
||||||
|
public User(UserId id, Email email, Username username)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
Email = email;
|
||||||
|
Username = username;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using AipsCore.Domain.Common.Validation.Rules;
|
||||||
|
using AipsCore.Utility.Text;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Models.User.Validation;
|
||||||
|
|
||||||
|
public class UsernameCharsetRule : CharsetRule
|
||||||
|
{
|
||||||
|
public UsernameCharsetRule(string stringValue)
|
||||||
|
: base(stringValue, GetUsernameCharset())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private static char[] GetUsernameCharset()
|
||||||
|
{
|
||||||
|
var alphanumericCharset = Charset.GetAlphanumericCharset();
|
||||||
|
|
||||||
|
char[] usernameCharset = [..alphanumericCharset, '_'];
|
||||||
|
|
||||||
|
return usernameCharset;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string ErrorCode => "username_charset";
|
||||||
|
|
||||||
|
protected override string ErrorMessage =>
|
||||||
|
"Username contains invalid characters, only alphanumeric characters and '_' are allowed";
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
using AipsCore.Domain.Common.ValueObjects;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Models.User.ValueObjects;
|
||||||
|
|
||||||
|
public record UserId(string IdValue) : DomainId(IdValue);
|
||||||
33
dotnet/AipsCore/Domain/Models/User/ValueObjects/Username.cs
Normal file
33
dotnet/AipsCore/Domain/Models/User/ValueObjects/Username.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using AipsCore.Domain.Abstract;
|
||||||
|
using AipsCore.Domain.Abstract.Rule;
|
||||||
|
using AipsCore.Domain.Abstract.ValueObject;
|
||||||
|
using AipsCore.Domain.Common.Validation;
|
||||||
|
using AipsCore.Domain.Common.Validation.Rules;
|
||||||
|
using AipsCore.Domain.Common.ValueObjects;
|
||||||
|
using AipsCore.Domain.Models.User.Validation;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Models.User.ValueObjects;
|
||||||
|
|
||||||
|
public record Username : AbstractValueObject
|
||||||
|
{
|
||||||
|
public string UsernameValue { get; init; }
|
||||||
|
|
||||||
|
public Username(string UsernameValue)
|
||||||
|
{
|
||||||
|
this.UsernameValue = UsernameValue;
|
||||||
|
Validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private const int MinimumLength = 8;
|
||||||
|
private const int MaximumLength = 20;
|
||||||
|
|
||||||
|
protected override ICollection<IRule> GetValidationRules()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
[
|
||||||
|
new MinLengthRule(UsernameValue, MinimumLength),
|
||||||
|
new MaxLengthRule(UsernameValue, MaximumLength),
|
||||||
|
new UsernameCharsetRule(UsernameValue)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using AipsCore.Domain.Common.Validation.Rules;
|
||||||
|
using AipsCore.Utility.Text;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Models.Whiteboard.Validation;
|
||||||
|
|
||||||
|
public class WhitebordCodeCharsetRule : CharsetRule
|
||||||
|
{
|
||||||
|
public WhitebordCodeCharsetRule(string stringValue)
|
||||||
|
: base(stringValue, GetWhiteboardCodeCharset())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private static char[] GetWhiteboardCodeCharset()
|
||||||
|
{
|
||||||
|
return Charset.GetNumericCharset();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string ErrorCode => "whiteboard_code_charset";
|
||||||
|
protected override string ErrorMessage => "Whiteboard code must contain only numbers";
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using AipsCore.Domain.Abstract;
|
||||||
|
using AipsCore.Domain.Abstract.Rule;
|
||||||
|
using AipsCore.Domain.Abstract.ValueObject;
|
||||||
|
using AipsCore.Domain.Common.Validation;
|
||||||
|
using AipsCore.Domain.Common.Validation.Rules;
|
||||||
|
using AipsCore.Domain.Common.ValueObjects;
|
||||||
|
using AipsCore.Domain.Models.Whiteboard.Validation;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Models.Whiteboard.ValueObjects;
|
||||||
|
|
||||||
|
public record WhiteboardCode : AbstractValueObject
|
||||||
|
{
|
||||||
|
public string CodeValue { get; init; }
|
||||||
|
|
||||||
|
public WhiteboardCode(string CodeValue)
|
||||||
|
{
|
||||||
|
this.CodeValue = CodeValue;
|
||||||
|
Validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private const int CodeLength = 8;
|
||||||
|
|
||||||
|
protected override ICollection<IRule> GetValidationRules()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
[
|
||||||
|
new ExactLength(CodeValue, CodeLength),
|
||||||
|
new WhitebordCodeCharsetRule(CodeValue)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
using AipsCore.Domain.Common.ValueObjects;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Models.Whiteboard.ValueObjects;
|
||||||
|
|
||||||
|
public record WhiteboardId(string IdValue) : DomainId(IdValue);
|
||||||
18
dotnet/AipsCore/Domain/Models/Whiteboard/Whiteboard.cs
Normal file
18
dotnet/AipsCore/Domain/Models/Whiteboard/Whiteboard.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using AipsCore.Domain.Models.User.ValueObjects;
|
||||||
|
using AipsCore.Domain.Models.Whiteboard.ValueObjects;
|
||||||
|
|
||||||
|
namespace AipsCore.Domain.Models.Whiteboard;
|
||||||
|
|
||||||
|
public class Whiteboard
|
||||||
|
{
|
||||||
|
public WhiteboardId Id { get; private set; }
|
||||||
|
public UserId WhiteboardOwnerId { get; private set; }
|
||||||
|
public WhiteboardCode Code { get; private set; }
|
||||||
|
|
||||||
|
public Whiteboard(WhiteboardId id, User.User whiteboardOwner, WhiteboardCode code)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
WhiteboardOwnerId = whiteboardOwner.Id;
|
||||||
|
Code = code;
|
||||||
|
}
|
||||||
|
}
|
||||||
6
dotnet/AipsCore/Infrastructure/Db/AipsDbContext.cs
Normal file
6
dotnet/AipsCore/Infrastructure/Db/AipsDbContext.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace AipsCore.Infrastructure.Db;
|
||||||
|
|
||||||
|
public class AipsDbContext
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
41
dotnet/AipsCore/Utility/Text/Charset.cs
Normal file
41
dotnet/AipsCore/Utility/Text/Charset.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
namespace AipsCore.Utility.Text;
|
||||||
|
|
||||||
|
public static class Charset
|
||||||
|
{
|
||||||
|
public static char[] GetNumericCharset()
|
||||||
|
{
|
||||||
|
var charset = new List<char>();
|
||||||
|
|
||||||
|
// 0–9
|
||||||
|
for (char c = '0'; c <= '9'; c++)
|
||||||
|
charset.Add(c);
|
||||||
|
|
||||||
|
return charset.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static char[] GetLettersCharset()
|
||||||
|
{
|
||||||
|
|
||||||
|
var charset = new List<char>();
|
||||||
|
|
||||||
|
// a–z
|
||||||
|
for (char c = 'a'; c <= 'z'; c++)
|
||||||
|
charset.Add(c);
|
||||||
|
|
||||||
|
// A–Z
|
||||||
|
for (char c = 'A'; c <= 'Z'; c++)
|
||||||
|
charset.Add(c);
|
||||||
|
|
||||||
|
return charset.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static char[] GetAlphanumericCharset()
|
||||||
|
{
|
||||||
|
var lettersCharset = GetLettersCharset();
|
||||||
|
var numericCharset = GetNumericCharset();
|
||||||
|
|
||||||
|
char[] alphanumericCharset = [..numericCharset, ..lettersCharset];
|
||||||
|
|
||||||
|
return alphanumericCharset;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
dotnet/dotnet.sln
Normal file
18
dotnet/dotnet.sln
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E0259F3A-496C-4A5E-8D6D-D134F2A9E3D4}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AipsCore", "AipsCore\AipsCore.csproj", "{C2EAA516-A045-4525-9A47-4AA8198FD104}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{C2EAA516-A045-4525-9A47-4AA8198FD104}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C2EAA516-A045-4525-9A47-4AA8198FD104}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C2EAA516-A045-4525-9A47-4AA8198FD104}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C2EAA516-A045-4525-9A47-4AA8198FD104}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
Reference in New Issue
Block a user