Skip to content

Commit

Permalink
incremental
Browse files Browse the repository at this point in the history
  • Loading branch information
clarkis117 committed Aug 5, 2016
1 parent 24197b1 commit daef199
Show file tree
Hide file tree
Showing 15 changed files with 868 additions and 328 deletions.
2 changes: 1 addition & 1 deletion src/GenericMvcUtilities.Test.Library/project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "1.0.0-*",
"version": "1.0.0",

"dependencies": {
"xunit": "2.2.0-beta2-build3300",
Expand Down
279 changes: 186 additions & 93 deletions src/GenericMvcUtilities.Test.Library/project.lock.json

Large diffs are not rendered by default.

22 changes: 18 additions & 4 deletions src/GenericMvcUtilities/Controllers/BaseApiController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using GenericMvcUtilities.Repositories;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
Expand Down Expand Up @@ -82,6 +83,19 @@ protected string FormatExceptionMessage(string message)
return (this.GetType().Name + ": " + message + ": " + typeof(T));
}

[NonAction]
public virtual Task<bool> IsValid(T Model, ModelStateDictionary ModelState, bool updating = false)
{
return Task.FromResult(ModelState.IsValid);
}

[NonAction]
public virtual Task<bool> IsValid(T[] Models, ModelStateDictionary ModelState, bool updating = false)
{
return Task.FromResult(ModelState.IsValid);
}


[NonAction]
protected virtual async Task<ICollection<T>> DifferentalExistance(ICollection<T> items)
{
Expand Down Expand Up @@ -211,7 +225,7 @@ public virtual async Task<IActionResult> Create([FromBody] T item)
{
if (item != null)
{
if (ModelState.IsValid)
if (await IsValid(item, ModelState))
{
//var id = item.Id;

Expand Down Expand Up @@ -280,7 +294,7 @@ public virtual async Task<IActionResult> Creates([FromBody] T[] items)
{
if (items != null)
{
if (ModelState.IsValid)
if (await IsValid(items, ModelState))
{
ICollection<T> differental = await this.DifferentalExistance(items);

Expand Down Expand Up @@ -330,9 +344,9 @@ public virtual async Task<IActionResult> Update(TKey id, [FromBody] T item)
if (id != null && item != null)
{
//Validate Model
if (ModelState.IsValid)
if (await IsValid(item, ModelState, updating: true))
{
//since some things like "consts"
//since some things like "consts" use id arg for query


//Check for item existence
Expand Down
243 changes: 243 additions & 0 deletions src/GenericMvcUtilities/Controllers/IFileApiController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
using GenericMvcUtilities.Models;
using GenericMvcUtilities.Repositories;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace GenericMvcUtilities.Controllers
{
public abstract class IFileApiController<T, TKey> : BaseApiController<T, TKey>
where T : class, IFile<TKey>
where TKey : IEquatable<TKey>
{
public IFileApiController(IRepository<T> repository, ILogger<T> logger) :base(repository, logger)
{

}

protected abstract string[] whiteListedMimes { get; }

//use this to avoid name check on repos that change file name during save
protected bool CheckFileName { get; set; } = true;

//add check to see if it is create or update
public override async Task<bool> IsValid(T Model, ModelStateDictionary ModelState, bool Updating = false)
{
if (await base.IsValid(Model, ModelState))
{
int errors = 0;

//check if name is valid file name
if (CheckFileName)
{
var Filename = Utilities.IsValidFileName(Model.Name);

//check for valid name
if (!Filename.IsValid)
{
errors++;
ModelState.AddModelError(nameof(Model.Name), Filename.ErrorMessage);
}

if (!Updating)
{
//see if any name matches
var NameMatch = await Utilities.IsFileNameUnique<T, TKey>(Model.Name, Repository);

if (!NameMatch.IsValid)
{
errors++;
ModelState.AddModelError(nameof(Model.Name), NameMatch.ErrorMessage);
}
}
}

//check if mime type is valid
var MimeTypeValid = Utilities.IsWhiteListedContentType<T, TKey>(Model, whiteListedMimes);

if (!MimeTypeValid.IsValid)
{
errors++;
ModelState.AddModelError(nameof(Model.ContentType), MimeTypeValid.ErrorMessage);
}

if (errors > 0)
{
return false;
}
else
{
return true;
}
}
else
{
return false;
}
}

public override async Task<bool> IsValid(T[] Models, ModelStateDictionary ModelState, bool updating = false)
{
if (ModelState.IsValid)
{
List<bool> truths = new List<bool>();

foreach (var item in Models)
{
truths.Add(await IsValid(item, ModelState));
}

if (truths.Any(x => x == false))
{
return false;
}
else
{
return true;
}
}
else
{
return false;
}
}

[AcceptVerbs("Get", "Post")]
[Route("[controller]/[action]/")]
public IActionResult VerifyContentType(string ContentType)
{
var whiteListResult = Utilities.IsWhiteListedContentType(ContentType, whiteListedMimes);

if (whiteListResult.IsValid)
{
return Json(data: true);
}
else
{
return Json(data: whiteListResult.ErrorMessage);
}
}

//todo add check to see if its update mode and the file hasnt changed
//if the file has changed then check
//if the file hasn't change dont' check
[AcceptVerbs("Get", "Post")]
[Route("[controller]/[action]/")]
public abstract Task<IActionResult> VerifyName(string Name, TKey Id);
}

public abstract class PairedApiController<TKey, TViewModel, TEntity, TEntityRepo, TFileRepo> : IFileApiController<TViewModel, TKey>
where TKey : IEquatable<TKey>
where TViewModel : class, IRelatedFile<TKey>, new()
where TEntity : class, IModelWithFilename<TKey>
where TFileRepo : IFileRepository<TViewModel, TKey>
where TEntityRepo : IRepository<TEntity>
{
public PairedApiController(PairedRepository<TKey,TViewModel,TEntity,TEntityRepo,TFileRepo> repository, ILogger<TViewModel> logger) : base(repository, logger)
{
_repository = repository;
}

private PairedRepository<TKey, TViewModel, TEntity, TEntityRepo, TFileRepo> _repository;

//todo add check to see if its update mode and the file hasnt changed
//if the file has changed then check
//if the file hasn't change dont' check
[AcceptVerbs("Get", "Post")]
[Route("[controller]/[action]/")]
public override async Task<IActionResult> VerifyName(string Name, TKey Id)
{
bool isValid = false;

var Filename = Utilities.IsValidFileName(Name);

//check for valid name
if (Filename.IsValid)
{
isValid = true;
}
else
{
return Json(data: Filename.ErrorMessage);
}

//if we find both conditions then that means we're updating and the file hasn't changed
if (await _repository._entityRepo.Any(x => x.Id.Equals(Id) && x.Filename == Name))
{
return Json(data: true);
}
else
{
//see if any name matches
var NameMatch = await Utilities.IsFileNameUnique<TViewModel, TKey>(Name, _repository);

if (NameMatch.IsValid)
{
isValid = true;
}
else
{
return Json(data: NameMatch.ErrorMessage);
}

return Json(data: isValid);
}
}


//fixed: fix design oversight to have whole object deleted
[Route("[controller]/[action]/")]
[HttpDelete]
public virtual async Task<IActionResult> PairedDelete(TKey id, TKey parentId)
{
try
{
if (id != null)
{
//Get Item, this causes EF to begin tracking it
var item = await Repository.Get(x => x.Id.Equals(id));

item.ParentObjectId = parentId;

if (item != null)
{
//This causes EF to Remove the Item from the Database
var result = await Repository.Delete(item);

if (result != false)
{
//If success return 201 response
return new NoContentResult();
}
else
{
throw new Exception("Deleting Item Failed");
}
}
else
{
//Send 404 if object is not in Database
return NotFound();
}
}
else
{
//Send 400 Response
return BadRequest("Object Identifier is Null");
}
}
catch (Exception ex)
{
string message = "Deleting Item Failed";

this.Logger.LogError(this.FormatLogMessage(message, this.Request));

throw new Exception(this.FormatExceptionMessage(message), ex);
}
}
}
}
14 changes: 13 additions & 1 deletion src/GenericMvcUtilities/Models/IModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public interface IModelWithFile<TKey> : IModel<TKey>
public interface IModelWithFilename<TKey> : IModel<TKey>
where TKey : IEquatable<TKey>
{
[AutoMapper.Configuration.Conventions.MapTo("Name")]
string Filename { get; set; }
}

Expand All @@ -37,32 +38,43 @@ public interface IFile<TKey> : IModel<TKey> where TKey : IEquatable<TKey>

//replaces Id in File... this is the path to the file
//equal directory name
[AutoMapper.IgnoreMap]
string Path { get; set; }

//file name as it appears on disk
[AutoMapper.Configuration.Conventions.MapTo("Filename")]
string Name { get; set; }

/// <summary>
/// mime content type
/// </summary>
[AutoMapper.IgnoreMap]
string ContentType { get; set; }

/// <summary>
/// encoding type
/// needed to decode data from over the wire transmissions
/// </summary>
[AutoMapper.IgnoreMap]
EncodingType EncodingType { get; set; }

/// <summary>
/// if file facade this will be null
/// </summary>
[AutoMapper.IgnoreMap]
byte[] Data { get; set; }


[AutoMapper.IgnoreMap]
FileInfo FileInfo { get; set; }

bool IsFileBacked();

//FileInfo GetFileInfo();
}

public interface IRelatedFile<TKey> : IFile<TKey>
where TKey : IEquatable<TKey>
{
TKey ParentObjectId { get; set; }
}
}
4 changes: 2 additions & 2 deletions src/GenericMvcUtilities/Repositories/EntityRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ public virtual Task<T> Get(System.Linq.Expressions.Expression<Func<T, bool>> pre
//Throw if query is Canceled
token.ThrowIfCancellationRequested();

return ContextSet.FirstOrDefaultAsync<T>(predicate, token);
return ContextSet.AsNoTracking().FirstOrDefaultAsync<T>(predicate, token);
}
catch (Exception ex)
{
Expand Down Expand Up @@ -552,7 +552,7 @@ public virtual async Task<bool> Delete(T entity)

ContextSet.Remove(entity);

if (await DataContext.SaveChangesAsync() > 0)
if (await DataContext.SaveChangesAsync() >= 0)
{
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/GenericMvcUtilities/Repositories/IFileRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ public Task<bool> Delete(TFile entity)

return Task.FromResult(true);
}
catch (Exception e)
catch (Exception)
{
return Task.FromResult(false);
}
Expand Down
Loading

0 comments on commit daef199

Please sign in to comment.