add custom attribute for file mime type validation #6
@ -38,6 +38,7 @@ namespace pwt_0x01_ng.Areas.Admin.Controllers
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Create(Product product)
|
||||
{
|
||||
if (ModelState.IsValid) {
|
||||
product.ImageSrc = string.Empty;
|
||||
MegaUpload mega_upload = new MegaUpload(hosting_env);
|
||||
await mega_upload.DoMegaUpload(product);
|
||||
@ -45,6 +46,10 @@ namespace pwt_0x01_ng.Areas.Admin.Controllers
|
||||
dbctx.Product.Add(product);
|
||||
await dbctx.SaveChangesAsync();
|
||||
return RedirectToAction(nameof(Select));
|
||||
} else {
|
||||
ViewData["Message"] = "error creating Product";
|
||||
return View(product);
|
||||
}
|
||||
}
|
||||
|
||||
public IActionResult Edit(int id)
|
||||
|
@ -13,4 +13,5 @@
|
||||
|
||||
@section Scripts {
|
||||
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
|
||||
<script defer src="~/js/validation/file_type.js"></script>
|
||||
}
|
||||
|
@ -13,4 +13,5 @@
|
||||
|
||||
@section Scripts {
|
||||
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
|
||||
<script defer src="~/js/validation/file_type.js"></script>
|
||||
}
|
||||
|
@ -12,22 +12,22 @@
|
||||
}}
|
||||
<div class="form-group">
|
||||
<label asp-for="@Model.DataTarget"></label>
|
||||
<input asp-for="@Model.DataTarget" class="form-control" id="inputCarousel" aria-describedby="css selector id of the image" placeholder="Data Target">
|
||||
<input asp-for="@Model.DataTarget" class="form-control" aria-describedby="css selector id of the image" placeholder="Data Target">
|
||||
<span asp-validation-for="@Model.DataTarget" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="@Model.Image"></label>
|
||||
<input asp-for="@Model.Image" accept="image/*" class="form-inline" id="inputCarousel" aria-describedby="the image">
|
||||
<input id="file" asp-for="@Model.Image" accept="image/*" class="form-inline" aria-describedby="the image">
|
||||
<span asp-validation-for="@Model.Image" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="@Model.ImageAlt"></label>
|
||||
<input asp-for="@Model.ImageAlt" class="form-control" id="inputCarousel" aria-describedby="image alt text" placeholder="Image alt">
|
||||
<input asp-for="@Model.ImageAlt" class="form-control" aria-describedby="image alt text" placeholder="Image alt">
|
||||
<span asp-validation-for="@Model.ImageAlt" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="@Model.CarouselContent"></label>
|
||||
<input asp-for="@Model.CarouselContent" class="form-control" id="inputCarousel" aria-describedby="image description" placeholder="Image description">
|
||||
<input asp-for="@Model.CarouselContent" class="form-control" aria-describedby="image description" placeholder="Image description">
|
||||
<span asp-validation-for="@Model.CarouselContent" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
|
@ -12,4 +12,5 @@
|
||||
|
||||
@section Scripts {
|
||||
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
|
||||
<script defer src="~/js/validation/file_type.js"></script>
|
||||
}
|
||||
|
@ -12,4 +12,5 @@
|
||||
|
||||
@section Scripts {
|
||||
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
|
||||
<script defer src="~/js/validation/file_type.js"></script>
|
||||
}
|
||||
|
@ -27,7 +27,7 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="@Model.Image"></label>
|
||||
<input asp-for="@Model.Image" accept="image/*" class="form-inline" aria-describedby="product image">
|
||||
<input id="file" asp-for="@Model.Image" accept="image/*" class="form-inline" aria-describedby="product image">
|
||||
<span asp-validation-for="@Model.Image" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using pwt_0x01_ng.Models.Validation;
|
||||
|
||||
namespace pwt_0x01_ng.Models
|
||||
{
|
||||
@ -10,8 +11,8 @@ namespace pwt_0x01_ng.Models
|
||||
[Required]
|
||||
public string DataTarget { get; set; }
|
||||
[NotMapped]
|
||||
[FileTypeAttr("image")]
|
||||
public IFormFile Image { get; set; }
|
||||
[Required]
|
||||
[StringLength(255)]
|
||||
public string ImageSrc { get; set; }
|
||||
[Required]
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using pwt_0x01_ng.Models.Validation;
|
||||
|
||||
namespace pwt_0x01_ng.Models
|
||||
{
|
||||
@ -13,10 +14,9 @@ namespace pwt_0x01_ng.Models
|
||||
public int Price { get; set; }
|
||||
[Required]
|
||||
public string Description { get; set; }
|
||||
[Required]
|
||||
[FileTypeAttr("image")]
|
||||
[NotMapped]
|
||||
public IFormFile Image { get; set; }
|
||||
[Required]
|
||||
[StringLength(255)]
|
||||
public string ImageSrc { get; set; }
|
||||
[Required]
|
||||
|
48
Models/Validation/FileTypeAttr.cs
Normal file
48
Models/Validation/FileTypeAttr.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||
|
||||
namespace pwt_0x01_ng.Models.Validation
|
||||
{
|
||||
public class FileTypeAttr : ValidationAttribute, IClientModelValidator
|
||||
{
|
||||
private readonly string type;
|
||||
public FileTypeAttr(string type){
|
||||
this.type = type.ToLower();
|
||||
}
|
||||
|
||||
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
|
||||
if (value == null) {
|
||||
/* img is optional as of now */
|
||||
return ValidationResult.Success;
|
||||
} else if (value is IFormFile iff) {
|
||||
if(iff.ContentType.ToLower().Contains(type)) {
|
||||
return ValidationResult.Success;
|
||||
} else {
|
||||
return new ValidationResult(GetErrorMessage(validationContext.MemberName), new List<string> { validationContext.MemberName });
|
||||
}
|
||||
}
|
||||
throw new NotImplementedException($"Attribute {nameof(FileTypeAttr)} not implemented for object {value.GetType()}.");
|
||||
}
|
||||
|
||||
protected string GetErrorMessage(string member_name) => $"make sure the {member_name} you picked really is of type <code>{type}/*</code>. <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types\" title=\"help\" target=\"_blank\" rel=\"noopener noreferer\"><em>help</em></a>";
|
||||
|
||||
public void AddValidation(ClientModelValidationContext ctx){
|
||||
MergeAttribute(ctx.Attributes, "data-val", "true");
|
||||
MergeAttribute(ctx.Attributes, "data-val-content", GetErrorMessage("file"));
|
||||
MergeAttribute(ctx.Attributes, "data-val-content-type", type);
|
||||
}
|
||||
|
||||
private bool MergeAttribute(IDictionary<string, string> attributes, string key, string value){
|
||||
if (attributes.ContainsKey(key)){
|
||||
return false;
|
||||
}
|
||||
|
||||
attributes.Add(key, value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -28,6 +28,7 @@
|
||||
<Folder Include="Migrations\pgsql" />
|
||||
<Folder Include="Models\Database" />
|
||||
<Folder Include="Models\Database\Conf" />
|
||||
<Folder Include="Models\Validation" />
|
||||
<Folder Include="wwwroot\images\carousels" />
|
||||
<Folder Include="wwwroot\images\products" />
|
||||
</ItemGroup>
|
||||
|
25
wwwroot/js/validation/file_type.js
Normal file
25
wwwroot/js/validation/file_type.js
Normal file
@ -0,0 +1,25 @@
|
||||
$.validator.addMethod('content', function (value, element, params) {
|
||||
var f_type = params[1]
|
||||
uploaded_type = "";
|
||||
|
||||
if (!value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (element && element.files && element.files.length > 0) {
|
||||
uploaded_type = element.files[0].type;
|
||||
}
|
||||
|
||||
if (f_type && uploaded_type != "" && uploaded_type.toLowerCase().includes(f_type)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$.validator.unobtrusive.adapters.add('content', ['type'], function (options) {
|
||||
var element = $(options.form).find('#file')[0];
|
||||
|
||||
options.rules['content'] = [element, options.params['type']];
|
||||
options.messages['content'] = options.message;
|
||||
});
|
Reference in New Issue
Block a user