diff --git a/.gitignore b/.gitignore index 4d4389a..d8cb21f 100644 --- a/.gitignore +++ b/.gitignore @@ -339,4 +339,5 @@ ASALocalRun/ # BeatPulse healthcheck temp database healthchecksdb -**/appsettings.json \ No newline at end of file +**/appsettings.json +**/uploads/ \ No newline at end of file diff --git a/MultipleChoiceTrainer/Controllers/QuestionsController.cs b/MultipleChoiceTrainer/Controllers/QuestionsController.cs index b947af3..4f80b3e 100644 --- a/MultipleChoiceTrainer/Controllers/QuestionsController.cs +++ b/MultipleChoiceTrainer/Controllers/QuestionsController.cs @@ -1,11 +1,14 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.EntityFrameworkCore; using MultipleChoiceTrainer.Data; +using MultipleChoiceTrainer.Models; using MultipleChoiceTrainer.Models.DataModels; namespace MultipleChoiceTrainer.Controllers @@ -13,10 +16,11 @@ namespace MultipleChoiceTrainer.Controllers public class QuestionsController : Controller { private readonly ApplicationDbContext _context; - - public QuestionsController(ApplicationDbContext context) + private readonly IWebHostEnvironment _webHostEnvironment; + public QuestionsController(ApplicationDbContext context, IWebHostEnvironment hostEnvironment) { _context = context; + _webHostEnvironment = hostEnvironment; } public IActionResult List(int sectionId) @@ -37,13 +41,14 @@ namespace MultipleChoiceTrainer.Controllers // more details, see http://go.microsoft.com/fwlink/?LinkId=317598. [HttpPost] [ValidateAntiForgeryToken] - public async Task Create(Question question) - { + public async Task Create(QuestionViewModel question) + { if (ModelState.IsValid) - { + { question.Choices = question.Choices.ToList().Where(e => !string.IsNullOrEmpty(e.Text) && !string.IsNullOrWhiteSpace(e.Text)).ToList(); + CopyUploadedFile(question); - _context.Add(question); + _context.Add(question as Question); await _context.SaveChangesAsync(); var section = _context.Sections.FirstOrDefault(s => s.Id == question.SectionId); return RedirectToAction(nameof(Index), "Home", new { categoryId = section.CategoryId }); @@ -66,7 +71,16 @@ namespace MultipleChoiceTrainer.Controllers return NotFound(); } ViewData["Section"] = _context.Sections.Include(e => e.Category).FirstOrDefault(s => s.Id == question.SectionId); - return View(question); + + var vm = new QuestionViewModel() + { + Choices = question.Choices, + Image = question.Image, + Id = question.Id, + SectionId = question.SectionId, + Text = question.Text + }; + return View(vm); } // POST: Questions/Edit/5 @@ -74,7 +88,7 @@ namespace MultipleChoiceTrainer.Controllers // more details, see http://go.microsoft.com/fwlink/?LinkId=317598. [HttpPost] [ValidateAntiForgeryToken] - public async Task Edit(int id, Question question) + public async Task Edit(int id, QuestionViewModel question) { if (id != question.Id) { @@ -87,9 +101,10 @@ namespace MultipleChoiceTrainer.Controllers question.Choices = question.Choices.ToList().Where(e => !string.IsNullOrEmpty(e.Text) && !string.IsNullOrWhiteSpace(e.Text)).ToList(); + CopyUploadedFile(question); try { - _context.Update(question); + _context.Update(question as Question); await _context.SaveChangesAsync(); if(deletedChoices.Any()) @@ -120,5 +135,21 @@ namespace MultipleChoiceTrainer.Controllers { return _context.Questions.Any(e => e.Id == id); } + + private void CopyUploadedFile(QuestionViewModel model) + { + if (model.QuestionImage != null) + { + string uploadsFolder = Path.Combine(_webHostEnvironment.WebRootPath, "uploads", "images", "questions"); + Directory.CreateDirectory(uploadsFolder); + + model.Image = Guid.NewGuid().ToString() + Path.GetExtension(model.QuestionImage.FileName); + string filePath = Path.Combine(uploadsFolder, model.Image); + using (var fileStream = new FileStream(filePath, FileMode.Create)) + { + model.QuestionImage.CopyTo(fileStream); + } + } + } } } diff --git a/MultipleChoiceTrainer/Models/DataModels/Question.cs b/MultipleChoiceTrainer/Models/DataModels/Question.cs index b882490..1abc8fa 100644 --- a/MultipleChoiceTrainer/Models/DataModels/Question.cs +++ b/MultipleChoiceTrainer/Models/DataModels/Question.cs @@ -18,6 +18,8 @@ namespace MultipleChoiceTrainer.Models.DataModels public Section Section { get; set; } public int SectionId { get; set; } + public string Image { get; set; } + [Display(Name = "Antwortmöglichkeiten")] [NotEmptyChoiceCollection()] public List Choices { get; set; } diff --git a/MultipleChoiceTrainer/Models/QuestionViewModel.cs b/MultipleChoiceTrainer/Models/QuestionViewModel.cs new file mode 100644 index 0000000..72befa6 --- /dev/null +++ b/MultipleChoiceTrainer/Models/QuestionViewModel.cs @@ -0,0 +1,16 @@ +using Microsoft.AspNetCore.Http; +using MultipleChoiceTrainer.Models.DataModels; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; + +namespace MultipleChoiceTrainer.Models +{ + public class QuestionViewModel : Question + { + [Display(Name ="Bild zur Frage")] + public IFormFile QuestionImage { get; set; } + } +} diff --git a/MultipleChoiceTrainer/Views/Questions/Create.cshtml b/MultipleChoiceTrainer/Views/Questions/Create.cshtml index a3d86bc..f62b7d6 100644 --- a/MultipleChoiceTrainer/Views/Questions/Create.cshtml +++ b/MultipleChoiceTrainer/Views/Questions/Create.cshtml @@ -1,4 +1,4 @@ -@model MultipleChoiceTrainer.Models.DataModels.Question +@model MultipleChoiceTrainer.Models.QuestionViewModel @{ ViewData["Title"] = "Frage Anlegen"; @@ -9,7 +9,7 @@
-
+
@@ -17,31 +17,37 @@
+
+
+ + +
+
@for (int i = 0; i < 5; i++) { -
- @if (Model != null && Model.Choices != null && Model.Choices.Count > i) - { - -
- - -
- } - else - { - -
- - -
- } -
+
+ @if (Model != null && Model.Choices != null && Model.Choices.Count > i) + { + +
+ + +
+ } + else + { + +
+ + +
+ } +
} - +
diff --git a/MultipleChoiceTrainer/Views/Questions/Edit.cshtml b/MultipleChoiceTrainer/Views/Questions/Edit.cshtml index 5da25e8..706d12f 100644 --- a/MultipleChoiceTrainer/Views/Questions/Edit.cshtml +++ b/MultipleChoiceTrainer/Views/Questions/Edit.cshtml @@ -1,4 +1,4 @@ -@model MultipleChoiceTrainer.Models.DataModels.Question +@model MultipleChoiceTrainer.Models.QuestionViewModel @{ ViewData["Title"] = "Frage bearbeiten"; @@ -9,7 +9,7 @@
- +
@@ -19,32 +19,39 @@
+
+
+ + +
+ +
@for (int i = 0; i < 5; i++) { -
- @if (Model != null && Model.Choices != null && Model.Choices.Count > i) - { - - -
- - -
- } - else - { - -
- - -
- } -
+
+ @if (Model != null && Model.Choices != null && Model.Choices.Count > i) + { + + +
+ + +
+ } + else + { + +
+ + +
+ } +
} - +
diff --git a/MultipleChoiceTrainer/Views/Shared/_Layout.cshtml b/MultipleChoiceTrainer/Views/Shared/_Layout.cshtml index 9bc57cc..cc00f32 100644 --- a/MultipleChoiceTrainer/Views/Shared/_Layout.cshtml +++ b/MultipleChoiceTrainer/Views/Shared/_Layout.cshtml @@ -41,10 +41,15 @@ + @RenderSection("Scripts", required: false) diff --git a/MultipleChoiceTrainer/wwwroot/js/bs-custom-file-input.min.js b/MultipleChoiceTrainer/wwwroot/js/bs-custom-file-input.min.js new file mode 100644 index 0000000..d9af3b1 --- /dev/null +++ b/MultipleChoiceTrainer/wwwroot/js/bs-custom-file-input.min.js @@ -0,0 +1,7 @@ +/*! + * bsCustomFileInput v1.3.2 (https://github.com/Johann-S/bs-custom-file-input) + * Copyright 2018 - 2019 Johann-S + * Licensed under MIT (https://github.com/Johann-S/bs-custom-file-input/blob/master/LICENSE) + */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).bsCustomFileInput=t()}(this,function(){"use strict";var d={CUSTOMFILE:'.custom-file input[type="file"]',CUSTOMFILELABEL:".custom-file-label",FORM:"form",INPUT:"input"},r=function(e){if(0