From ba2625f87b3ba7e57d63a4374903f4138bd4acbe Mon Sep 17 00:00:00 2001 From: Souvik Mazumder Date: Wed, 26 Jan 2022 18:44:56 -0500 Subject: [PATCH] File upload implemented --- .../Controllers/EncylopediaController.cs | 6 +- .../Controllers/FilesController.cs | 49 ++++++------- Library.Encyclopedia.API/Startup.cs | 12 +++- Library.Encyclopedia.API/appsettings.json | 14 ++-- Library.Encyclopedia.API/web.config | 13 ++++ .../DataAccess/MainDataAccess.cs | 62 +++++++++++++---- .../FileAccess/FTPAdapter.cs | 69 ------------------- .../FileAccess/WindowsFileSaveAdapter.cs | 53 ++++++++++++++ .../Interfaces/IFilesAdapter.cs | 5 +- 9 files changed, 162 insertions(+), 121 deletions(-) create mode 100644 Library.Encyclopedia.API/web.config delete mode 100644 Library.Encyclopedia.DataAccess/FileAccess/FTPAdapter.cs create mode 100644 Library.Encyclopedia.DataAccess/FileAccess/WindowsFileSaveAdapter.cs diff --git a/Library.Encyclopedia.API/Controllers/EncylopediaController.cs b/Library.Encyclopedia.API/Controllers/EncylopediaController.cs index 1338864..fab97c7 100644 --- a/Library.Encyclopedia.API/Controllers/EncylopediaController.cs +++ b/Library.Encyclopedia.API/Controllers/EncylopediaController.cs @@ -1,16 +1,13 @@ -using Library.Encyclopedia.API.Attributes; -using Library.Encyclopedia.DataAccess; +using Library.Encyclopedia.DataAccess; using Library.Encyclopedia.DataAccess.DataAccess; using Library.Encyclopedia.Entity.Interfaces; using Library.Encyclopedia.Entity.Models; using Library.Encyclopedia.Entity.Models.External; -using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using System; -using System.Collections.Generic; using System.DirectoryServices.AccountManagement; using System.Threading.Tasks; @@ -45,6 +42,7 @@ public IActionResult Login() { using (var context = new PrincipalContext(ContextType.Domain | ContextType.Machine)) { + var usr = UserPrincipal.FindByIdentity(context, this.HttpContext.User.Identity.Name); return Ok(usr.DisplayName); } diff --git a/Library.Encyclopedia.API/Controllers/FilesController.cs b/Library.Encyclopedia.API/Controllers/FilesController.cs index a98ffcb..ce3a146 100644 --- a/Library.Encyclopedia.API/Controllers/FilesController.cs +++ b/Library.Encyclopedia.API/Controllers/FilesController.cs @@ -3,6 +3,7 @@ using Library.Encyclopedia.DataAccess.DataAccess; using Library.Encyclopedia.Entity.Interfaces; using Library.Encyclopedia.Entity.Models; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; @@ -38,38 +39,34 @@ public FilesController(ILogger logger, IApplicationDbContext db /// /// [HttpPost("{id}")] - [ApiKey] - public async Task Post(Guid id, List files, [FromForm] Dictionary descriptions) + [Authorize(Roles = @"EncyclopediaAdministrators")] + public async Task Post(Guid id, IFormFile file, string description) { try { // Store files at remote location - var responses = filesAdapter.UploadFiles(id, files); + var response = await filesAdapter.UploadFile(id, file); - List fileResponses = new List(); - - // filter out the failed uploads - for (int i = 0; i < responses.Count(); i++) + if (response) { - if (responses.ToList()[i]) + string fileNameWithoutExt = Path.GetFileNameWithoutExtension(file.FileName); + Files file_entry = new Files { - string fileNameWithoutExt = Path.GetFileNameWithoutExtension(files[i].FileName); - fileResponses.Add(new Files - { - Id = Guid.NewGuid(), - MainId = id, - FileName = files[i].FileName, - FilePath = $@"/encyclopedia-media/{id}/{files[i].FileName}", - FileType = files[i].ContentType, - FileDescription = descriptions.ContainsKey(fileNameWithoutExt) ? descriptions[fileNameWithoutExt] : null - }); - } - } + Id = Guid.NewGuid(), + MainId = id, + FileName = file.FileName, + FilePath = $@"/{id}/{file.FileName}", + FileType = file.ContentType, + FileDescription = description + }; - // Save to database - await filesDataAccess.AddFiles(fileResponses); + // Save to database + await filesDataAccess.AddFiles(new List { file_entry }); - return Ok(fileResponses); + return Ok(file_entry); + } + else + return BadRequest(); } catch (Exception ex) { @@ -87,14 +84,12 @@ public async Task Post(Guid id, List files, [FromForm] /// /// [HttpGet("{id}")] - [ApiKey] + [Authorize(Roles = @"EncyclopediaAdministrators")] public async Task Get(Guid id, string directory) { try { - var files = await filesDataAccess.GetFiles(id); - var fileResponses = filesAdapter.DownloadFiles(files, directory); - return Ok(fileResponses); + return Ok(); } catch (Exception ex) { diff --git a/Library.Encyclopedia.API/Startup.cs b/Library.Encyclopedia.API/Startup.cs index 07b2104..80d2d73 100644 --- a/Library.Encyclopedia.API/Startup.cs +++ b/Library.Encyclopedia.API/Startup.cs @@ -3,6 +3,7 @@ using Library.Encyclopedia.Entity.Interfaces; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.IISIntegration; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -38,14 +39,21 @@ public void ConfigureServices(IServiceCollection services) services.AddControllers(); - string url = Configuration.GetValue("FTPSettings:url"); + string url = Configuration.GetValue("FTPSettings:filePath"); string userName = Configuration.GetValue("FTPSettings:username"); string password = Configuration.GetValue("FTPSettings:password"); services.AddScoped(s => new ApplicationDbContext(Configuration.GetConnectionString("DefaultConnection"))); services.AddScoped(s => { - return new FTPAdapter(url, new System.Net.NetworkCredential(userName, password)); + return new WindowsFileSaveAdapter(url); + }); + + services.Configure(x => + { + x.ValueLengthLimit = int.MaxValue; + x.MultipartBodyLengthLimit = int.MaxValue; + x.MultipartHeadersLengthLimit = int.MaxValue; }); } diff --git a/Library.Encyclopedia.API/appsettings.json b/Library.Encyclopedia.API/appsettings.json index 9b70064..abc7927 100644 --- a/Library.Encyclopedia.API/appsettings.json +++ b/Library.Encyclopedia.API/appsettings.json @@ -10,13 +10,17 @@ "App-Base-Url": "https://tools.library.pfw.edu/encyclopedia", "AllowedHosts": "*", "ConnectionStrings": { - //"DefaultConnection": "Server=localhost;Database=Encyclopedia;User=root;Password=root" - "DefaultConnection": "Server=localhost;Database=Encyclopedia;User=root;Password=RW_qh+-ta5hW*2s" + "DefaultConnection": "Server=localhost;Database=Encyclopedia;User=root;Password=root" + //"DefaultConnection": "Server=localhost;Database=Encyclopedia;User=root;Password=RW_qh+-ta5hW*2s" }, "ApiKey": "5929b003-8895-4fb3-bbb0-2eb101c48f66", "FTPSettings": { - "url": "10.161.100.82", - "username": "mazus01", - "password": "" + // For Linux + //"url": "10.161.100.82", + //"username": "mazus01", + //"password": "" + + // For Windows + "filePath": "O:\\Library\\Departments\\Applications\\PFW Encyclopedia Files\\" } } \ No newline at end of file diff --git a/Library.Encyclopedia.API/web.config b/Library.Encyclopedia.API/web.config new file mode 100644 index 0000000..a991ee8 --- /dev/null +++ b/Library.Encyclopedia.API/web.config @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Library.Encyclopedia.DataAccess/DataAccess/MainDataAccess.cs b/Library.Encyclopedia.DataAccess/DataAccess/MainDataAccess.cs index 20fa987..e3241b8 100644 --- a/Library.Encyclopedia.DataAccess/DataAccess/MainDataAccess.cs +++ b/Library.Encyclopedia.DataAccess/DataAccess/MainDataAccess.cs @@ -241,11 +241,13 @@ private Main ReplaceLineBreaks(Main model) return model; } - private Main ReplaceInternalLinks(Main model) + private Main ReplaceInternalLinks(Main model, bool isUpdate = false) { string searchStartString = ""; - model.Links = new List(); + model.Links ??= new List(); + var newCreatedLinks = new List(); + var updatedLinks = new List(); if (model.RichDescription != null) { @@ -283,21 +285,42 @@ private Main ReplaceInternalLinks(Main model) newDesc = newDesc.Replace(value, $"$$${id}$$$"); newDesc2 = newDesc2.Replace(value, desc); - // add to links list - model.Links.Add(new Links + if (!model.Links.Any(s => s.ReferenceId == Guid.Parse(id))) { - Id = Guid.NewGuid(), - MainId = model.Id, - ReferenceId = Guid.Parse(id), - Link = value, - Description = desc, - IsInternal = true - }); + // add to links list + Links item = new Links + { + Id = Guid.NewGuid(), + MainId = model.Id, + ReferenceId = Guid.Parse(id), + Link = value, + Description = desc, + IsInternal = true + }; + model.Links.Add(item); + + newCreatedLinks.Add(item); + } + else + { + model.Links.FirstOrDefault(s => s.ReferenceId == Guid.Parse(id)).Link = value; + model.Links.FirstOrDefault(s => s.ReferenceId == Guid.Parse(id)).Description = desc; + updatedLinks.Add(model.Links.FirstOrDefault(s => s.ReferenceId == Guid.Parse(id))); + } + } } model.RichDescription = newDesc; model.RawDescription = newDesc2; + + if (isUpdate) + { + _dbcontext.Links.AddRangeAsync(newCreatedLinks); + _dbcontext.Links.UpdateRange(updatedLinks); + _dbcontext.SaveChanges().Wait(); + } + } return model; @@ -323,7 +346,7 @@ public async Task
UpdateAsync(Guid id, MainUpdateModel model) entry.RichDescription = model.RichDescription; - entry = ReplaceInternalLinks(entry); + entry = ReplaceInternalLinks(entry, true); entry = ReplaceLineBreaks(entry); //santize data @@ -334,6 +357,21 @@ public async Task
UpdateAsync(Guid id, MainUpdateModel model) _dbcontext.Main.Update(entry); await _dbcontext.SaveChanges(); + + if (entry.RichDescription != null) + { + // replace links in item + while (entry.RichDescription.IndexOf("$$$") != -1) + { + var startIndex = entry.RichDescription.IndexOf("$$$") + 3; + var endIndex = entry.RichDescription.Substring(startIndex).IndexOf("$$$"); + + var referenceid = entry.RichDescription.Substring(startIndex, endIndex); + + entry.RichDescription = entry.RichDescription.Replace($"$$${referenceid}$$$", $"{entry.Links.FirstOrDefault(s => s.ReferenceId.ToString() == referenceid).Description}"); + } + } + return entry; } } diff --git a/Library.Encyclopedia.DataAccess/FileAccess/FTPAdapter.cs b/Library.Encyclopedia.DataAccess/FileAccess/FTPAdapter.cs deleted file mode 100644 index 1e1cae2..0000000 --- a/Library.Encyclopedia.DataAccess/FileAccess/FTPAdapter.cs +++ /dev/null @@ -1,69 +0,0 @@ -using Library.Encyclopedia.Entity.Interfaces; -using Library.Encyclopedia.Entity.Models; -using Microsoft.AspNetCore.Http; -using Renci.SshNet; -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Text; - -namespace Library.Encyclopedia.DataAccess.FileAccess -{ - public class FTPAdapter : IFilesAdapter - { - private readonly string url; - private readonly NetworkCredential networkCredential; - - public FTPAdapter(string url, NetworkCredential networkCredential) - { - this.url = url; - this.networkCredential = networkCredential; - } - - public IEnumerable DownloadFiles(IEnumerable files, string directory) - { - List responses = new List(); - var customUrl = $@"/home/{networkCredential.UserName}"; - - using (SftpClient client = new SftpClient(url, 22, networkCredential.UserName, networkCredential.Password)) - { - client.Connect(); - foreach (var file in files) - { - using (var stream = File.OpenWrite(Path.Combine(directory, file.FileName))) - { - client.DownloadFile(customUrl + file.FilePath, stream); - responses.Add(true); - } - } - } - - return responses; - } - - public IEnumerable UploadFiles(Guid id, List files) - { - List responses = new List(); - var customUrl = $@"/home/{networkCredential.UserName}/encyclopedia-media/{id}/"; - - using (SftpClient client = new SftpClient(url, 22, networkCredential.UserName, networkCredential.Password)) - { - client.Connect(); - if (!client.Exists(customUrl)) - client.CreateDirectory(customUrl); - - foreach (var file in files) - { - if (client.Exists(customUrl + file.FileName)) - client.DeleteFile(customUrl + file.FileName); - - client.UploadFile(file.OpenReadStream(), customUrl + file.FileName); - responses.Add(true); - } - } - - return responses; - } - } -} diff --git a/Library.Encyclopedia.DataAccess/FileAccess/WindowsFileSaveAdapter.cs b/Library.Encyclopedia.DataAccess/FileAccess/WindowsFileSaveAdapter.cs new file mode 100644 index 0000000..9b408c8 --- /dev/null +++ b/Library.Encyclopedia.DataAccess/FileAccess/WindowsFileSaveAdapter.cs @@ -0,0 +1,53 @@ +using Library.Encyclopedia.Entity.Interfaces; +using Library.Encyclopedia.Entity.Models; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Library.Encyclopedia.DataAccess.FileAccess +{ + public class WindowsFileSaveAdapter : IFilesAdapter + { + private readonly string networkPath; + + public WindowsFileSaveAdapter(string networkPath) + { + this.networkPath = networkPath; + } + public bool DownloadFile(Files file, string directory) + { + throw new NotImplementedException(); + } + + public async Task UploadFile(Guid id, IFormFile file) + { + try + { + var path = Path.Combine(networkPath, id.ToString(), file.FileName); + if (File.Exists(path)) + using (var stream = File.OpenWrite(path)) + { + await file.CopyToAsync(stream); + } + else + { + Directory.CreateDirectory(Path.GetDirectoryName(path)); + using (var stream = File.Create(path)) + { + await file.CopyToAsync(stream); + } + } + + return true; + } + catch (Exception ex) + { + return false; + } + } + } +} diff --git a/Library.Encyclopedia.Entity/Interfaces/IFilesAdapter.cs b/Library.Encyclopedia.Entity/Interfaces/IFilesAdapter.cs index 95bfb79..5dd34ef 100644 --- a/Library.Encyclopedia.Entity/Interfaces/IFilesAdapter.cs +++ b/Library.Encyclopedia.Entity/Interfaces/IFilesAdapter.cs @@ -2,12 +2,13 @@ using Microsoft.AspNetCore.Http; using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace Library.Encyclopedia.Entity.Interfaces { public interface IFilesAdapter { - IEnumerable UploadFiles(Guid id, List files); - IEnumerable DownloadFiles(IEnumerable files, string directory); + public Task UploadFile(Guid id, IFormFile file); + bool DownloadFile(Files file, string directory); } } \ No newline at end of file