diff --git a/backend/api/LCPApi/Context/DBContext.cs b/backend/api/LCPApi/Context/DBContext.cs index 685d8f3..4d4ee2e 100644 --- a/backend/api/LCPApi/Context/DBContext.cs +++ b/backend/api/LCPApi/Context/DBContext.cs @@ -50,6 +50,6 @@ protected override void OnModelCreating(ModelBuilder mb) { base.OnModelCreating(mb); new DBOpData(mb).SetupForeignKeys(false); - new DBOpData(mb).Seed(false); + new DBOpData(mb).Seed(true); } } \ No newline at end of file diff --git a/backend/api/LCPApi/Context/DBOpData.cs b/backend/api/LCPApi/Context/DBOpData.cs index a702eef..018029d 100644 --- a/backend/api/LCPApi/Context/DBOpData.cs +++ b/backend/api/LCPApi/Context/DBOpData.cs @@ -28,7 +28,7 @@ public void Seed(Boolean isSeedData) int seedval = 1000; List listEmp = [ - new Employee { EmployeeId = 1001, EmployeeFirstName = "Luis", EmployeeLastName = "Carvalho", EmployeeCity = "Braga", EmployeeCountry = "Portugal", EmployeeStateProvince = "", EmployeeName = "luigicardev96", EmployeeEmail = "luiscarvalho239@gmail.com", EmployeeDateBirthday = DateTime.Parse("1996-06-04T00:00:00"), EmployeeDateRegistered = DateTime.Now, EmployeePassword = BC.HashPassword("luigi1234"), EmployeePin = 1234, EmployeeJob = "Programmer", EmployeePhoneNumber = "0123456789", EmployeePostalAddress = "1234-567", EmployeeZipCode = "1234-567", EmployeeRole = ENRoles.Administrator.ToString(), Products = null } + new Employee { EmployeeId = 1001, EmployeeFirstName = "Luis", EmployeeLastName = "Carvalho", EmployeeCity = "Braga", EmployeeCountry = "Portugal", EmployeeStateProvince = "", EmployeeName = "admin", EmployeeEmail = "luiscarvalho239@gmail.com", EmployeeDateBirthday = DateTime.Parse("1996-06-04T00:00:00"), EmployeeDateRegistered = DateTime.Now, EmployeePassword = BC.HashPassword("Kw@?7t3z704M6-6B92XG"), EmployeePin = BC.HashPassword("1234"), EmployeeJob = "Programmer", EmployeePhoneNumber = "0123456789", EmployeePostalAddress = "1234-567", EmployeeZipCode = "1234-567", EmployeeRole = ENRoles.Administrator.ToString(), Products = null } ]; _mb.Entity(b => { diff --git a/backend/api/LCPApi/Controllers/AuthController.cs b/backend/api/LCPApi/Controllers/AuthController.cs new file mode 100644 index 0000000..71cd2fa --- /dev/null +++ b/backend/api/LCPApi/Controllers/AuthController.cs @@ -0,0 +1,45 @@ +using Microsoft.AspNetCore.Mvc; +using LCPApi.Models; +using BC = BCrypt.Net.BCrypt; +using Microsoft.AspNetCore.Authorization; +using LCPApi.Functions; +using LCPApi.Context; +using Microsoft.EntityFrameworkCore; + +namespace LCPApi.Controllers +{ + [Route("api/auth/login")] + [ApiController] + [AllowAnonymous] + public class AuthController : ControllerBase + { + private readonly IConfiguration _config; + private readonly DBContext _dbc; + public AuthController(IConfiguration config, DBContext dbc) + { + _config = config; + _dbc = dbc; + } + + /// + /// Login authentication for LCP Api + /// + /// + /// + [HttpPost] + public async Task DoAuth(UserAuth userauth) + { + var users = await _dbc.Employees.SingleOrDefaultAsync(x => x.EmployeeName == userauth.UserAuthName); + + if(users == null || !CheckIfPassOrPinIsValid(userauth.UserAuthPassword, users.EmployeePassword)) { + return Problem($"The authentication of this user {userauth.UserAuthName} is invalid!"); + } + + return Ok(AuthFunctions.GenToken(_config, userauth)); + } + + private bool CheckIfPassOrPinIsValid(string originalPass, string hashedPass) { + return BC.Verify(originalPass, hashedPass, false, BCrypt.Net.HashType.SHA512); + } + } +} diff --git a/backend/api/LCPApi/Controllers/CategoryController.cs b/backend/api/LCPApi/Controllers/CategoryController.cs index d7cecda..790b2fd 100644 --- a/backend/api/LCPApi/Controllers/CategoryController.cs +++ b/backend/api/LCPApi/Controllers/CategoryController.cs @@ -1,11 +1,13 @@ using Microsoft.AspNetCore.Mvc; using LCPApi.Models; using LCPApi.Interfaces; +using Microsoft.AspNetCore.Authorization; namespace LCPApi.Controllers { [Route("api/[controller]")] [ApiController] + [Authorize(Policy = "StaffOnly")] public class CategoryController : ControllerBase { private readonly ICategory _categoryRepo; diff --git a/backend/api/LCPApi/Controllers/CustomerController.cs b/backend/api/LCPApi/Controllers/CustomerController.cs index 7fdda7c..633efea 100644 --- a/backend/api/LCPApi/Controllers/CustomerController.cs +++ b/backend/api/LCPApi/Controllers/CustomerController.cs @@ -1,12 +1,13 @@ using Microsoft.AspNetCore.Mvc; using LCPApi.Models; -using LCPApi.Repositories; using LCPApi.Interfaces; +using Microsoft.AspNetCore.Authorization; namespace LCPApi.Controllers { [Route("api/[controller]")] [ApiController] + [Authorize(Policy = "StaffOnly")] public class CustomerController : ControllerBase { private readonly ICustomer _customerRepo; diff --git a/backend/api/LCPApi/Controllers/DepartmentController.cs b/backend/api/LCPApi/Controllers/DepartmentController.cs index 7752b8b..96877fb 100644 --- a/backend/api/LCPApi/Controllers/DepartmentController.cs +++ b/backend/api/LCPApi/Controllers/DepartmentController.cs @@ -1,11 +1,13 @@ using Microsoft.AspNetCore.Mvc; using LCPApi.Models; using LCPApi.Interfaces; +using Microsoft.AspNetCore.Authorization; namespace LCPApi.Controllers { [Route("api/[controller]")] [ApiController] + [Authorize(Policy = "StaffOnly")] public class DepartmentController : ControllerBase { private readonly IDepartment _departmentRepo; diff --git a/backend/api/LCPApi/Controllers/EmployeeController.cs b/backend/api/LCPApi/Controllers/EmployeeController.cs index 836cf46..6c0936c 100644 --- a/backend/api/LCPApi/Controllers/EmployeeController.cs +++ b/backend/api/LCPApi/Controllers/EmployeeController.cs @@ -1,13 +1,13 @@ -// using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using LCPApi.Models; using LCPApi.Interfaces; +using Microsoft.AspNetCore.Authorization; namespace LCPApi.Controllers { [Route("api/[controller]")] [ApiController] - // [Authorize(Policy = "AllRights")] + [Authorize(Policy = "StaffOnly")] public class EmployeeController : ControllerBase { private readonly IEmployee _employeeRepo; diff --git a/backend/api/LCPApi/Controllers/FeedbackController.cs b/backend/api/LCPApi/Controllers/FeedbackController.cs index 5540f01..6c887e1 100644 --- a/backend/api/LCPApi/Controllers/FeedbackController.cs +++ b/backend/api/LCPApi/Controllers/FeedbackController.cs @@ -1,11 +1,13 @@ using Microsoft.AspNetCore.Mvc; using LCPApi.Models; using LCPApi.Interfaces; +using Microsoft.AspNetCore.Authorization; namespace LCPApi.Controllers { [Route("api/[controller]")] [ApiController] + [AllowAnonymous] public class FeedbackController : ControllerBase { private readonly IFeedback _feedbackRepo; diff --git a/backend/api/LCPApi/Controllers/HomeController.cs b/backend/api/LCPApi/Controllers/HomeController.cs index 87640e0..d4cce78 100644 --- a/backend/api/LCPApi/Controllers/HomeController.cs +++ b/backend/api/LCPApi/Controllers/HomeController.cs @@ -2,8 +2,6 @@ namespace LCPApi.Controllers; -// [ApiController] -// [NonController] [ApiExplorerSettings(IgnoreApi = true)] [Route("")] [Route("[controller]")] diff --git a/backend/api/LCPApi/Controllers/OrderController.cs b/backend/api/LCPApi/Controllers/OrderController.cs index 84e4d2b..d21fd00 100644 --- a/backend/api/LCPApi/Controllers/OrderController.cs +++ b/backend/api/LCPApi/Controllers/OrderController.cs @@ -1,11 +1,13 @@ using Microsoft.AspNetCore.Mvc; using LCPApi.Models; using LCPApi.Interfaces; +using Microsoft.AspNetCore.Authorization; namespace LCPApi.Controllers { [Route("api/[controller]")] [ApiController] + [AllowAnonymous] public class OrderController : ControllerBase { private readonly IOrder _orderRepo; diff --git a/backend/api/LCPApi/Controllers/ProductController.cs b/backend/api/LCPApi/Controllers/ProductController.cs index 334c950..08a94b2 100644 --- a/backend/api/LCPApi/Controllers/ProductController.cs +++ b/backend/api/LCPApi/Controllers/ProductController.cs @@ -1,11 +1,13 @@ using Microsoft.AspNetCore.Mvc; using LCPApi.Models; using LCPApi.Interfaces; +using Microsoft.AspNetCore.Authorization; namespace LCPApi.Controllers { [Route("api/[controller]")] [ApiController] + [AllowAnonymous] public class ProductController : ControllerBase { private readonly IProduct _productRepo; diff --git a/backend/api/LCPApi/Controllers/ProjectController.cs b/backend/api/LCPApi/Controllers/ProjectController.cs index 7f65bda..f854125 100644 --- a/backend/api/LCPApi/Controllers/ProjectController.cs +++ b/backend/api/LCPApi/Controllers/ProjectController.cs @@ -1,11 +1,13 @@ using Microsoft.AspNetCore.Mvc; using LCPApi.Models; using LCPApi.Interfaces; +using Microsoft.AspNetCore.Authorization; namespace LCPApi.Controllers { [Route("api/[controller]")] [ApiController] + [AllowAnonymous] public class ProjectController : ControllerBase { private readonly IProject _projectRepo; diff --git a/backend/api/LCPApi/Controllers/SubscriptionController.cs b/backend/api/LCPApi/Controllers/SubscriptionController.cs index b22ea73..ebe3d4f 100644 --- a/backend/api/LCPApi/Controllers/SubscriptionController.cs +++ b/backend/api/LCPApi/Controllers/SubscriptionController.cs @@ -1,11 +1,14 @@ +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using LCPApi.Models; using LCPApi.Interfaces; +using LCPApi.Functions; namespace LCPApi.Controllers { [Route("api/[controller]")] [ApiController] + [Authorize(Policy = "StaffOnly")] public class SubscriptionController : ControllerBase { private readonly ISubscription _subscriptionRepo; @@ -45,6 +48,12 @@ public async Task DeleteSubscription(int id) return await _subscriptionRepo.DeleteSubscription(id); } + [HttpGet("genpkey")] + public async Task>> GenerateProdKey() + { + return await ProductKeyFunctions.GetProductKey(); + } + [HttpGet("key")] public async Task>> GetSubscriptionKey() { diff --git a/backend/api/LCPApi/Functions/AuthFunctions.cs b/backend/api/LCPApi/Functions/AuthFunctions.cs index 79194f3..4b24bcf 100644 --- a/backend/api/LCPApi/Functions/AuthFunctions.cs +++ b/backend/api/LCPApi/Functions/AuthFunctions.cs @@ -8,19 +8,19 @@ namespace LCPApi.Functions; public static class AuthFunctions { - public static IResult GenToken(WebApplicationBuilder builder, UserAuth userauth) + public static string GenToken(IConfiguration config, UserAuth userauth) { - if (userauth.UserAuthName == builder.Configuration["userAuth:username"] && userauth.UserAuthPassword == builder.Configuration["userAuth:userpass"]) + if (userauth.UserAuthName == config["userAuth:username"] && userauth.UserAuthPassword == config["userAuth:userpass"]) { - var issuer = builder.Configuration["Jwt:Issuer"]; - var audience = builder.Configuration["Jwt:Audience"]; - var key = Encoding.ASCII.GetBytes(builder.Configuration["Jwt:Key"]!); + var issuer = config["Jwt:Issuer"]; + var audience = config["Jwt:Audience"]; + var key = Encoding.ASCII.GetBytes(config["Jwt:Key"]!); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new[] { new Claim("Id", Guid.NewGuid().ToString()), - new Claim("Role", ENRoles.Administrator.ToString()), + new Claim(ClaimTypes.Role, ENRoles.Administrator.ToString()), new Claim(JwtRegisteredClaimNames.Name, ""+userauth.UserAuthName), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }), @@ -32,8 +32,8 @@ public static IResult GenToken(WebApplicationBuilder builder, UserAuth userauth) var tokenHandler = new JwtSecurityTokenHandler(); var token = tokenHandler.CreateToken(tokenDescriptor); var stringToken = tokenHandler.WriteToken(token); - return Results.Ok(stringToken); + return stringToken; } - return Results.Unauthorized(); + return "Unauthorized"; } } \ No newline at end of file diff --git a/backend/api/LCPApi/Functions/ProductKeyFunctions.cs b/backend/api/LCPApi/Functions/ProductKeyFunctions.cs new file mode 100644 index 0000000..56111ae --- /dev/null +++ b/backend/api/LCPApi/Functions/ProductKeyFunctions.cs @@ -0,0 +1,128 @@ +using System.Text; +using System.Security.Cryptography; + +namespace LCPApi.Functions; + +public class ProductKeyClass { + public Guid? Id { get; set; } = Guid.NewGuid(); + public string? SecretKey { get; set; } + public string? PrivateKey { get; set; } + public string? LicenseKey { get; set; } + public string? Msg { get; set; } + public bool? IsValid { get; set; } + public DateTime? DateExp { get; set; } + public DateTime? DateNow { get; set; } +} + +public static class ProductKeyFunctions +{ + public async static Task> GetProductKey() { + //src: https://dotnetfiddle.net/srGTKN + //var secretKey = CreatePrivateKey(); + var secretKey = "+bCzRidhVxwx5TKpkz14nf5cL+BMH+ahZIOCy4bPVzdXWhysq+tZfOtrHsw9vdg5vKes/lVwzHIyquvmz9taDg=="; + var privateKey = CreatePrivateKey(); + var licenseKey = CreateLicense(secretKey); + var isValid = ValidateLicense(licenseKey, secretKey); + var validStatus = isValid ? "valid" : "invalid"; + Random rnd = new Random(); + + return await Task.FromResult(new List() { + new ProductKeyClass() { + Id = Guid.NewGuid(), + SecretKey = secretKey, + PrivateKey = privateKey, + LicenseKey = licenseKey, + Msg = $"This product license key is {validStatus}", + IsValid = isValid, + DateExp = DateTime.UtcNow.AddMonths(rnd.Next(1, 13)), + DateNow = DateTime.UtcNow + } + }); + } + + static string CreatePrivateKey() + { + // Step 01: Create your private hashkey and store it on the database + byte[] hashKey = GenerateRandomCryptographicBytes(64); + + // Convert the key to base64 so you can easily store it on the database. + // This should be kept private and never leaves your control. + var base64Secret = Convert.ToBase64String(hashKey); + + Console.WriteLine($"Private Key = {base64Secret}"); + + return base64Secret; + } + + static string CreateLicense(string secretKey) + { + // Generate a license key of 10 chars (split into groups of 5) + var licenseKey = Guid.NewGuid().ToString().ToUpper().Replace("-", "").Substring(0, 15); + + Console.WriteLine($"licenseKey = {licenseKey}"); + + // Generate a Hmac license using secretkey + var storedHmacOnDB = CalculateHmac(licenseKey, secretKey).ToUpper(); + var HMACTruncated = storedHmacOnDB.Substring(0, 15); + + Console.WriteLine($"HMAC = {HMACTruncated}"); + + var licenseAndHMAC = InsertHyphen($"{licenseKey}{HMACTruncated}"); + + Console.WriteLine($"Final User License = {licenseAndHMAC}"); + + return licenseAndHMAC; + } + + static bool ValidateLicense(string licenseKey, string secretKey) + { + var tmp = licenseKey.Split('-'); + + var license = $"{tmp[0]}{tmp[1]}{tmp[2]}"; + var licenseHmac = $"{tmp[3]}{tmp[4]}{tmp[5]}"; + + string calculatedHmac = CalculateHmac(license, secretKey); + var HMACTruncated = calculatedHmac.ToUpper().Substring(0, 15); + + bool isValid = licenseHmac.Equals(HMACTruncated, StringComparison.OrdinalIgnoreCase); + + return isValid; + } + + static string InsertHyphen(string input, int everyNthChar = 5) + { + var sb = new StringBuilder(); + for (int i = 0; i < input.Length; i++) + { + sb.Append(input[i]); + if ((i + 1) % everyNthChar == 0 && i != input.Length - 1) + { + sb.Append("-"); + } + } + return sb.ToString(); + } + + static byte[] GenerateRandomCryptographicBytes(int keyLength) + { + byte[] key = new byte[64]; + using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) + { + rng.GetBytes(key); + } + return key; + } + + static string CalculateHmac(string data, string hashKeyBase64) + { + var byteArray = Convert.FromBase64String(hashKeyBase64); + return CalculateHmac(data, byteArray); + } + + static string CalculateHmac(string data, byte[] hashKey) + { + var hmac = new HMACMD5(hashKey); + byte[] hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(data)); + return BitConverter.ToString(hashBytes).Replace("-", "").ToLower(); + } +} \ No newline at end of file diff --git a/backend/api/LCPApi/Hubs/DataHub.cs b/backend/api/LCPApi/Hubs/DataHub.cs new file mode 100644 index 0000000..1602358 --- /dev/null +++ b/backend/api/LCPApi/Hubs/DataHub.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.SignalR; + +namespace LCPApi.Hubs; + +public class DataHub : Hub { + public async Task SendData(string user, string data) { + await Clients.All.SendAsync("ReceiveData", user, data); + } +} \ No newline at end of file diff --git a/backend/api/LCPApi/LCPApi.csproj b/backend/api/LCPApi/LCPApi.csproj index 6c459cb..6819ed5 100644 --- a/backend/api/LCPApi/LCPApi.csproj +++ b/backend/api/LCPApi/LCPApi.csproj @@ -28,6 +28,7 @@ + diff --git a/backend/api/LCPApi/Migrations/20231121163209_InitialCreate.Designer.cs b/backend/api/LCPApi/Migrations/20231121163209_InitialCreate.Designer.cs new file mode 100644 index 0000000..2859433 --- /dev/null +++ b/backend/api/LCPApi/Migrations/20231121163209_InitialCreate.Designer.cs @@ -0,0 +1,789 @@ +// +using System; +using LCPApi.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace LCPApi.Migrations +{ + [DbContext(typeof(DBContext))] + [Migration("20231121163209_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("LCPApi.Models.Category", b => + { + b.Property("CategoryId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("CategoryId")); + + b.Property("CategoryDesc") + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectId") + .HasColumnType("int"); + + b.HasKey("CategoryId"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("LCPApi.Models.Customer", b => + { + b.Property("CustomerId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("CustomerId")); + + b.Property("CustomerCity") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerCountry") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerDateBirthday") + .HasColumnType("datetime2"); + + b.Property("CustomerDateRegistered") + .HasColumnType("datetime2"); + + b.Property("CustomerEmail") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerFirstName") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerJob") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerLastName") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerPassword") + .IsRequired() + .HasColumnType("varchar(MAX)"); + + b.Property("CustomerPhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerPin") + .HasMaxLength(4) + .HasColumnType("varchar(MAX)"); + + b.Property("CustomerPostalAddress") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerRole") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerStateProvince") + .HasColumnType("nvarchar(max)"); + + b.Property("CustomerZipCode") + .HasColumnType("nvarchar(max)"); + + b.HasKey("CustomerId"); + + b.ToTable("Customers"); + }); + + modelBuilder.Entity("LCPApi.Models.Department", b => + { + b.Property("DepartmentId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("DepartmentId")); + + b.Property("DepartmentDesc") + .HasColumnType("nvarchar(max)"); + + b.Property("DepartmentName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DepartmentType") + .HasColumnType("nvarchar(max)"); + + b.Property("EmployeeId") + .HasColumnType("int"); + + b.Property("ProjectId") + .HasColumnType("int"); + + b.HasKey("DepartmentId"); + + b.ToTable("Departments"); + }); + + modelBuilder.Entity("LCPApi.Models.Employee", b => + { + b.Property("EmployeeId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("EmployeeId"), 1000L); + + b.Property("EmployeeCity") + .HasColumnType("nvarchar(max)"); + + b.Property("EmployeeCountry") + .HasColumnType("nvarchar(max)"); + + b.Property("EmployeeDateBirthday") + .HasColumnType("datetime2"); + + b.Property("EmployeeDateRegistered") + .HasColumnType("datetime2"); + + b.Property("EmployeeEmail") + .HasColumnType("nvarchar(max)"); + + b.Property("EmployeeFirstName") + .HasColumnType("nvarchar(max)"); + + b.Property("EmployeeJob") + .HasColumnType("nvarchar(max)"); + + b.Property("EmployeeLastName") + .HasColumnType("nvarchar(max)"); + + b.Property("EmployeeName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EmployeePassword") + .IsRequired() + .HasColumnType("varchar(MAX)"); + + b.Property("EmployeePhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("EmployeePin") + .HasMaxLength(4) + .HasColumnType("varchar(MAX)"); + + b.Property("EmployeePostalAddress") + .HasColumnType("nvarchar(max)"); + + b.Property("EmployeeRole") + .HasColumnType("nvarchar(max)"); + + b.Property("EmployeeStateProvince") + .HasColumnType("nvarchar(max)"); + + b.Property("EmployeeZipCode") + .HasColumnType("nvarchar(max)"); + + b.HasKey("EmployeeId"); + + b.ToTable("Employees", (string)null); + + b.HasData( + new + { + EmployeeId = 1001, + EmployeeCity = "Braga", + EmployeeCountry = "Portugal", + EmployeeDateBirthday = new DateTime(1996, 6, 4, 0, 0, 0, 0, DateTimeKind.Unspecified), + EmployeeDateRegistered = new DateTime(2023, 11, 21, 16, 32, 7, 771, DateTimeKind.Local).AddTicks(152), + EmployeeEmail = "luiscarvalho239@gmail.com", + EmployeeFirstName = "Luis", + EmployeeJob = "Programmer", + EmployeeLastName = "Carvalho", + EmployeeName = "admin", + EmployeePassword = "$2a$11$Qd678ylOMNtjqvoE6MjdyO1hZVZeJykAjN065x5drAKM7miGmhbuO", + EmployeePhoneNumber = "0123456789", + EmployeePin = "$2a$11$OPoXbRKU/e94Y8nCKN.OkO50/6U7Xp37ViGoo45cXmcjNp.MF9Lnu", + EmployeePostalAddress = "1234-567", + EmployeeRole = "Administrator", + EmployeeStateProvince = "", + EmployeeZipCode = "1234-567" + }); + }); + + modelBuilder.Entity("LCPApi.Models.Feedback", b => + { + b.Property("FeedbackId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("FeedbackId")); + + b.Property("CommentId") + .HasColumnType("int"); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("FeedbackAssignBy") + .HasColumnType("nvarchar(max)"); + + b.Property("FeedbackDateCreated") + .HasColumnType("datetime2"); + + b.Property("FeedbackDateLocked") + .HasColumnType("datetime2"); + + b.Property("FeedbackDateUpdated") + .HasColumnType("datetime2"); + + b.Property("FeedbackDownvotes") + .HasColumnType("int"); + + b.Property("FeedbackMsg") + .HasColumnType("nvarchar(max)"); + + b.Property("FeedbackStatus") + .HasColumnType("int"); + + b.Property("FeedbackTitle") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FeedbackUpvotes") + .HasColumnType("int"); + + b.Property("ProjectId") + .HasColumnType("int"); + + b.HasKey("FeedbackId"); + + b.ToTable("Feedbacks"); + }); + + modelBuilder.Entity("LCPApi.Models.FeedbackComment", b => + { + b.Property("FeedbackCommentId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("FeedbackCommentId")); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("FeedbackCommentDateCreated") + .HasColumnType("datetime2"); + + b.Property("FeedbackCommentDateLocked") + .HasColumnType("datetime2"); + + b.Property("FeedbackCommentDateUpdated") + .HasColumnType("datetime2"); + + b.Property("FeedbackCommentDownvotes") + .HasColumnType("int"); + + b.Property("FeedbackCommentMsg") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FeedbackCommentStatus") + .HasColumnType("int"); + + b.Property("FeedbackCommentUpvotes") + .HasColumnType("int"); + + b.Property("FeedbackId") + .HasColumnType("int"); + + b.Property("ProjectId") + .HasColumnType("int"); + + b.HasKey("FeedbackCommentId"); + + b.ToTable("FeedbacksComments"); + }); + + modelBuilder.Entity("LCPApi.Models.Order", b => + { + b.Property("OrderId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("OrderId")); + + b.Property("ItemDiscount") + .HasColumnType("float"); + + b.Property("ItemPrice") + .HasColumnType("float"); + + b.Property("ItemStock") + .HasColumnType("float"); + + b.Property("OrderDate") + .HasColumnType("datetime2"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("int"); + + b.HasKey("OrderId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("LCPApi.Models.OrderCustomer", b => + { + b.Property("OrderId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("OrderId")); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.HasKey("OrderId"); + + b.ToTable("OrdersCustomers"); + }); + + modelBuilder.Entity("LCPApi.Models.Product", b => + { + b.Property("ProductId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ProductId")); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("EmployeeId") + .HasColumnType("int"); + + b.Property("ProductDateCreated") + .HasColumnType("datetime2"); + + b.Property("ProductDateUpdated") + .HasColumnType("datetime2"); + + b.Property("ProductDesc") + .HasColumnType("nvarchar(max)"); + + b.Property("ProductGallery") + .HasColumnType("nvarchar(max)"); + + b.Property("ProductImageMain") + .HasColumnType("nvarchar(max)"); + + b.Property("ProductIsFeatured") + .HasColumnType("bit"); + + b.Property("ProductPrice") + .HasColumnType("float"); + + b.Property("ProductTitle") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("ProductId"); + + b.HasIndex("CustomerId"); + + b.HasIndex("EmployeeId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("LCPApi.Models.ProductProject", b => + { + b.Property("ProductId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ProductId")); + + b.Property("ProjectId") + .HasColumnType("int"); + + b.HasKey("ProductId"); + + b.ToTable("ProductsProjects"); + }); + + modelBuilder.Entity("LCPApi.Models.ProductSubscription", b => + { + b.Property("ProductId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ProductId")); + + b.Property("SubscriptionId") + .HasColumnType("int"); + + b.HasKey("ProductId"); + + b.ToTable("ProductsSubscriptions"); + }); + + modelBuilder.Entity("LCPApi.Models.Project", b => + { + b.Property("ProjectId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ProjectId")); + + b.Property("ProjectBudgetCost") + .HasColumnType("float"); + + b.Property("ProjectBudgetDays") + .HasColumnType("int"); + + b.Property("ProjectCategory") + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectCompany") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectDateClose") + .HasColumnType("datetime2"); + + b.Property("ProjectDateEnd") + .HasColumnType("datetime2"); + + b.Property("ProjectDateStart") + .HasColumnType("datetime2"); + + b.Property("ProjectDesc") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectOwner") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectPriority") + .HasColumnType("bit"); + + b.Property("ProjectRecords") + .HasColumnType("int"); + + b.Property("ProjectStatus") + .HasColumnType("int"); + + b.HasKey("ProjectId"); + + b.ToTable("Projects"); + }); + + modelBuilder.Entity("LCPApi.Models.ProjectPhase", b => + { + b.Property("ProjectPhaseId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ProjectPhaseId")); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("ProjectPhaseActivities") + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectPhaseDateEnd") + .HasColumnType("datetime2"); + + b.Property("ProjectPhaseDateStart") + .HasColumnType("datetime2"); + + b.Property("ProjectPhaseDesc") + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectPhaseName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectPhaseStatus") + .HasColumnType("int"); + + b.Property("TaskId") + .HasColumnType("int"); + + b.HasKey("ProjectPhaseId"); + + b.ToTable("ProjectsPhases"); + }); + + modelBuilder.Entity("LCPApi.Models.ProjectTask", b => + { + b.Property("ProjectTaskId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ProjectTaskId")); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("ProjectId") + .HasColumnType("int"); + + b.Property("ProjectTaskDesc") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectTaskDetails") + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectTaskDocument") + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectTaskEndDate") + .HasColumnType("datetime2"); + + b.Property("ProjectTaskName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectTaskOwner") + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectTaskPhaseName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectTaskPriority") + .HasColumnType("int"); + + b.Property("ProjectTaskProject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectTaskReviewDate") + .HasColumnType("datetime2"); + + b.Property("ProjectTaskReviewReport") + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectTaskStartDate") + .HasColumnType("datetime2"); + + b.Property("ProjectTaskStatus") + .HasColumnType("int"); + + b.Property("ProjectTaskTeam") + .HasColumnType("nvarchar(max)"); + + b.Property("ProjectTaskType") + .HasColumnType("nvarchar(max)"); + + b.HasKey("ProjectTaskId"); + + b.ToTable("ProjectTasks"); + }); + + modelBuilder.Entity("LCPApi.Models.ProjectTaskType", b => + { + b.Property("ProjectTaskTypeId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ProjectTaskTypeId")); + + b.Property("ProjectTaskId") + .HasColumnType("int"); + + b.Property("ProjectTaskTypeDesc") + .HasColumnType("nvarchar(max)"); + + b.HasKey("ProjectTaskTypeId"); + + b.ToTable("ProjectTasksTypes"); + }); + + modelBuilder.Entity("LCPApi.Models.Subscription", b => + { + b.Property("SubscriptionId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("SubscriptionId")); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("EmployeeId") + .HasColumnType("int"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("SubscriptionDateEnded") + .HasColumnType("datetime2"); + + b.Property("SubscriptionDatePurchased") + .HasColumnType("datetime2"); + + b.Property("SubscriptionDesc") + .HasColumnType("nvarchar(max)"); + + b.Property("SubscriptionImage") + .HasColumnType("nvarchar(max)"); + + b.Property("SubscriptionIsExpired") + .HasColumnType("bit"); + + b.Property("SubscriptionTitle") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SubscriptionType") + .HasColumnType("nvarchar(max)"); + + b.HasKey("SubscriptionId"); + + b.ToTable("Subscriptions"); + }); + + modelBuilder.Entity("LCPApi.Models.SubscriptionKey", b => + { + b.Property("SubscriptionKeyId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("SubscriptionKeyId")); + + b.Property("SubscriptionId") + .HasColumnType("int"); + + b.Property("SubscriptionKeyDateEnd") + .HasColumnType("datetime2"); + + b.Property("SubscriptionKeyDateStart") + .HasColumnType("datetime2"); + + b.Property("SubscriptionKeyDateUpdated") + .HasColumnType("datetime2"); + + b.Property("SubscriptionKeyStatus") + .HasColumnType("int"); + + b.Property("SubscriptionKeyValue") + .HasColumnType("nvarchar(max)"); + + b.HasKey("SubscriptionKeyId"); + + b.ToTable("SubscriptionsKeys"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasColumnType("nvarchar(max)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasColumnType("nvarchar(max)"); + + b.Property("NormalizedUserName") + .HasColumnType("nvarchar(max)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("AspNetUsers", null, t => + { + t.ExcludeFromMigrations(); + }); + }); + + modelBuilder.Entity("LCPApi.Models.Product", b => + { + b.HasOne("LCPApi.Models.Customer", "Customers") + .WithMany("Products") + .HasForeignKey("CustomerId"); + + b.HasOne("LCPApi.Models.Employee", "Employees") + .WithMany("Products") + .HasForeignKey("EmployeeId"); + + b.Navigation("Customers"); + + b.Navigation("Employees"); + }); + + modelBuilder.Entity("LCPApi.Models.Customer", b => + { + b.Navigation("Products"); + }); + + modelBuilder.Entity("LCPApi.Models.Employee", b => + { + b.Navigation("Products"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/api/LCPApi/Migrations/20231121163209_InitialCreate.cs b/backend/api/LCPApi/Migrations/20231121163209_InitialCreate.cs new file mode 100644 index 0000000..df8eeaa --- /dev/null +++ b/backend/api/LCPApi/Migrations/20231121163209_InitialCreate.cs @@ -0,0 +1,436 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace LCPApi.Migrations +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Categories", + columns: table => new + { + CategoryId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + CategoryDesc = table.Column(type: "nvarchar(max)", nullable: true), + ProjectId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Categories", x => x.CategoryId); + }); + + migrationBuilder.CreateTable( + name: "Customers", + columns: table => new + { + CustomerId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + CustomerName = table.Column(type: "nvarchar(max)", nullable: false), + CustomerPassword = table.Column(type: "varchar(MAX)", nullable: false), + CustomerRole = table.Column(type: "nvarchar(max)", nullable: true), + CustomerEmail = table.Column(type: "nvarchar(max)", nullable: true), + CustomerPin = table.Column(type: "varchar(MAX)", maxLength: 4, nullable: true), + CustomerFirstName = table.Column(type: "nvarchar(max)", nullable: true), + CustomerLastName = table.Column(type: "nvarchar(max)", nullable: true), + CustomerJob = table.Column(type: "nvarchar(max)", nullable: true), + CustomerDateBirthday = table.Column(type: "datetime2", nullable: true), + CustomerDateRegistered = table.Column(type: "datetime2", nullable: true), + CustomerCountry = table.Column(type: "nvarchar(max)", nullable: true), + CustomerPhoneNumber = table.Column(type: "nvarchar(max)", nullable: true), + CustomerPostalAddress = table.Column(type: "nvarchar(max)", nullable: true), + CustomerCity = table.Column(type: "nvarchar(max)", nullable: true), + CustomerZipCode = table.Column(type: "nvarchar(max)", nullable: true), + CustomerStateProvince = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Customers", x => x.CustomerId); + }); + + migrationBuilder.CreateTable( + name: "Departments", + columns: table => new + { + DepartmentId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + DepartmentName = table.Column(type: "nvarchar(max)", nullable: false), + DepartmentType = table.Column(type: "nvarchar(max)", nullable: true), + DepartmentDesc = table.Column(type: "nvarchar(max)", nullable: true), + ProjectId = table.Column(type: "int", nullable: true), + EmployeeId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Departments", x => x.DepartmentId); + }); + + migrationBuilder.CreateTable( + name: "Employees", + columns: table => new + { + EmployeeId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1000, 1"), + EmployeeName = table.Column(type: "nvarchar(max)", nullable: false), + EmployeePassword = table.Column(type: "varchar(MAX)", nullable: false), + EmployeeRole = table.Column(type: "nvarchar(max)", nullable: true), + EmployeeEmail = table.Column(type: "nvarchar(max)", nullable: true), + EmployeePin = table.Column(type: "varchar(MAX)", maxLength: 4, nullable: true), + EmployeeFirstName = table.Column(type: "nvarchar(max)", nullable: true), + EmployeeLastName = table.Column(type: "nvarchar(max)", nullable: true), + EmployeeJob = table.Column(type: "nvarchar(max)", nullable: true), + EmployeeDateBirthday = table.Column(type: "datetime2", nullable: true), + EmployeeDateRegistered = table.Column(type: "datetime2", nullable: true), + EmployeeCountry = table.Column(type: "nvarchar(max)", nullable: true), + EmployeePhoneNumber = table.Column(type: "nvarchar(max)", nullable: true), + EmployeePostalAddress = table.Column(type: "nvarchar(max)", nullable: true), + EmployeeCity = table.Column(type: "nvarchar(max)", nullable: true), + EmployeeZipCode = table.Column(type: "nvarchar(max)", nullable: true), + EmployeeStateProvince = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Employees", x => x.EmployeeId); + }); + + migrationBuilder.CreateTable( + name: "Feedbacks", + columns: table => new + { + FeedbackId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + FeedbackTitle = table.Column(type: "nvarchar(max)", nullable: false), + FeedbackMsg = table.Column(type: "nvarchar(max)", nullable: true), + FeedbackStatus = table.Column(type: "int", nullable: true), + FeedbackDateCreated = table.Column(type: "datetime2", nullable: true), + FeedbackDateUpdated = table.Column(type: "datetime2", nullable: true), + FeedbackDateLocked = table.Column(type: "datetime2", nullable: true), + FeedbackAssignBy = table.Column(type: "nvarchar(max)", nullable: true), + FeedbackUpvotes = table.Column(type: "int", nullable: true), + FeedbackDownvotes = table.Column(type: "int", nullable: true), + CustomerId = table.Column(type: "int", nullable: true), + ProjectId = table.Column(type: "int", nullable: true), + CommentId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Feedbacks", x => x.FeedbackId); + }); + + migrationBuilder.CreateTable( + name: "FeedbacksComments", + columns: table => new + { + FeedbackCommentId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + FeedbackCommentMsg = table.Column(type: "nvarchar(max)", nullable: false), + FeedbackCommentUpvotes = table.Column(type: "int", nullable: true), + FeedbackCommentDownvotes = table.Column(type: "int", nullable: true), + FeedbackCommentStatus = table.Column(type: "int", nullable: true), + FeedbackCommentDateCreated = table.Column(type: "datetime2", nullable: true), + FeedbackCommentDateUpdated = table.Column(type: "datetime2", nullable: true), + FeedbackCommentDateLocked = table.Column(type: "datetime2", nullable: true), + FeedbackId = table.Column(type: "int", nullable: true), + CustomerId = table.Column(type: "int", nullable: true), + ProjectId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_FeedbacksComments", x => x.FeedbackCommentId); + }); + + migrationBuilder.CreateTable( + name: "Orders", + columns: table => new + { + OrderId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Quantity = table.Column(type: "int", nullable: false), + OrderDate = table.Column(type: "datetime2", nullable: false), + ItemPrice = table.Column(type: "float", nullable: false), + ItemDiscount = table.Column(type: "float", nullable: false), + ItemStock = table.Column(type: "float", nullable: false), + ProductId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Orders", x => x.OrderId); + }); + + migrationBuilder.CreateTable( + name: "OrdersCustomers", + columns: table => new + { + OrderId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + CustomerId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_OrdersCustomers", x => x.OrderId); + }); + + migrationBuilder.CreateTable( + name: "ProductsProjects", + columns: table => new + { + ProductId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + ProjectId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_ProductsProjects", x => x.ProductId); + }); + + migrationBuilder.CreateTable( + name: "ProductsSubscriptions", + columns: table => new + { + ProductId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + SubscriptionId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_ProductsSubscriptions", x => x.ProductId); + }); + + migrationBuilder.CreateTable( + name: "Projects", + columns: table => new + { + ProjectId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + ProjectName = table.Column(type: "nvarchar(max)", nullable: false), + ProjectDesc = table.Column(type: "nvarchar(max)", nullable: false), + ProjectCompany = table.Column(type: "nvarchar(max)", nullable: false), + ProjectOwner = table.Column(type: "nvarchar(max)", nullable: false), + ProjectCategory = table.Column(type: "nvarchar(max)", nullable: true), + ProjectPriority = table.Column(type: "bit", nullable: true), + ProjectStatus = table.Column(type: "int", nullable: true), + ProjectDateStart = table.Column(type: "datetime2", nullable: true), + ProjectDateEnd = table.Column(type: "datetime2", nullable: true), + ProjectDateClose = table.Column(type: "datetime2", nullable: true), + ProjectBudgetDays = table.Column(type: "int", nullable: true), + ProjectBudgetCost = table.Column(type: "float", nullable: true), + ProjectRecords = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Projects", x => x.ProjectId); + }); + + migrationBuilder.CreateTable( + name: "ProjectsPhases", + columns: table => new + { + ProjectPhaseId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + ProjectPhaseName = table.Column(type: "nvarchar(max)", nullable: false), + ProjectPhaseDesc = table.Column(type: "nvarchar(max)", nullable: true), + ProjectPhaseStatus = table.Column(type: "int", nullable: true), + ProjectPhaseDateStart = table.Column(type: "datetime2", nullable: true), + ProjectPhaseDateEnd = table.Column(type: "datetime2", nullable: true), + ProjectPhaseActivities = table.Column(type: "nvarchar(max)", nullable: true), + TaskId = table.Column(type: "int", nullable: true), + CategoryId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_ProjectsPhases", x => x.ProjectPhaseId); + }); + + migrationBuilder.CreateTable( + name: "ProjectTasks", + columns: table => new + { + ProjectTaskId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + ProjectTaskName = table.Column(type: "nvarchar(max)", nullable: false), + ProjectTaskDesc = table.Column(type: "nvarchar(max)", nullable: false), + ProjectTaskProject = table.Column(type: "nvarchar(max)", nullable: false), + ProjectTaskPhaseName = table.Column(type: "nvarchar(max)", nullable: false), + ProjectTaskStatus = table.Column(type: "int", nullable: false), + ProjectTaskOwner = table.Column(type: "nvarchar(max)", nullable: true), + ProjectTaskType = table.Column(type: "nvarchar(max)", nullable: true), + ProjectTaskPriority = table.Column(type: "int", nullable: true), + ProjectTaskStartDate = table.Column(type: "datetime2", nullable: true), + ProjectTaskEndDate = table.Column(type: "datetime2", nullable: true), + ProjectTaskTeam = table.Column(type: "nvarchar(max)", nullable: true), + ProjectTaskReviewDate = table.Column(type: "datetime2", nullable: true), + ProjectTaskReviewReport = table.Column(type: "nvarchar(max)", nullable: true), + ProjectTaskDocument = table.Column(type: "nvarchar(max)", nullable: true), + ProjectTaskDetails = table.Column(type: "nvarchar(max)", nullable: true), + ProjectId = table.Column(type: "int", nullable: true), + CategoryId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_ProjectTasks", x => x.ProjectTaskId); + }); + + migrationBuilder.CreateTable( + name: "ProjectTasksTypes", + columns: table => new + { + ProjectTaskTypeId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + ProjectTaskTypeDesc = table.Column(type: "nvarchar(max)", nullable: true), + ProjectTaskId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_ProjectTasksTypes", x => x.ProjectTaskTypeId); + }); + + migrationBuilder.CreateTable( + name: "Subscriptions", + columns: table => new + { + SubscriptionId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + SubscriptionTitle = table.Column(type: "nvarchar(max)", nullable: false), + SubscriptionDesc = table.Column(type: "nvarchar(max)", nullable: true), + SubscriptionType = table.Column(type: "nvarchar(max)", nullable: true), + SubscriptionImage = table.Column(type: "nvarchar(max)", nullable: true), + SubscriptionDatePurchased = table.Column(type: "datetime2", nullable: true), + SubscriptionDateEnded = table.Column(type: "datetime2", nullable: true), + SubscriptionIsExpired = table.Column(type: "bit", nullable: true), + CustomerId = table.Column(type: "int", nullable: true), + EmployeeId = table.Column(type: "int", nullable: true), + ProductId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Subscriptions", x => x.SubscriptionId); + }); + + migrationBuilder.CreateTable( + name: "SubscriptionsKeys", + columns: table => new + { + SubscriptionKeyId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + SubscriptionKeyValue = table.Column(type: "nvarchar(max)", nullable: true), + SubscriptionKeyDateStart = table.Column(type: "datetime2", nullable: true), + SubscriptionKeyDateEnd = table.Column(type: "datetime2", nullable: true), + SubscriptionKeyDateUpdated = table.Column(type: "datetime2", nullable: true), + SubscriptionKeyStatus = table.Column(type: "int", nullable: true), + SubscriptionId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_SubscriptionsKeys", x => x.SubscriptionKeyId); + }); + + migrationBuilder.CreateTable( + name: "Products", + columns: table => new + { + ProductId = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + ProductTitle = table.Column(type: "nvarchar(max)", nullable: false), + ProductType = table.Column(type: "nvarchar(max)", nullable: false), + ProductDesc = table.Column(type: "nvarchar(max)", nullable: true), + ProductPrice = table.Column(type: "float", nullable: true), + ProductImageMain = table.Column(type: "nvarchar(max)", nullable: true), + ProductGallery = table.Column(type: "nvarchar(max)", nullable: true), + ProductIsFeatured = table.Column(type: "bit", nullable: true), + ProductDateCreated = table.Column(type: "datetime2", nullable: true), + ProductDateUpdated = table.Column(type: "datetime2", nullable: true), + CustomerId = table.Column(type: "int", nullable: true), + EmployeeId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Products", x => x.ProductId); + table.ForeignKey( + name: "FK_Products_Customers_CustomerId", + column: x => x.CustomerId, + principalTable: "Customers", + principalColumn: "CustomerId"); + table.ForeignKey( + name: "FK_Products_Employees_EmployeeId", + column: x => x.EmployeeId, + principalTable: "Employees", + principalColumn: "EmployeeId"); + }); + + migrationBuilder.InsertData( + table: "Employees", + columns: new[] { "EmployeeId", "EmployeeCity", "EmployeeCountry", "EmployeeDateBirthday", "EmployeeDateRegistered", "EmployeeEmail", "EmployeeFirstName", "EmployeeJob", "EmployeeLastName", "EmployeeName", "EmployeePassword", "EmployeePhoneNumber", "EmployeePin", "EmployeePostalAddress", "EmployeeRole", "EmployeeStateProvince", "EmployeeZipCode" }, + values: new object[] { 1001, "Braga", "Portugal", new DateTime(1996, 6, 4, 0, 0, 0, 0, DateTimeKind.Unspecified), new DateTime(2023, 11, 21, 16, 32, 7, 771, DateTimeKind.Local).AddTicks(152), "luiscarvalho239@gmail.com", "Luis", "Programmer", "Carvalho", "admin", "$2a$11$Qd678ylOMNtjqvoE6MjdyO1hZVZeJykAjN065x5drAKM7miGmhbuO", "0123456789", "$2a$11$OPoXbRKU/e94Y8nCKN.OkO50/6U7Xp37ViGoo45cXmcjNp.MF9Lnu", "1234-567", "Administrator", "", "1234-567" }); + + migrationBuilder.CreateIndex( + name: "IX_Products_CustomerId", + table: "Products", + column: "CustomerId"); + + migrationBuilder.CreateIndex( + name: "IX_Products_EmployeeId", + table: "Products", + column: "EmployeeId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Categories"); + + migrationBuilder.DropTable( + name: "Departments"); + + migrationBuilder.DropTable( + name: "Feedbacks"); + + migrationBuilder.DropTable( + name: "FeedbacksComments"); + + migrationBuilder.DropTable( + name: "Orders"); + + migrationBuilder.DropTable( + name: "OrdersCustomers"); + + migrationBuilder.DropTable( + name: "Products"); + + migrationBuilder.DropTable( + name: "ProductsProjects"); + + migrationBuilder.DropTable( + name: "ProductsSubscriptions"); + + migrationBuilder.DropTable( + name: "Projects"); + + migrationBuilder.DropTable( + name: "ProjectsPhases"); + + migrationBuilder.DropTable( + name: "ProjectTasks"); + + migrationBuilder.DropTable( + name: "ProjectTasksTypes"); + + migrationBuilder.DropTable( + name: "Subscriptions"); + + migrationBuilder.DropTable( + name: "SubscriptionsKeys"); + + migrationBuilder.DropTable( + name: "Customers"); + + migrationBuilder.DropTable( + name: "Employees"); + } + } +} diff --git a/backend/api/LCPApi/Migrations/DBContextModelSnapshot.cs b/backend/api/LCPApi/Migrations/DBContextModelSnapshot.cs index 3ef49ab..f13e1c3 100644 --- a/backend/api/LCPApi/Migrations/DBContextModelSnapshot.cs +++ b/backend/api/LCPApi/Migrations/DBContextModelSnapshot.cs @@ -79,13 +79,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("CustomerPassword") .IsRequired() - .HasColumnType("nvarchar(max)"); + .HasColumnType("varchar(MAX)"); b.Property("CustomerPhoneNumber") .HasColumnType("nvarchar(max)"); - b.Property("CustomerPin") - .HasColumnType("int"); + b.Property("CustomerPin") + .HasMaxLength(4) + .HasColumnType("varchar(MAX)"); b.Property("CustomerPostalAddress") .HasColumnType("nvarchar(max)"); @@ -139,7 +140,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("int"); - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("EmployeeId")); + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("EmployeeId"), 1000L); b.Property("EmployeeCity") .HasColumnType("nvarchar(max)"); @@ -171,13 +172,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("EmployeePassword") .IsRequired() - .HasColumnType("nvarchar(max)"); + .HasColumnType("varchar(MAX)"); b.Property("EmployeePhoneNumber") .HasColumnType("nvarchar(max)"); - b.Property("EmployeePin") - .HasColumnType("int"); + b.Property("EmployeePin") + .HasMaxLength(4) + .HasColumnType("varchar(MAX)"); b.Property("EmployeePostalAddress") .HasColumnType("nvarchar(max)"); @@ -193,7 +195,29 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("EmployeeId"); - b.ToTable("Employees"); + b.ToTable("Employees", (string)null); + + b.HasData( + new + { + EmployeeId = 1001, + EmployeeCity = "Braga", + EmployeeCountry = "Portugal", + EmployeeDateBirthday = new DateTime(1996, 6, 4, 0, 0, 0, 0, DateTimeKind.Unspecified), + EmployeeDateRegistered = new DateTime(2023, 11, 21, 16, 32, 7, 771, DateTimeKind.Local).AddTicks(152), + EmployeeEmail = "luiscarvalho239@gmail.com", + EmployeeFirstName = "Luis", + EmployeeJob = "Programmer", + EmployeeLastName = "Carvalho", + EmployeeName = "admin", + EmployeePassword = "$2a$11$Qd678ylOMNtjqvoE6MjdyO1hZVZeJykAjN065x5drAKM7miGmhbuO", + EmployeePhoneNumber = "0123456789", + EmployeePin = "$2a$11$OPoXbRKU/e94Y8nCKN.OkO50/6U7Xp37ViGoo45cXmcjNp.MF9Lnu", + EmployeePostalAddress = "1234-567", + EmployeeRole = "Administrator", + EmployeeStateProvince = "", + EmployeeZipCode = "1234-567" + }); }); modelBuilder.Entity("LCPApi.Models.Feedback", b => diff --git a/backend/api/LCPApi/Models/customer.cs b/backend/api/LCPApi/Models/customer.cs index ebc8fef..1466daf 100644 --- a/backend/api/LCPApi/Models/customer.cs +++ b/backend/api/LCPApi/Models/customer.cs @@ -8,10 +8,14 @@ public class Customer { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int CustomerId { get; set; } public string CustomerName { get; set; } = null!; + [Column(TypeName = "varchar(MAX)")] public string CustomerPassword { get; set; } = null!; public string? CustomerRole { get; set; } public string? CustomerEmail { get; set; } - public int? CustomerPin { get; set; } + [RegularExpression(@"^[0-9]+$", ErrorMessage = "Please enter a valid number.")] + [MaxLength(4, ErrorMessage = "The pin has been reached at max of 4 numbers!")] + [Column(TypeName = "varchar(MAX)")] + public string? CustomerPin { get; set; } public string? CustomerFirstName { get; set; } public string? CustomerLastName { get; set; } public string? CustomerJob { get; set; } diff --git a/backend/api/LCPApi/Models/employee.cs b/backend/api/LCPApi/Models/employee.cs index 1927b16..acd1e1c 100644 --- a/backend/api/LCPApi/Models/employee.cs +++ b/backend/api/LCPApi/Models/employee.cs @@ -8,10 +8,14 @@ public class Employee { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int EmployeeId { get; set; } public string EmployeeName { get; set; } = null!; + [Column(TypeName = "varchar(MAX)")] public string EmployeePassword { get; set; } = null!; public string? EmployeeRole { get; set; } public string? EmployeeEmail { get; set; } - public int? EmployeePin { get; set; } + [RegularExpression(@"^[0-9]+$", ErrorMessage = "Please enter a valid number.")] + [MaxLength(4, ErrorMessage = "The pin has been reached at max of 4 numbers!")] + [Column(TypeName = "varchar(MAX)")] + public string? EmployeePin { get; set; } public string? EmployeeFirstName { get; set; } public string? EmployeeLastName { get; set; } public string? EmployeeJob { get; set; } diff --git a/backend/api/LCPApi/Program.cs b/backend/api/LCPApi/Program.cs index a34a712..07da74c 100644 --- a/backend/api/LCPApi/Program.cs +++ b/backend/api/LCPApi/Program.cs @@ -2,16 +2,13 @@ using System.Text.Json.Serialization; using LCPApi.Context; using LCPApi.Interfaces; -using LCPApi.Models; using LCPApi.Repositories; -using LCPApi.Functions; using LCPApi.Enums; -using Microsoft.AspNetCore.Authorization; +using LCPApi.Hubs; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using Microsoft.AspNetCore.Authentication.JwtBearer; using Serilog; -using Swashbuckle.AspNetCore.Annotations; var builder = WebApplication.CreateBuilder(args); @@ -73,6 +70,7 @@ options.AddPolicy("EditorsOnly", policy => policy.RequireRole(ENRoles.Editor.ToString())); options.AddPolicy("ModeratorsOnly", policy => policy.RequireRole(ENRoles.Moderator.ToString())); options.AddPolicy("AdminsOnly", policy => policy.RequireRole(ENRoles.Administrator.ToString())); + options.AddPolicy("StaffOnly", policy => policy.RequireRole(ENRoles.Administrator.ToString(), ENRoles.Moderator.ToString())); options.AddPolicy("AllRights", policy => policy.RequireRole(ENRoles.Guest.ToString(), ENRoles.User.ToString(), ENRoles.Customer.ToString(), ENRoles.Employee.ToString(), ENRoles.Editor.ToString(), ENRoles.Moderator.ToString(), ENRoles.Administrator.ToString())); }); @@ -121,6 +119,7 @@ }); builder.Services.Configure(options => options.LowercaseUrls = true); +builder.Services.AddSignalR(); var app = builder.Build(); @@ -137,14 +136,12 @@ } app.UseHttpsRedirection(); - app.UseRouting(); - -app.MapPost("/api/auth/login", [AllowAnonymous] (UserAuth userauth) => AuthFunctions.GenToken(builder, userauth)).WithTags("Auth").WithMetadata(new SwaggerOperationAttribute("Login", "Login")); - +app.UseStaticFiles(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); +app.MapHub("/dataHub"); app.Run(); diff --git a/backend/api/LCPApi/Repositories/RCustomer.cs b/backend/api/LCPApi/Repositories/RCustomer.cs index 7ebefbd..529ad0e 100644 --- a/backend/api/LCPApi/Repositories/RCustomer.cs +++ b/backend/api/LCPApi/Repositories/RCustomer.cs @@ -3,6 +3,7 @@ using LCPApi.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using BC = BCrypt.Net.BCrypt; namespace LCPApi.Repositories; @@ -47,6 +48,14 @@ public async Task PutCustomer(int id, Customer Customer) return BadRequest(); } + if(!string.IsNullOrEmpty(Customer.CustomerPassword)) { + Customer.CustomerPassword = BC.HashPassword(Customer.CustomerPassword); + } + + if(!string.IsNullOrEmpty(Customer.CustomerPin)) { + Customer.CustomerPin = BC.HashPassword(Customer.CustomerPin); + } + _context.Entry(Customer).State = EntityState.Modified; try @@ -69,11 +78,15 @@ public async Task PutCustomer(int id, Customer Customer) } public async Task> PostCustomer(Customer Customer) - { + { if (_context.Customers == null) { return Problem("Entity set 'DBContext.Customers' is null."); } + + Customer.CustomerPassword = BC.HashPassword(Customer.CustomerPassword); + Customer.CustomerPin = BC.HashPassword(Customer.CustomerPin); + _context.Customers.Add(Customer); await _context.SaveChangesAsync(); diff --git a/backend/api/LCPApi/Repositories/REmployee.cs b/backend/api/LCPApi/Repositories/REmployee.cs index 50732e1..3abcc24 100644 --- a/backend/api/LCPApi/Repositories/REmployee.cs +++ b/backend/api/LCPApi/Repositories/REmployee.cs @@ -3,6 +3,7 @@ using LCPApi.Context; using LCPApi.Models; using LCPApi.Interfaces; +using BC = BCrypt.Net.BCrypt; namespace LCPApi.Repositories; @@ -47,6 +48,14 @@ public async Task PutEmployee(int id, Employee Employee) return BadRequest(); } + if(!string.IsNullOrEmpty(Employee.EmployeePassword)) { + Employee.EmployeePassword = BC.HashPassword(Employee.EmployeePassword); + } + + if(!string.IsNullOrEmpty(Employee.EmployeePin)) { + Employee.EmployeePin = BC.HashPassword(Employee.EmployeePin); + } + _context.Entry(Employee).State = EntityState.Modified; try @@ -74,6 +83,10 @@ public async Task> PostEmployee(Employee Employee) { return Problem("Entity set 'DBContext.Employees' is null."); } + + Employee.EmployeePassword = BC.HashPassword(Employee.EmployeePassword); + Employee.EmployeePin = BC.HashPassword(Employee.EmployeePin); + _context.Employees.Add(Employee); await _context.SaveChangesAsync(); diff --git a/backend/api/LCPApi/Scripts/installdeps.sh b/backend/api/LCPApi/Scripts/installdeps.sh index f9fd8e2..a5f6594 100644 --- a/backend/api/LCPApi/Scripts/installdeps.sh +++ b/backend/api/LCPApi/Scripts/installdeps.sh @@ -15,5 +15,6 @@ dotnet add package Serilog dotnet add package Serilog.Sinks.Console dotnet add package Serilog.Sinks.File dotnet add package Serilog.AspNetCore +libman install @microsoft/signalr@latest -p unpkg -d wwwroot/js/signalr --files dist/browser/signalr.js exit \ No newline at end of file diff --git a/backend/api/LCPApi/Scripts/updatedb.sh b/backend/api/LCPApi/Scripts/updatedb.sh index 260fda2..d51f9c9 100644 --- a/backend/api/LCPApi/Scripts/updatedb.sh +++ b/backend/api/LCPApi/Scripts/updatedb.sh @@ -3,19 +3,20 @@ # src: https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli # dotnet tool install --global dotnet-ef -# myusername=$(whoami) +clear -# if [ -e "C:\\Users\\$myusername\\LCPDB.mdf" ] then -# rm -rf "C:\\Users\\$myusername\\LCPDB.mdf" -# end +myusername=$(whoami) -# if [ -e "C:\\Users\\$myusername\\LCPDB_log.ldf" ] then -# rm -rf "C:\\Users\\$myusername\\LCPDB_log.ldf" -# end +if [[ -e "C:\\Users\\$myusername\\LCPDB.mdf" ]]; then + rm -f "C:\\Users\\$myusername\\LCPDB.mdf" +fi -dotnet tool update --global dotnet-ef +if [[ -e "C:\\Users\\$myusername\\LCPDB_log.ldf" ]]; then + rm -f "C:\\Users\\$myusername\\LCPDB_log.ldf" +fi -cd ".." +cd .. +dotnet tool update --global dotnet-ef dotnet ef database drop --force dotnet ef migrations remove --force dotnet ef migrations add InitialCreate diff --git a/backend/api/LCPApi/appsettings.Development.json b/backend/api/LCPApi/appsettings.Development.json index 7fcc8f9..652a783 100644 --- a/backend/api/LCPApi/appsettings.Development.json +++ b/backend/api/LCPApi/appsettings.Development.json @@ -5,6 +5,7 @@ "Microsoft.AspNetCore": "Warning" } }, + "AllowedHosts": "*", "defaultDBMode": "SQL Server", "ConnectionStrings": { "LCPDBSqlServer": "Server=(localdb)\\mssqllocaldb;Database=LCPDB;Trusted_Connection=True", @@ -21,25 +22,36 @@ "userpass": "Kw@?7t3z704M6-6B92XG" }, "Serilog": { - "Using": [ "Serilog.Sinks.File", "Serilog.Sinks.Console" ], + "Using": [ + "Serilog.Sinks.File", + "Serilog.Sinks.Console" + ], "MinimumLevel": { "Default": "Information" }, "WriteTo": [ { - "Name": "File", + "Name": "Async", "Args": { - "path": "./logs/lcpapi-.log", - "rollingInterval": "Day", - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {CorrelationId} {Level:u3} {Username} {Message:lj}{Exception}{NewLine}" - } - }, - { - "Name": "Console", - "Args": { - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] {Message}{NewLine}{Exception}" + "configure": [ + { + "Name": "File", + "Args": { + "path": "./logs/lcpapi-.log", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {CorrelationId} {Level:u3} {Username} {Message:lj}{Exception}{NewLine}" + } + }, + { + "Name": "Console", + "Args": { + "theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] {Message}{NewLine}{Exception}" + } + } + ] } } ] } -} +} \ No newline at end of file diff --git a/backend/api/LCPApi/appsettings.json b/backend/api/LCPApi/appsettings.json index 7b2f69c..652a783 100644 --- a/backend/api/LCPApi/appsettings.json +++ b/backend/api/LCPApi/appsettings.json @@ -22,25 +22,36 @@ "userpass": "Kw@?7t3z704M6-6B92XG" }, "Serilog": { - "Using": [ "Serilog.Sinks.File", "Serilog.Sinks.Console" ], + "Using": [ + "Serilog.Sinks.File", + "Serilog.Sinks.Console" + ], "MinimumLevel": { "Default": "Information" }, "WriteTo": [ { - "Name": "File", + "Name": "Async", "Args": { - "path": "./logs/lcpapi-.log", - "rollingInterval": "Day", - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {CorrelationId} {Level:u3} {Username} {Message:lj}{Exception}{NewLine}" - } - }, - { - "Name": "Console", - "Args": { - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] {Message}{NewLine}{Exception}" + "configure": [ + { + "Name": "File", + "Args": { + "path": "./logs/lcpapi-.log", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {CorrelationId} {Level:u3} {Username} {Message:lj}{Exception}{NewLine}" + } + }, + { + "Name": "Console", + "Args": { + "theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] {Message}{NewLine}{Exception}" + } + } + ] } } ] } -} +} \ No newline at end of file diff --git a/backend/api/LCPApi/libman.json b/backend/api/LCPApi/libman.json new file mode 100644 index 0000000..8b3379b --- /dev/null +++ b/backend/api/LCPApi/libman.json @@ -0,0 +1,13 @@ +{ + "version": "1.0", + "defaultProvider": "unpkg", + "libraries": [ + { + "library": "@microsoft/signalr@latest", + "destination": "wwwroot/js/signalr", + "files": [ + "dist/browser/signalr.js" + ] + } + ] +} \ No newline at end of file