| @@ -10,5 +10,4 @@ public sealed class MapperProfile : Profile | |||
| { | |||
| CreateMap<Message, MessageDto>().ReverseMap(); | |||
| } | |||
| } | |||
| @@ -1,5 +1,4 @@ | |||
| using System.Reflection.Metadata; | |||
| using AutoMapper; | |||
| using AutoMapper; | |||
| using Microsoft.EntityFrameworkCore; | |||
| using SecureSharing.Business.Dtos; | |||
| using SecureSharing.Business.Infrastructure; | |||
| @@ -44,7 +43,7 @@ public sealed class MessageService : IMessageService | |||
| var toReturn = result.Select(x => x.Code).ToList(); | |||
| _dbContext.RemoveRange(result); | |||
| await _dbContext.SaveChangesAsync(); | |||
| return toReturn; | |||
| } | |||
| @@ -55,22 +54,14 @@ public sealed class MessageService : IMessageService | |||
| await _dbContext.SaveChangesAsync(); | |||
| } | |||
| private void DeleteFiles(Guid basePathGuid) | |||
| { | |||
| // TODO: this path needs to be extracted somehow. | |||
| var basePath = Path.Combine(@"D:\secure-sharing\SecureSharing\wwwroot\files", basePathGuid.ToString()); | |||
| Directory.Delete(basePath, true); | |||
| } | |||
| public async Task<bool> Delete(int id) | |||
| { | |||
| var messageDto = await GetById(id); | |||
| if (messageDto is null) | |||
| if (messageDto is null) | |||
| return false; | |||
| DeleteFiles(messageDto.Code); | |||
| _dbContext.Messages.Remove(_mapper.Map<Message>(messageDto)); | |||
| try | |||
| { | |||
| @@ -94,21 +85,31 @@ public sealed class MessageService : IMessageService | |||
| public async Task<MessageDto> GetById(int messageId) | |||
| { | |||
| var result = await _dbContext.Messages.Include(x=>x.FileNames).AsNoTracking().FirstOrDefaultAsync(x => x.Id == messageId); | |||
| var result = await _dbContext.Messages.Include(x => x.FileNames).AsNoTracking() | |||
| .FirstOrDefaultAsync(x => x.Id == messageId); | |||
| var mappedResult = _mapper.Map<MessageDto>(result); | |||
| return mappedResult; | |||
| } | |||
| public async Task<MessageDto> GetByCode(Guid code) | |||
| { | |||
| var result = await _dbContext.Messages.Include(x=>x.FileNames).AsNoTracking().FirstOrDefaultAsync(x => x.Code == code.ToString()); | |||
| var result = await _dbContext.Messages.Include(x => x.FileNames).AsNoTracking() | |||
| .FirstOrDefaultAsync(x => x.Code == code.ToString()); | |||
| var mappedResult = _mapper.Map<MessageDto>(result); | |||
| return mappedResult; | |||
| } | |||
| public async Task Update(MessageDto messageDto) | |||
| { | |||
| var a = _dbContext.Messages.Update(_mapper.Map<Message>(messageDto)); | |||
| await _dbContext.SaveChangesAsync(); | |||
| } | |||
| private void DeleteFiles(Guid basePathGuid) | |||
| { | |||
| // TODO: this path needs to be extracted somehow. | |||
| var basePath = Path.Combine(@"D:\secure-sharing\SecureSharing\wwwroot\files", basePathGuid.ToString()); | |||
| Directory.Delete(basePath, true); | |||
| } | |||
| } | |||
| @@ -8,21 +8,21 @@ | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="AutoMapper" Version="11.0.1" /> | |||
| <PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="6.0.9" /> | |||
| <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.9" /> | |||
| <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.9" /> | |||
| <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.9" /> | |||
| <PackageReference Include="AutoMapper" Version="11.0.1"/> | |||
| <PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="6.0.9"/> | |||
| <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.9"/> | |||
| <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.9"/> | |||
| <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.9"/> | |||
| <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.9"> | |||
| <PrivateAssets>all</PrivateAssets> | |||
| <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | |||
| </PackageReference> | |||
| <PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" /> | |||
| <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" /> | |||
| <PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1"/> | |||
| <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0"/> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <Folder Include="Migrations" /> | |||
| <Folder Include="Migrations"/> | |||
| </ItemGroup> | |||
| </Project> | |||
| @@ -1,7 +1,6 @@ | |||
| using Microsoft.AspNetCore.Authorization; | |||
| using Microsoft.AspNetCore.Mvc; | |||
| using Microsoft.AspNetCore.StaticFiles; | |||
| using Org.BouncyCastle.Ocsp; | |||
| using SecureSharing.Business.Dtos; | |||
| using SecureSharing.Business.Interfaces; | |||
| using SecureSharing.Data.Data; | |||
| @@ -13,14 +12,15 @@ namespace SecureSharing.Controllers; | |||
| [Authorize] | |||
| public sealed class HomeController : Controller | |||
| { | |||
| private const string DefaultPath = "files"; | |||
| private const string DefaultPathTmp = "filestmp"; | |||
| private readonly ILogger<HomeController> _logger; | |||
| private readonly IMessageService _messageService; | |||
| private readonly IModelFactory _modelFactory; | |||
| private readonly IWebHostEnvironment _webHostEnvironment; | |||
| private const string DefaultPath = "files"; | |||
| private const string DefaultPathTmp = "filestmp"; | |||
| public HomeController(ILogger<HomeController> logger, IMessageService messageService, IModelFactory modelFactory, IWebHostEnvironment webHostEnvironment) | |||
| public HomeController(ILogger<HomeController> logger, IMessageService messageService, IModelFactory modelFactory, | |||
| IWebHostEnvironment webHostEnvironment) | |||
| { | |||
| _logger = logger; | |||
| _messageService = messageService; | |||
| @@ -39,12 +39,12 @@ public sealed class HomeController : Controller | |||
| var files = Request.Form.Files.ToList(); | |||
| var basePath = Path.Combine(_webHostEnvironment.WebRootPath.Split('/')[0], DefaultPathTmp, code); | |||
| Directory.CreateDirectory(basePath); | |||
| foreach (var formFile in files) | |||
| { | |||
| if (formFile.Length <= 0) | |||
| if (formFile.Length <= 0) | |||
| continue; | |||
| var filePath = Path.Combine(basePath, formFile.FileName); | |||
| await using var stream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite); | |||
| await formFile.CopyToAsync(stream); | |||
| @@ -57,21 +57,20 @@ public sealed class HomeController : Controller | |||
| public async Task<IActionResult> CreateMessage(MessageModel model) | |||
| { | |||
| if (string.IsNullOrWhiteSpace(model.Text) && model.Files.Count == 0 && string.IsNullOrEmpty(model.FilesAsText)) | |||
| { | |||
| return Redirect("/"); | |||
| } | |||
| var message = new MessageDto { Text = model.Text }; | |||
| await UploadFiles(model, message); | |||
| var code = await _messageService.Create(message, model.ChosenPeriod); | |||
| return RedirectToAction("Link", "Home", new { code = code, share = true }); | |||
| return RedirectToAction("Link", "Home", new { code, share = true }); | |||
| } | |||
| private async Task UploadFiles(MessageModel model, MessageDto message) | |||
| { | |||
| var basePath = Path.Combine(_webHostEnvironment.WebRootPath.Split('/')[0], DefaultPath, message.Code.ToString()); | |||
| var basePath = Path.Combine(_webHostEnvironment.WebRootPath.Split('/')[0], DefaultPath, | |||
| message.Code.ToString()); | |||
| var basePathTemporary = Path.Combine(_webHostEnvironment.WebRootPath.Split('/')[0], DefaultPathTmp); | |||
| Directory.CreateDirectory(basePath); | |||
| @@ -88,17 +87,14 @@ public sealed class HomeController : Controller | |||
| .ToList(); | |||
| var fileNames = fileNamesTmp.Select(x => x.Split(':')[1]).ToList(); | |||
| foreach (var file in fileNames) | |||
| { | |||
| message.FileNames.Add(new FileModel { Name = file }); | |||
| } | |||
| foreach (var file in fileNames) message.FileNames.Add(new FileModel { Name = file }); | |||
| for (var ind = 0; ind < directoryNames.Count; ind++) | |||
| { | |||
| var directoryName = directoryNames[ind]; | |||
| var directoryPath = Path.Combine(basePathTemporary, directoryName); | |||
| var files = Directory.GetFiles(directoryPath); | |||
| for (var i = 0; i < files.Length; i++) | |||
| { | |||
| // var file = files[i]; | |||
| @@ -109,10 +105,7 @@ public sealed class HomeController : Controller | |||
| } | |||
| } | |||
| foreach (var directory in directoryNames) | |||
| { | |||
| Directory.Delete(Path.Combine(basePathTemporary, directory), true); | |||
| } | |||
| foreach (var directory in directoryNames) Directory.Delete(Path.Combine(basePathTemporary, directory), true); | |||
| foreach (var formFile in model.Files) | |||
| { | |||
| @@ -134,7 +127,7 @@ public sealed class HomeController : Controller | |||
| await stream.CopyToAsync(memory); | |||
| memory.Position = 0; | |||
| new FileExtensionContentTypeProvider().TryGetContentType(filename, out var contentType); | |||
| return contentType is null ? null : File(memory, contentType,Path.GetFileName(path)); | |||
| return contentType is null ? null : File(memory, contentType, Path.GetFileName(path)); | |||
| } | |||
| [HttpGet] | |||
| @@ -1,5 +1,4 @@ | |||
| using SecureSharing.Business.Interfaces; | |||
| using SecureSharing.Data.Data; | |||
| using SecureSharing.Models; | |||
| namespace SecureSharing.Infrastructure; | |||
| @@ -26,10 +25,10 @@ public sealed class ModelFactory : IModelFactory | |||
| { | |||
| MessageModel = new MessageModel | |||
| { | |||
| Code = code, | |||
| Code = code, | |||
| Text = message.Text, | |||
| FileNames = message.FileNames.Select(x => x.Name).ToList() | |||
| }, | |||
| }, | |||
| Share = share, | |||
| IsValid = message.IsValid | |||
| }; | |||
| @@ -10,6 +10,7 @@ public sealed class MessageModel | |||
| public PeriodOfValidity ChosenPeriod { get; set; } | |||
| public List<IFormFile> Files { get; init; } = new(); | |||
| public List<string> FileNames { get; init; } = new(); | |||
| public string FilesAsText { get; set; } = default!; | |||
| // public Dictionary<int, string> AvailablePeriods { get; set; } | |||
| } | |||
| @@ -21,10 +21,7 @@ StartupConfiguration.ConfigureStartupConfig<EmailSettings>(services, configurati | |||
| services.AddControllersWithViews(); | |||
| services.AddRazorPages(); | |||
| StartupExtensions.ConfigureServices(services); | |||
| services.AddDefaultIdentity<IdentityUser>(options => | |||
| { | |||
| options.SignIn.RequireConfirmedAccount = false; | |||
| }) | |||
| services.AddDefaultIdentity<IdentityUser>(options => { options.SignIn.RequireConfirmedAccount = false; }) | |||
| .AddDefaultUI() | |||
| .AddRoles<IdentityRole>() | |||
| .AddEntityFrameworkStores<AppDbContext>(); | |||
| @@ -32,18 +29,14 @@ services.AddDefaultIdentity<IdentityUser>(options => | |||
| services.AddScoped<IMessageService, MessageService>(); | |||
| services.AddScoped<IModelFactory, ModelFactory>(); | |||
| services.AddAuthentication(o => | |||
| { | |||
| o.DefaultScheme = GoogleDefaults.AuthenticationScheme; | |||
| }) | |||
| services.AddAuthentication(o => { o.DefaultScheme = GoogleDefaults.AuthenticationScheme; }) | |||
| .AddGoogle(options => | |||
| { | |||
| options.ClientId = configuration["EmailSettings:ClientId"]; | |||
| options.ClientSecret =configuration["EmailSettings:ClientSecret"]; | |||
| options.ClientSecret = configuration["EmailSettings:ClientSecret"]; | |||
| }); | |||
| // Add Quartz services | |||
| services.AddSingleton<IJobFactory, JobFactory>(); | |||
| services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>(); | |||
| @@ -44,10 +44,8 @@ public class JobFactory : IJobFactory | |||
| public void ReturnJob(IJob job) | |||
| { | |||
| if (_scopes.TryRemove(job, out var scope)) | |||
| { | |||
| // The Dispose() method ends the scope lifetime. | |||
| // Once Dispose is called, any scoped services that have been resolved from ServiceProvider will be disposed. | |||
| scope.Dispose(); | |||
| } | |||
| } | |||
| } | |||
| @@ -5,9 +5,9 @@ namespace SecureSharing.Quartz; | |||
| public sealed class MessageDeletionJob : IJob | |||
| { | |||
| private readonly IMessageService _messageService; | |||
| private readonly string _basePath; | |||
| private readonly string _basePathTmp; | |||
| private readonly IMessageService _messageService; | |||
| public MessageDeletionJob(IMessageService messageService, IWebHostEnvironment webHostEnvironment) | |||
| { | |||
| @@ -23,9 +23,7 @@ public sealed class MessageDeletionJob : IJob | |||
| var foldersToRemove = await _messageService.DeleteExpiredMessages(); | |||
| foreach (var path in foldersToRemove.Select(folder => Path.Combine(_basePath, folder))) | |||
| { | |||
| Directory.Delete(path, true); | |||
| } | |||
| Directory.Delete(_basePathTmp, true); | |||
| } | |||
| @@ -11,43 +11,43 @@ | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="AutoMapper" Version="11.0.1" /> | |||
| <PackageReference Include="Microsoft.AspNet.Identity.Core" Version="2.2.3" /> | |||
| <PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="6.0.9" /> | |||
| <PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="6.0.9" /> | |||
| <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.9" /> | |||
| <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.9" /> | |||
| <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.9" /> | |||
| <PackageReference Include="AutoMapper" Version="11.0.1"/> | |||
| <PackageReference Include="Microsoft.AspNet.Identity.Core" Version="2.2.3"/> | |||
| <PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="6.0.9"/> | |||
| <PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="6.0.9"/> | |||
| <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.9"/> | |||
| <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.9"/> | |||
| <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.9"/> | |||
| <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.9"> | |||
| <PrivateAssets>all</PrivateAssets> | |||
| <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | |||
| </PackageReference> | |||
| <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.15.1" /> | |||
| <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.9" /> | |||
| <PackageReference Include="Quartz" Version="3.5.0" /> | |||
| <PackageReference Include="Serilog" Version="2.12.0" /> | |||
| <PackageReference Include="Serilog.AspNetCore" Version="6.0.1" /> | |||
| <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.15.1"/> | |||
| <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.9"/> | |||
| <PackageReference Include="Quartz" Version="3.5.0"/> | |||
| <PackageReference Include="Serilog" Version="2.12.0"/> | |||
| <PackageReference Include="Serilog.AspNetCore" Version="6.0.1"/> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <ProjectReference Include="..\SecureSharing.Business\SecureSharing.Business.csproj" /> | |||
| <ProjectReference Include="..\SecureSharing.Data\SecureSharing.Data.csproj" /> | |||
| <ProjectReference Include="..\SecureSharing.Business\SecureSharing.Business.csproj"/> | |||
| <ProjectReference Include="..\SecureSharing.Data\SecureSharing.Data.csproj"/> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <Folder Include="AppData\Errors\" /> | |||
| <Folder Include="wwwroot\files" /> | |||
| <Folder Include="AppData\Errors\"/> | |||
| <Folder Include="wwwroot\files"/> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <_ContentIncludedByDefault Remove="Areas\Identity\Pages\Account\Login.cshtml" /> | |||
| <_ContentIncludedByDefault Remove="Areas\Identity\Pages\Account\LoginTestbe.cshtml" /> | |||
| <_ContentIncludedByDefault Remove="Areas\Identity\Pages\Account\Register.cshtml" /> | |||
| <_ContentIncludedByDefault Remove="Areas\Identity\Pages\Account\ResetPassword.cshtml" /> | |||
| <_ContentIncludedByDefault Remove="Areas\Identity\Pages\Account\_ViewImports.cshtml" /> | |||
| <_ContentIncludedByDefault Remove="Areas\Identity\Pages\_ValidationScriptsPartial.cshtml" /> | |||
| <_ContentIncludedByDefault Remove="Areas\Identity\Pages\_ViewImports.cshtml" /> | |||
| <_ContentIncludedByDefault Remove="Areas\Identity\Pages\_ViewStart.cshtml" /> | |||
| <_ContentIncludedByDefault Remove="Areas\Identity\Pages\Account\Login.cshtml"/> | |||
| <_ContentIncludedByDefault Remove="Areas\Identity\Pages\Account\LoginTestbe.cshtml"/> | |||
| <_ContentIncludedByDefault Remove="Areas\Identity\Pages\Account\Register.cshtml"/> | |||
| <_ContentIncludedByDefault Remove="Areas\Identity\Pages\Account\ResetPassword.cshtml"/> | |||
| <_ContentIncludedByDefault Remove="Areas\Identity\Pages\Account\_ViewImports.cshtml"/> | |||
| <_ContentIncludedByDefault Remove="Areas\Identity\Pages\_ValidationScriptsPartial.cshtml"/> | |||
| <_ContentIncludedByDefault Remove="Areas\Identity\Pages\_ViewImports.cshtml"/> | |||
| <_ContentIncludedByDefault Remove="Areas\Identity\Pages\_ViewStart.cshtml"/> | |||
| </ItemGroup> | |||
| </Project> | |||
| @@ -35,14 +35,14 @@ | |||
| <input asp-for="FilesAsText" id="fileInputAsText" type="text" style="display:none"/> | |||
| </div> | |||
| </div> | |||
| <div class="label-text"> | |||
| Your files | |||
| </div> | |||
| <div id="filesUploaded"> | |||
| </div> | |||
| <button class=" btn btn-light share-button" type="submit">Share</button> | |||
| </form> | |||
| @@ -46,7 +46,8 @@ else | |||
| <div class="label-text link-show"> | |||
| @foreach (var file in Model.MessageModel.FileNames) | |||
| { | |||
| <a asp-action="Download" asp-route-filename="@file" asp-route-code="@Model.MessageModel.Code">@file</a><br/> | |||
| <a asp-action="Download" asp-route-filename="@file" asp-route-code="@Model.MessageModel.Code">@file</a> | |||
| <br/> | |||
| } | |||
| </div> | |||
| } | |||
| @@ -95,7 +96,8 @@ else | |||
| <div class="label-text link-show"> | |||
| @foreach (var file in Model.MessageModel.FileNames) | |||
| { | |||
| <a asp-action="Download" asp-route-filename="@file" asp-route-code="@Model.MessageModel.Code">@file</a><br/> | |||
| <a asp-action="Download" asp-route-filename="@file" asp-route-code="@Model.MessageModel.Code">@file</a> | |||
| <br/> | |||
| } | |||
| </div> | |||
| } | |||
| @@ -28,7 +28,7 @@ | |||
| <link rel="stylesheet" href="~/plugins/daterangepicker/daterangepicker.css"> | |||
| <!-- summernote --> | |||
| <link rel="stylesheet" href="~/plugins/summernote/summernote-bs4.min.css"> | |||
| <link href="~/lib/jquery-confirm/jquery-confirm.min.css" rel="stylesheet"/> | |||
| <link rel="stylesheet" href="~/css/site.css"> | |||