Skip to content

Commit

Permalink
Add file management page for puzzles (#71)
Browse files Browse the repository at this point in the history
* Add file management page for puzzles
  • Loading branch information
morganbr authored Oct 6, 2018
1 parent b585306 commit aa7a58e
Show file tree
Hide file tree
Showing 5 changed files with 301 additions and 42 deletions.
10 changes: 0 additions & 10 deletions ServerCore/Pages/Puzzles/Edit.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,6 @@
<input asp-for="Puzzle.MinPrerequisiteCount" class="form-control" />
<span asp-validation-for="Puzzle.MinPrerequisiteCount" class="text-danger"></span>
</div>
<div class="form-group">
<label class="control-label">Puzzle PDF</label>
<div>
<a href="@Html.DisplayFor(model => model.Puzzle.PuzzleFile.Url)">
@Html.DisplayFor(model => model.Puzzle.PuzzleFile.Url)
</a>
</div>
<input asp-for="PuzzleFile" class="form-control" style="height:auto" />
<span asp-validation-for="PuzzleFile" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-default" />
</div>
Expand Down
29 changes: 0 additions & 29 deletions ServerCore/Pages/Puzzles/Edit.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<IActionResult> OnGetAsync(int id)
{
Puzzle = await _context.Puzzles.Where(m => m.ID == id).FirstOrDefaultAsync();
Expand All @@ -44,32 +41,6 @@ public async Task<IActionResult> 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();
Expand Down
82 changes: 82 additions & 0 deletions ServerCore/Pages/Puzzles/FileManagement.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
@page "/{eventId}/Puzzles/FileManagement/{id}/{handler?}"
@model ServerCore.Pages.Puzzles.FileManagementModel

@{
ViewData["Title"] = "FileManagement";
}

<h2>FileManagement</h2>

<div>
<h4>Puzzle</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Puzzle.Name)
</dt>
<dd>
@Html.DisplayFor(model => model.Puzzle.Name)
</dd>

</dl>
<div class="form-group">
<form method="post" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Puzzle.ID" />
<label class="control-label">Puzzle File</label>
<div>
@if (Model.Puzzle.PuzzleFile != null)
{
@Html.ActionLink(Model.Puzzle.PuzzleFile.ShortName, "Index", "Files", new { eventId = Model.Event.ID, filename = Model.Puzzle.PuzzleFile.ShortName })
<button type="submit" asp-route-id="@Model.Puzzle.ID" asp-route-fileId="@Model.Puzzle.PuzzleFile.ID" asp-page-handler="Delete">Delete</button>
}
</div>
<input asp-for="PuzzleFile" class="form-control" style="height:auto" />
<span asp-validation-for="PuzzleFile" class="text-danger"></span>
<hr />

<label class="control-label">Answer File</label>
<div>
@if (Model.Puzzle.AnswerFile != null)
{
@Html.ActionLink(Model.Puzzle.AnswerFile.ShortName, "Index", "Files", new { eventId = Model.Event.ID, filename = Model.Puzzle.AnswerFile.ShortName })
<button type="submit" asp-route-id="@Model.Puzzle.ID" asp-route-fileId="@Model.Puzzle.AnswerFile.ID" asp-page-handler="Delete">Delete</button>
}
</div>
<input asp-for="AnswerFile" class="form-control" style="height:auto" />
<span asp-validation-for="AnswerFile" class="text-danger"></span>
<hr />

<label class="control-label">Materials</label>
@foreach (var puzzleFile in Model.Puzzle.Materials)
{
<p>
@Html.ActionLink(puzzleFile.ShortName, "Index", "Files", new { eventId = Model.Event.ID, filename = puzzleFile.ShortName })
<button type="submit" asp-route-id="@Model.Puzzle.ID" asp-route-fileId="@puzzleFile.ID" asp-page-handler="Delete">Delete</button>
</p>
}
<input asp-for="PuzzleMaterialFiles" class="form-control" style="height:auto" />
<span asp-validation-for="PuzzleMaterialFiles" class="text-danger"></span>
<hr />

<label class="control-label">Solve Token Files</label>
@foreach (var solveFile in Model.Puzzle.SolveTokenFiles)
{
<p>
@Html.ActionLink(solveFile.ShortName, "Index", "Files", new { eventId = Model.Event.ID, filename = solveFile.ShortName })
<button type="submit" asp-route-id="@Model.Puzzle.ID" asp-route-fileId="@solveFile.ID" asp-page-handler="Delete">Delete</button>
</p>
}
<input asp-for="SolveTokenFiles" class="form-control" style="height:auto" />
<span asp-validation-for="SolveTokenFiles" class="text-danger"></span>

<div class="form-group">
<input type="submit" value="Upload" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
|
<a asp-page="./Index">Back to List</a>
</div>
210 changes: 210 additions & 0 deletions ServerCore/Pages/Puzzles/FileManagement.cshtml.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// Page for managing the files associated with a puzzle
/// </summary>
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<IFormFile> PuzzleMaterialFiles { get; set; }

[BindProperty]
public List<IFormFile> SolveTokenFiles { get; set; }

/// <summary>
/// Handler for listing files
/// </summary>
public async Task<IActionResult> OnGetAsync(int id)
{
Puzzle = await _context.Puzzles.FirstOrDefaultAsync(m => m.ID == id);

if (Puzzle == null)
{
return NotFound();
}

return Page();
}

/// <summary>
/// Handler for uploading files
/// </summary>
public async Task<IActionResult> 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");
}

/// <summary>
/// Handler for deleting an uploaded file
/// </summary>
public async Task<IActionResult> 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");
}

/// <summary>
/// Returns true if a puzzle exists with a given id
/// </summary>
private bool PuzzleExists(int id)
{
return _context.Puzzles.Any(e => e.ID == id);
}

/// <summary>
/// Helper for taking an uploaded form file, uploading it, and tracking it in the database
/// </summary>
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);
}
}
}
12 changes: 9 additions & 3 deletions ServerCore/Pages/Puzzles/Index.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,14 @@
@foreach (var item in Model.Puzzles) {
<tr>
<td>
<a href="@Html.DisplayFor(modelItem => item.PuzzleFile.Url)">
@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)
</a>
}
</td>
<td>
@Html.DisplayFor(modelItem => item.IsPuzzle)
Expand Down Expand Up @@ -85,7 +90,8 @@
<a asp-Page="./Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-Page="./Details" asp-route-id="@item.ID">Details</a> |
<a asp-Page="./Delete" asp-route-id="@item.ID">Delete</a> |
<a asp-page="./Status" asp-route-id="@item.ID">Status</a>
<a asp-page="./Status" asp-route-id="@item.ID">Status</a> |
<a asp-Page="./FileManagement" asp-route-id="@item.ID">File Management</a>
</td>
</tr>
}
Expand Down

0 comments on commit aa7a58e

Please sign in to comment.