From a975beac42e2faff7aaf2266ca269dd5695d8ea7 Mon Sep 17 00:00:00 2001 From: Morgan Brown Date: Wed, 26 Sep 2018 03:31:00 -0700 Subject: [PATCH 1/2] Add file management page for puzzles --- ServerCore/Pages/Puzzles/Edit.cshtml | 10 - ServerCore/Pages/Puzzles/Edit.cshtml.cs | 29 --- .../Pages/Puzzles/FileManagement.cshtml | 79 +++++++ .../Pages/Puzzles/FileManagement.cshtml.cs | 210 ++++++++++++++++++ ServerCore/Pages/Puzzles/Index.cshtml | 12 +- 5 files changed, 298 insertions(+), 42 deletions(-) create mode 100644 ServerCore/Pages/Puzzles/FileManagement.cshtml create mode 100644 ServerCore/Pages/Puzzles/FileManagement.cshtml.cs diff --git a/ServerCore/Pages/Puzzles/Edit.cshtml b/ServerCore/Pages/Puzzles/Edit.cshtml index a68fb925..3ef87427 100644 --- a/ServerCore/Pages/Puzzles/Edit.cshtml +++ b/ServerCore/Pages/Puzzles/Edit.cshtml @@ -72,16 +72,6 @@ -
- -
- - @Html.DisplayFor(model => model.Puzzle.PuzzleFile.Url) - -
- - -
diff --git a/ServerCore/Pages/Puzzles/Edit.cshtml.cs b/ServerCore/Pages/Puzzles/Edit.cshtml.cs index caffeecc..d788f8ed 100644 --- a/ServerCore/Pages/Puzzles/Edit.cshtml.cs +++ b/ServerCore/Pages/Puzzles/Edit.cshtml.cs @@ -21,9 +21,6 @@ public EditModel(ServerCore.Models.PuzzleServerContext context) [BindProperty] public Puzzle Puzzle { get; set; } - [BindProperty] - public IFormFile PuzzleFile { get; set; } - public async Task OnGetAsync(int id) { Puzzle = await _context.Puzzles.Where(m => m.ID == id).FirstOrDefaultAsync(); @@ -44,32 +41,6 @@ public async Task OnPostAsync() _context.Attach(Puzzle).State = EntityState.Modified; - if (PuzzleFile != null) - { - ContentFile file = new ContentFile(); - string fileName = WebUtility.UrlEncode(PuzzleFile.FileName); - - file.ShortName = fileName; - file.Puzzle = Puzzle; - file.Event = Event; - file.FileType = ContentFileType.Puzzle; - - // Remove previous puzzle files - var oldFiles = from oldFile in _context.ContentFiles - where oldFile.Puzzle == Puzzle && - oldFile.FileType == ContentFileType.Puzzle - select oldFile; - foreach(ContentFile oldFile in oldFiles) - { - await FileManager.DeleteBlobAsync(oldFile.Url); - _context.ContentFiles.Remove(oldFile); - } - - file.Url = await FileManager.UploadBlobAsync(fileName, Event.ID, PuzzleFile.OpenReadStream()); - - _context.ContentFiles.Add(file); - } - try { await _context.SaveChangesAsync(); diff --git a/ServerCore/Pages/Puzzles/FileManagement.cshtml b/ServerCore/Pages/Puzzles/FileManagement.cshtml new file mode 100644 index 00000000..faf9432a --- /dev/null +++ b/ServerCore/Pages/Puzzles/FileManagement.cshtml @@ -0,0 +1,79 @@ +@page "/{eventId}/Puzzles/FileManagement/{id}/{handler?}" +@model ServerCore.Pages.Puzzles.FileManagementModel + +@{ + ViewData["Title"] = "FileManagement"; +} + +

FileManagement

+ +
+

Puzzle

+
+
+
+ @Html.DisplayNameFor(model => model.Puzzle.Name) +
+
+ @Html.DisplayFor(model => model.Puzzle.Name) +
+ +
+
+
+
+ + +
+ @if (Model.Puzzle.PuzzleFile != null) + { + @Html.ActionLink(Model.Puzzle.PuzzleFile.ShortName, "Index", "Files", new { eventId = Model.Event.ID, filename = Model.Puzzle.PuzzleFile.ShortName }) + + } +
+ + + + +
+ @if (Model.Puzzle.AnswerFile != null) + { + @Html.ActionLink(Model.Puzzle.AnswerFile.ShortName, "Index", "Files", new { eventId = Model.Event.ID, filename = Model.Puzzle.AnswerFile.ShortName }) + + } +
+ + + + + @foreach (var puzzleFile in Model.Puzzle.Materials) + { +

+ @Html.ActionLink(puzzleFile.ShortName, "Index", "Files", new { eventId = Model.Event.ID, filename = puzzleFile.ShortName }) + +

+ } + + + + + @foreach (var solveFile in Model.Puzzle.SolveTokenFiles) + { +

+ @Html.ActionLink(solveFile.ShortName, "Index", "Files", new { eventId = Model.Event.ID, filename = solveFile.ShortName }) + +

+ } + + + +
+ +
+
+
+
+
+ | + Back to List +
diff --git a/ServerCore/Pages/Puzzles/FileManagement.cshtml.cs b/ServerCore/Pages/Puzzles/FileManagement.cshtml.cs new file mode 100644 index 00000000..b7d4066d --- /dev/null +++ b/ServerCore/Pages/Puzzles/FileManagement.cshtml.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.EntityFrameworkCore; +using ServerCore.DataModel; +using ServerCore.ModelBases; +using ServerCore.Models; + +namespace ServerCore.Pages.Puzzles +{ + /// + /// Page for managing the files associated with a puzzle + /// + public class FileManagementModel : EventSpecificPageModel + { + private readonly ServerCore.Models.PuzzleServerContext _context; + + public FileManagementModel(ServerCore.Models.PuzzleServerContext context) + { + _context = context; + } + + //[BindProperty] + public Puzzle Puzzle { get; set; } + + [BindProperty] + public IFormFile PuzzleFile { get; set; } + + [BindProperty] + public IFormFile AnswerFile { get; set; } + + [BindProperty] + public List PuzzleMaterialFiles { get; set; } + + [BindProperty] + public List SolveTokenFiles { get; set; } + + /// + /// Handler for listing files + /// + public async Task OnGetAsync(int id) + { + Puzzle = await _context.Puzzles.FirstOrDefaultAsync(m => m.ID == id); + + if (Puzzle == null) + { + return NotFound(); + } + + return Page(); + } + + /// + /// Handler for uploading files + /// + public async Task OnPostAsync(int id) + { + if (!ModelState.IsValid) + { + return Page(); + } + + Puzzle = await _context.Puzzles.FirstOrDefaultAsync(m => m.ID == id); + + if (Puzzle == null) + { + return NotFound(); + } + + if (PuzzleFile != null) + { + // Remove previous puzzle files + var oldFiles = from oldFile in _context.ContentFiles + where oldFile.Puzzle == Puzzle && + oldFile.FileType == ContentFileType.Puzzle + select oldFile; + foreach (ContentFile oldFile in oldFiles) + { + await FileManager.DeleteBlobAsync(oldFile.Url); + _context.ContentFiles.Remove(oldFile); + } + await UploadFileAsync(PuzzleFile, ContentFileType.Puzzle); + } + + if (AnswerFile != null) + { + // Remove previous answer files + var oldFiles = from oldFile in _context.ContentFiles + where oldFile.Puzzle == Puzzle && + oldFile.FileType == ContentFileType.Answer + select oldFile; + foreach (ContentFile oldFile in oldFiles) + { + await FileManager.DeleteBlobAsync(oldFile.Url); + _context.ContentFiles.Remove(oldFile); + } + await UploadFileAsync(AnswerFile, ContentFileType.Answer); + } + + if (PuzzleMaterialFiles != null) + { + foreach (IFormFile materialFile in PuzzleMaterialFiles) + { + await UploadFileAsync(materialFile, ContentFileType.PuzzleMaterial); + } + } + + if (SolveTokenFiles != null) + { + foreach (IFormFile solveToken in SolveTokenFiles) + { + await UploadFileAsync(solveToken, ContentFileType.SolveToken); + } + } + + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException) + { + if (!PuzzleExists(Puzzle.ID)) + { + return NotFound(); + } + else + { + throw; + } + } + + return RedirectToPage("FileManagement"); + } + + /// + /// Handler for deleting an uploaded file + /// + public async Task OnPostDeleteAsync(int id, int fileId) + { + Puzzle = await _context.Puzzles.FirstOrDefaultAsync(m => m.ID == id); + + if (Puzzle == null) + { + return NotFound(); + } + + ContentFile fileToDelete = (from file in Puzzle.Contents + where file.ID == fileId + select file).SingleOrDefault(); + + if (fileToDelete == null) + { + return NotFound(); + } + + await FileManager.DeleteBlobAsync(fileToDelete.Url); + Puzzle.Contents.Remove(fileToDelete); + + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException) + { + if (!PuzzleExists(Puzzle.ID)) + { + return NotFound(); + } + else + { + throw; + } + } + + return RedirectToPage("FileManagement"); + } + + /// + /// Returns true if a puzzle exists with a given id + /// + private bool PuzzleExists(int id) + { + return _context.Puzzles.Any(e => e.ID == id); + } + + /// + /// Helper for taking an uploaded form file, uploading it, and tracking it in the database + /// + private async Task UploadFileAsync(IFormFile uploadedFile, ContentFileType fileType) + { + ContentFile file = new ContentFile(); + string fileName = WebUtility.UrlEncode(Path.GetFileName(uploadedFile.FileName)); + + file.ShortName = fileName; + file.Puzzle = Puzzle; + file.Event = Event; + file.FileType = fileType; + + file.Url = await FileManager.UploadBlobAsync(fileName, Event.ID, uploadedFile.OpenReadStream()); + + _context.ContentFiles.Add(file); + } + } +} diff --git a/ServerCore/Pages/Puzzles/Index.cshtml b/ServerCore/Pages/Puzzles/Index.cshtml index 660e458c..aafb31b2 100644 --- a/ServerCore/Pages/Puzzles/Index.cshtml +++ b/ServerCore/Pages/Puzzles/Index.cshtml @@ -50,9 +50,14 @@ @foreach (var item in Model.Puzzles) { - + @if (item.PuzzleFile != null) + { + @Html.ActionLink(item.Name, "Index", "Files", new { eventId = Model.Event.ID, filename = item.PuzzleFile.ShortName }) + } + else + { @Html.DisplayFor(modelItem => item.Name) - + } @Html.DisplayFor(modelItem => item.IsPuzzle) @@ -85,7 +90,8 @@ Edit | Details | Delete | - Status + Status | + File Management } From f0c9009533be6ab5bda8cd6ed64364f7c83f5976 Mon Sep 17 00:00:00 2001 From: Morgan Brown Date: Wed, 26 Sep 2018 18:32:32 -0700 Subject: [PATCH 2/2] Cleaner formatting --- ServerCore/Pages/Puzzles/FileManagement.cshtml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ServerCore/Pages/Puzzles/FileManagement.cshtml b/ServerCore/Pages/Puzzles/FileManagement.cshtml index faf9432a..88384e2d 100644 --- a/ServerCore/Pages/Puzzles/FileManagement.cshtml +++ b/ServerCore/Pages/Puzzles/FileManagement.cshtml @@ -33,6 +33,7 @@ +
@@ -44,6 +45,7 @@
+
@foreach (var puzzleFile in Model.Puzzle.Materials) @@ -55,6 +57,7 @@ } +
@foreach (var solveFile in Model.Puzzle.SolveTokenFiles)