diff --git a/Web/Azaion.Web/Azaion.Repository/Azaion.Repository.csproj b/Web/Azaion.Web/Azaion.Repository/Azaion.Repository.csproj
new file mode 100644
index 0000000..51e0b98
--- /dev/null
+++ b/Web/Azaion.Web/Azaion.Repository/Azaion.Repository.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/Web/Azaion.Web/Azaion.Repository/AzaionDbSql.cs b/Web/Azaion.Web/Azaion.Repository/AzaionDbSql.cs
new file mode 100644
index 0000000..2f19c85
--- /dev/null
+++ b/Web/Azaion.Web/Azaion.Repository/AzaionDbSql.cs
@@ -0,0 +1,12 @@
+using Azaion.Repository.Entities;
+using LinqToDB;
+using LinqToDB.Data;
+
+namespace Azaion.Repository;
+
+public class AzaionDbSql(DataOptions dataOptions) : DataConnection(dataOptions)
+{
+ public ITable Medias => this.GetTable();
+ public ITable Users => this.GetTable();
+ public ITable Annotations => this.GetTable();
+}
\ No newline at end of file
diff --git a/Web/Azaion.Web/Azaion.Repository/AzaionDbSqlSchemaHolder.cs b/Web/Azaion.Web/Azaion.Repository/AzaionDbSqlSchemaHolder.cs
new file mode 100644
index 0000000..8e398c3
--- /dev/null
+++ b/Web/Azaion.Web/Azaion.Repository/AzaionDbSqlSchemaHolder.cs
@@ -0,0 +1,26 @@
+using Azaion.Repository.Entities;
+using LinqToDB.Mapping;
+
+namespace Azaion.Repository;
+
+public static class AzaionDbSqlSchemaHolder
+{
+ public static readonly MappingSchema MappingSchema;
+
+ static AzaionDbSqlSchemaHolder()
+ {
+ MappingSchema = new MappingSchema();
+ var builder = new FluentMappingBuilder(MappingSchema);
+
+ builder.Entity()
+ .HasIdentity(x => x.Id);
+
+ builder.Entity()
+ .HasIdentity(x => x.Id);
+
+ builder.Entity()
+ .HasIdentity(x => x.Id);
+
+ builder.Build();
+ }
+}
\ No newline at end of file
diff --git a/Web/Azaion.Web/Azaion.Repository/DTO/ConnectionStrings.cs b/Web/Azaion.Web/Azaion.Repository/DTO/ConnectionStrings.cs
new file mode 100644
index 0000000..5cb592a
--- /dev/null
+++ b/Web/Azaion.Web/Azaion.Repository/DTO/ConnectionStrings.cs
@@ -0,0 +1,7 @@
+namespace Azaion.Repository.DTO;
+
+public class ConnectionStrings
+{
+ public string? FraudDb { get; set; }
+ public string? FraudDbMsSql { get; set; }
+}
\ No newline at end of file
diff --git a/Web/Azaion.Web/Azaion.Repository/DTO/MediaStatusEnum.cs b/Web/Azaion.Web/Azaion.Repository/DTO/MediaStatusEnum.cs
new file mode 100644
index 0000000..4eb1d1c
--- /dev/null
+++ b/Web/Azaion.Web/Azaion.Repository/DTO/MediaStatusEnum.cs
@@ -0,0 +1,9 @@
+namespace Azaion.Video.DTO;
+
+public enum MediaStatusEnum
+{
+ None = 0,
+ Uploaded = 10,
+ Annotating = 20,
+ Annotated = 30
+}
\ No newline at end of file
diff --git a/Web/Azaion.Web/Azaion.Repository/DTO/VideoDto.cs b/Web/Azaion.Web/Azaion.Repository/DTO/VideoDto.cs
new file mode 100644
index 0000000..bf919a3
--- /dev/null
+++ b/Web/Azaion.Web/Azaion.Repository/DTO/VideoDto.cs
@@ -0,0 +1,11 @@
+using Azaion.Video.DTO;
+
+namespace Azaion.Repository.DTO;
+
+public class VideoDto
+{
+ public Guid Id { get; set; }
+ public string Path { get; set; } = null!;
+ public MediaStatusEnum MediaStatus { get; set; }
+ public DateTime CreatedDate { get; set; }
+}
\ No newline at end of file
diff --git a/Web/Azaion.Web/Azaion.Repository/DbFactory.cs b/Web/Azaion.Web/Azaion.Repository/DbFactory.cs
new file mode 100644
index 0000000..55116fe
--- /dev/null
+++ b/Web/Azaion.Web/Azaion.Repository/DbFactory.cs
@@ -0,0 +1,48 @@
+using System.Diagnostics;
+using LinqToDB;
+
+namespace Azaion.Repository;
+
+public interface IDbFactory
+{
+ Task Run(Func> func);
+ Task Run(Func func);
+
+ T Run(Func func);
+}
+
+public class DbFactory : IDbFactory
+{
+ private readonly DataOptions _dataOptions;
+
+ public DbFactory(string connectionString, bool useTracing = true)
+ {
+ if (string.IsNullOrEmpty(connectionString))
+ throw new ArgumentException("Empty connectionString", nameof(connectionString));
+
+ _dataOptions = new DataOptions()
+ .UseMySqlConnector(connectionString)
+ .UseMappingSchema(AzaionDbSqlSchemaHolder.MappingSchema);
+
+ if (useTracing)
+ _ = _dataOptions.UseTracing(TraceLevel.Info, t => Console.WriteLine(t.SqlText));
+ }
+
+ public async Task Run(Func> func)
+ {
+ await using var db = new AzaionDbSql(_dataOptions);
+ return await func(db);
+ }
+
+ public async Task Run(Func func)
+ {
+ await using var db = new AzaionDbSql(_dataOptions);
+ await func(db);
+ }
+
+ public T Run(Func func)
+ {
+ using var db = new AzaionDbSql(_dataOptions);
+ return func(db);
+ }
+}
diff --git a/Web/Azaion.Web/Azaion.Repository/Entities/Annotation.cs b/Web/Azaion.Web/Azaion.Repository/Entities/Annotation.cs
new file mode 100644
index 0000000..1b83a50
--- /dev/null
+++ b/Web/Azaion.Web/Azaion.Repository/Entities/Annotation.cs
@@ -0,0 +1,10 @@
+namespace Azaion.Repository.Entities;
+
+public class Annotation
+{
+ public Guid Id { get; set; }
+ public Guid MediaId { get; set; }
+ public string ImagePath { get; set; } = null!;
+ public string LabelPath { get; set; } = null!;
+ public DateTime CreatedDate { get; set; }
+}
diff --git a/Web/Azaion.Web/Azaion.Repository/Entities/Media.cs b/Web/Azaion.Web/Azaion.Repository/Entities/Media.cs
new file mode 100644
index 0000000..686d134
--- /dev/null
+++ b/Web/Azaion.Web/Azaion.Repository/Entities/Media.cs
@@ -0,0 +1,12 @@
+using Azaion.Video.DTO;
+
+namespace Azaion.Repository.Entities;
+
+public class Media
+{
+ public Guid Id { get; set; }
+ public string Path { get; set; } = null!;
+ public Guid? AnnotatorId { get; set; }
+ public MediaStatusEnum Status { get; set; }
+ public DateTime CreatedDate { get; set; }
+}
diff --git a/Web/Azaion.Web/Azaion.Repository/Entities/User.cs b/Web/Azaion.Web/Azaion.Repository/Entities/User.cs
new file mode 100644
index 0000000..e0117d5
--- /dev/null
+++ b/Web/Azaion.Web/Azaion.Repository/Entities/User.cs
@@ -0,0 +1,12 @@
+namespace Azaion.Repository.Entities;
+
+public class User
+{
+ public Guid Id { get; set; }
+ public string Username { get; set; } = null!;
+ public string Email { get; set; } = null!;
+ public string PasswordHash { get; set; } = null!;
+ public string PasswordSalt { get; set; } = null!;
+ public DateTime CreatedDate { get; set; }
+ public DateTime UpdatedDate { get; set; }
+}
diff --git a/Web/Azaion.Web/Azaion.Repository/sql/01 initial.sql b/Web/Azaion.Web/Azaion.Repository/sql/01 initial.sql
new file mode 100644
index 0000000..5f0785b
--- /dev/null
+++ b/Web/Azaion.Web/Azaion.Repository/sql/01 initial.sql
@@ -0,0 +1,6 @@
+CREATE USER 'azaion-user' IDENTIFIED BY 'Aza1on@db123'
+CREATE DATABASE azaion;
+GRANT SELECT, INSERT, REFERENCES, UPDATE, DELETE, CREATE, INDEX, DROP, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES
+ ON azaion.*
+ TO 'azaion-user';
+GRANT FILE ON *.* TO 'azaion-user';
diff --git a/Web/Azaion.Web/Azaion.Repository/sql/02 create_tables.sql b/Web/Azaion.Web/Azaion.Repository/sql/02 create_tables.sql
new file mode 100644
index 0000000..1a8fa81
--- /dev/null
+++ b/Web/Azaion.Web/Azaion.Repository/sql/02 create_tables.sql
@@ -0,0 +1,34 @@
+CREATE TABLE User (
+ Id CHAR(16) NOT NULL,
+ Username VARCHAR(255) NOT NULL,
+ Email VARCHAR(255) NOT NULL,
+ PasswordHash VARCHAR(255) NOT NULL,
+ PasswordSalt VARCHAR(255) NOT NULL,
+ CreatedDate DATETIME NOT NULL,
+ UpdatedDate DATETIME NOT NULL,
+ PRIMARY KEY (Id),
+ UNIQUE KEY (Username),
+ UNIQUE KEY (Email)
+);
+
+DROP TABLE Annotation;
+DROP TABLE Media;
+CREATE TABLE Media (
+ Id CHAR(16) NOT NULL,
+ Path VARCHAR(255) NOT NULL,
+ AnnotatorId CHAR(16) NULL,
+ Status INT NOT NULL, -- replace with actual enum values
+ CreatedDate DATETIME NOT NULL,
+ PRIMARY KEY (Id),
+ FOREIGN KEY (AnnotatorId) REFERENCES User(Id)
+);
+
+CREATE TABLE Annotation (
+ Id CHAR(16) NOT NULL,
+ MediaId CHAR(16) NOT NULL,
+ ImagePath VARCHAR(255) NOT NULL,
+ LabelPath VARCHAR(255) NOT NULL,
+ CreatedDate DATETIME NOT NULL,
+ PRIMARY KEY (Id),
+ FOREIGN KEY (MediaId) REFERENCES Media(Id)
+);
diff --git a/Web/Azaion.Web/Azaion.Video/Azaion.Video.csproj b/Web/Azaion.Web/Azaion.Video/Azaion.Video.csproj
new file mode 100644
index 0000000..4232095
--- /dev/null
+++ b/Web/Azaion.Web/Azaion.Video/Azaion.Video.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/Web/Azaion.Web/Azaion.Video/IVideoManager.cs b/Web/Azaion.Web/Azaion.Video/IVideoManager.cs
new file mode 100644
index 0000000..4259dae
--- /dev/null
+++ b/Web/Azaion.Web/Azaion.Video/IVideoManager.cs
@@ -0,0 +1,58 @@
+using Azaion.Repository.DTO;
+
+namespace Azaion.Video;
+
+public interface IVideoManager
+{
+ List GetVideos();
+ void OpenVideo(Guid mediaId);
+
+ void CreateAnnotation(Guid mediaId, DateTime time)
+ {
+
+ }
+ void FinishAnnotation(Guid mediaId);
+
+ // after video ends, refresh list of free to edit videos.
+ // on attempt to open video, check whether it is already taken, if yes, then businessError, else take it to user
+ //
+ // Users
+ // Guid Username Email PasswordHash PasswordSalt CreatedDate UpdatedDate
+ //
+ // Media
+ // Guid Path UserId Status CreatedDate
+ //
+ // Annotations
+ // Guid MediaId ImagePath LabelPath CreatedDate
+ //
+ // Sftp Changes crawler
+ // Google Downloader
+ //
+ // Video_path User
+ //
+ // v01 NULL
+ // v02 NULL
+ // v03 NULL
+ // v04 NULL
+ // v05 user1
+ // v06 user1
+ // v07 user1
+ // v08 NULL
+ // v09 user2
+ // v10 user3
+ // v11 user3
+ // v12 NULL
+ // v13 user2
+ // v14 NULL
+ // v15
+ // v16
+ // v17
+ // v18
+ // v19
+ // v20
+ // v21
+ // v22
+ // v23
+ // v24
+ // v25
+}
\ No newline at end of file
diff --git a/Web/Azaion.Web/Azaion.Video/VideoManager.cs b/Web/Azaion.Web/Azaion.Video/VideoManager.cs
new file mode 100644
index 0000000..11ac107
--- /dev/null
+++ b/Web/Azaion.Web/Azaion.Video/VideoManager.cs
@@ -0,0 +1,36 @@
+using Azaion.Repository;
+using Azaion.Repository.DTO;
+
+namespace Azaion.Video;
+
+public class VideoManager(IDbFactory dbFactory) : IVideoManager
+{
+ public List GetVideos()
+ {
+ return dbFactory.Run(db => db.Medias
+ .Where(x => x.AnnotatorId != null)
+ .Select(x => new VideoDto
+ {
+ Id = x.Id,
+ Path = x.Path,
+ CreatedDate = x.CreatedDate,
+ MediaStatus = x.Status
+ })
+ .ToList());
+ }
+
+ public void OpenVideo(Guid mediaId)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void OpenTestVideo()
+ {
+
+ }
+
+ public void FinishAnnotation(Guid mediaId)
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/Web/Azaion.Web/Azaion.Web.sln b/Web/Azaion.Web/Azaion.Web.sln
index 29de87a..f234869 100644
--- a/Web/Azaion.Web/Azaion.Web.sln
+++ b/Web/Azaion.Web/Azaion.Web.sln
@@ -2,6 +2,10 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azaion.WebService", "Azaion.WebService\Azaion.WebService.csproj", "{1D56907A-00A6-4D8E-88C0-929747B7FB67}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azaion.Video", "Azaion.Video\Azaion.Video.csproj", "{0FB51B6B-2C77-4F24-B640-FEEBC5395E33}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azaion.Repository", "Azaion.Repository\Azaion.Repository.csproj", "{9620B192-0B9F-4AA7-A6EE-64616FBE1B5F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -12,5 +16,13 @@ Global
{1D56907A-00A6-4D8E-88C0-929747B7FB67}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D56907A-00A6-4D8E-88C0-929747B7FB67}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D56907A-00A6-4D8E-88C0-929747B7FB67}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0FB51B6B-2C77-4F24-B640-FEEBC5395E33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0FB51B6B-2C77-4F24-B640-FEEBC5395E33}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0FB51B6B-2C77-4F24-B640-FEEBC5395E33}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0FB51B6B-2C77-4F24-B640-FEEBC5395E33}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9620B192-0B9F-4AA7-A6EE-64616FBE1B5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9620B192-0B9F-4AA7-A6EE-64616FBE1B5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9620B192-0B9F-4AA7-A6EE-64616FBE1B5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9620B192-0B9F-4AA7-A6EE-64616FBE1B5F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/Web/Azaion.Web/Azaion.WebService/Azaion.WebService.csproj b/Web/Azaion.Web/Azaion.WebService/Azaion.WebService.csproj
index 48e39a5..79e6b59 100644
--- a/Web/Azaion.Web/Azaion.WebService/Azaion.WebService.csproj
+++ b/Web/Azaion.Web/Azaion.WebService/Azaion.WebService.csproj
@@ -11,4 +11,8 @@
+
+
+
+
diff --git a/Web/Azaion.Web/Azaion.WebService/Program.cs b/Web/Azaion.Web/Azaion.WebService/Program.cs
index 161f695..9962963 100644
--- a/Web/Azaion.Web/Azaion.WebService/Program.cs
+++ b/Web/Azaion.Web/Azaion.WebService/Program.cs
@@ -1,13 +1,17 @@
+using Azaion.Repository;
+using Azaion.Repository.DTO;
+using Microsoft.Extensions.Options;
+
var builder = WebApplication.CreateBuilder(args);
-// Add services to the container.
-// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
+builder.Services.Configure(builder.Configuration.GetSection(nameof(ConnectionStrings)));
+builder.Services.AddSingleton(sp => new DbFactory(sp.GetService>()!.Value.FraudDb!));
+
var app = builder.Build();
-// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();