Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions exercise.wwwapi/Configuration/ConfigurationSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace exercise.wwwapi.Configuration
{
public class ConfigurationSettings : IConfigurationSettings
{
IConfiguration _conf;
public ConfigurationSettings()
{
_conf = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
}
public T GetValue<T>(string key)
{
return _conf.GetValue<T>(key)!;
}
}
}
7 changes: 7 additions & 0 deletions exercise.wwwapi/Configuration/IConfigurationSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace exercise.wwwapi.Configuration
{
public interface IConfigurationSettings
{
public T GetValue<T>(string key);
}
}
39 changes: 39 additions & 0 deletions exercise.wwwapi/DTO/AbstractClasses/DTO_Auth_Request.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Net;
using System.Text.Json.Serialization;
using api_cinema_challenge.Models.Interfaces;
using api_cinema_challenge.Repository;
using exercise.wwwapi.Configuration;
using exercise.wwwapi.Payload;

namespace api_cinema_challenge.DTO.Interfaces
{
/// <summary>
/// Special base class inherited by anything requireing authentication, returns a payload with token;
/// </summary>
public abstract class DTO_Auth_Request<Model_Type>
where Model_Type : class,ICustomModel, new()
{
[JsonIgnore]
private string? _auth_token = null;
public static async Task<object?> authenticate(DTO_Auth_Request<Model_Type> dto, IRepository<Model_Type> repo, IConfigurationSettings conf)
{
Model_Type? model = await dto.ReturnCreatedInstanceModel(repo);
if (model == null) throw new HttpRequestException("requested object does not exist", null, HttpStatusCode.NotFound);
if (!await dto.VerifyRequestedModelAgainstDTO(repo, model)) throw new HttpRequestException("Wrong password", null, HttpStatusCode.NotFound);

dto._auth_token = await dto.CreateAndReturnJWTToken(repo, model, conf);
return dto._auth_token;
}
public static Payload<string, string> toPayloadAuth(DTO_Auth_Request<Model_Type> dto)
{
var p = new Payload<string, string>();
p.Data = dto._auth_token;
p.Status = dto._auth_token != null ? "success" : "failure";
return p;
}

protected abstract Task<Model_Type?> ReturnCreatedInstanceModel(IRepository<Model_Type> repo);
protected abstract Task<bool> VerifyRequestedModelAgainstDTO(IRepository<Model_Type> repo, Model_Type model);
protected abstract Task<string> CreateAndReturnJWTToken(IRepository<Model_Type> repo, Model_Type model, IConfigurationSettings conf);
}
}
30 changes: 30 additions & 0 deletions exercise.wwwapi/DTO/AbstractClasses/DTO_Request_create.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Security.Claims;
using api_cinema_challenge.Models.Interfaces;
using api_cinema_challenge.Repository;
using exercise.wwwapi.Models;

namespace api_cinema_challenge.DTO.Interfaces
{
/// <summary>
/// Special base class for all DTO that preforms a new Creation
/// </summary>
public abstract class DTO_Request_create<Model_type>
where Model_type : class, ICustomModel, new()
{
protected abstract Func<IQueryable<Model_type>, IQueryable<Model_type>> GetEntryWithIncludes(Model_type createdEntity , params object[] id);
public abstract Model_type CreateAndReturnNewInstance(ClaimsPrincipal user,params object[] pathargs);
protected virtual bool CheckConditionForValidCreate(ClaimsPrincipal user, Model_type createdModel,params object[] pathargs)
{
return true;
}
public async Task<Model_type> Create(IRepository<Model_type> repo, ClaimsPrincipal user, params object[] pathargs)
{
var model = CreateAndReturnNewInstance(user, pathargs);
if(!CheckConditionForValidCreate(user, model, pathargs)) throw new HttpRequestException($"Create condition was not met for creating {typeof(Model_type).Name}", null, System.Net.HttpStatusCode.BadRequest);
var createdEntity = await repo.CreateEntry(model);
if (createdEntity == null) throw new HttpRequestException("Bad Creation request", null, System.Net.HttpStatusCode.BadRequest);

return await repo.GetEntry(GetEntryWithIncludes(createdEntity, pathargs));
}
}
}
28 changes: 28 additions & 0 deletions exercise.wwwapi/DTO/AbstractClasses/DTO_Request_delete.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Net;
using System.Security.Claims;
using api_cinema_challenge.Models;
using api_cinema_challenge.Models.Interfaces;
using api_cinema_challenge.Repository;
using exercise.wwwapi.Models;

namespace api_cinema_challenge.DTO.Interfaces
{
/// <summary>
/// Special base class for all DTO that preforms a deletion
/// </summary>
public abstract class DTO_Request_delete<Model_Type>
where Model_Type : class, ICustomModel, new()
{
protected abstract Func<IQueryable<Model_Type>, IQueryable<Model_Type>> getId(params object[] id);
protected abstract bool VerifRightsToDelete(ClaimsPrincipal user, Model_Type fetchedModel);
public async Task<Model_Type> Delete(IRepository<Model_Type> repo, ClaimsPrincipal user,params object[] id)
{
var query = getId(id);
var fetchedModel = await repo.GetEntry(query);
if (fetchedModel == null) throw new HttpRequestException("requested object does not exist", null, HttpStatusCode.NotFound);
if (!VerifRightsToDelete(user, fetchedModel)) throw new HttpRequestException($"requested object is not owned by user {int.Parse(user.FindFirst(ClaimTypes.Sid)!.Value)}", null, HttpStatusCode.Unauthorized);

return await repo.DeleteEntry(query);
}
}
}
28 changes: 28 additions & 0 deletions exercise.wwwapi/DTO/AbstractClasses/DTO_Request_update.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Net;
using System.Security.Claims;
using api_cinema_challenge.Models.Interfaces;
using api_cinema_challenge.Repository;

namespace api_cinema_challenge.DTO.Interfaces
{
/// <summary>
/// Special base class for all DTO that updates a entity
/// </summary>
public abstract class DTO_Request_update<Model_Type>
where Model_Type : class,ICustomModel, new()
{
protected abstract Func<IQueryable<Model_Type>, IQueryable<Model_Type>> getId(params object[] id);
protected abstract bool VerifRightsToUpdate(ClaimsPrincipal user, Model_Type fetchedModel);
protected abstract Model_Type CreateAndReturnUpdatedInstance(Model_Type originalModelData);
public async Task<Model_Type> Update(IRepository<Model_Type> repo, ClaimsPrincipal user, params object[] id)
{
var query = getId(id);
var fetchedModel = await repo.GetEntry(query);
if (!VerifRightsToUpdate(user, fetchedModel)) throw new HttpRequestException($"requested object is not owned by user {int.Parse(user.FindFirst(ClaimTypes.Sid)!.Value)}", null, HttpStatusCode.Unauthorized);
if (fetchedModel == null) throw new HttpRequestException("requested object does not exist", null, HttpStatusCode.NotFound);
var model = CreateAndReturnUpdatedInstance(fetchedModel);

return await repo.UpdateEntry(query, model);
}
}
}
194 changes: 194 additions & 0 deletions exercise.wwwapi/DTO/AbstractClasses/DTO_Response.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
using System.Diagnostics;
using api_cinema_challenge.Models;
using api_cinema_challenge.Models.Interfaces;
using api_cinema_challenge.Repository;
using exercise.wwwapi.Models;
using exercise.wwwapi.Payload;
using Microsoft.EntityFrameworkCore.Metadata;

namespace api_cinema_challenge.DTO.Interfaces
{
public interface IDTO_Defines_Include<Model_Type>
where Model_Type : class, ICustomModel
{
public static abstract Func<IQueryable<Model_Type>, IQueryable<Model_Type>> _includeData();
}
/// <summary>
/// The abstract DTO_Response class contains many generic functions to turn a model into a DTO, and package into a payload...
/// </summary>
public abstract class DTO_Response<DTO_Type, Model_Type>
where DTO_Type : DTO_Response<DTO_Type, Model_Type>, new()
where Model_Type : class, ICustomModel
{
public DTO_Response() { }
protected abstract void _Initialize(Model_Type model);

public void Initialize(Model_Type model)
{
try
{
_Initialize(model);
}
catch(ArgumentNullException ex)
{
throw new NotImplementedException($"{this.GetType().Name} does not implement the `{nameof(IDTO_Defines_Include<Model_Type>)}` interface; Implement that interface to avoid null references by returning the include query");
}
catch (NullReferenceException ex)
{
throw new NotImplementedException($"{this.GetType().Name} does not implement the `{nameof(IDTO_Defines_Include<Model_Type>)}` interface; Implement that interface to avoid null references by returning the include query");
}
}

public static async Task<IEnumerable<DTO_Type>> Gets(IRepository<Model_Type> repo)
{
IEnumerable<Model_Type> list = await repo.GetEntries();

return list.Select(x => { var a = new DTO_Type(); a.Initialize(x); return a; }).ToList();
}
public static async Task<IEnumerable<DTO_Type>> Gets(IRepository<Model_Type> repo, Func<IQueryable<Model_Type>, IQueryable<Model_Type>>? WhereQuery)
{
IEnumerable<Model_Type> list = await repo.GetEntries(WhereQuery);

return list.Select(x => { var a = new DTO_Type(); a.Initialize(x); return a; }).ToList();
}

public static async Task<IEnumerable<DTO_Type>> Gets<T>(IRepository<T> repo, Func<IQueryable<T>, IQueryable<T>>? WhereQuery = null, Func<IEnumerable<T>, IEnumerable<Model_Type>>? selectorfunc = null)
where T : class, ICustomModel
{
IEnumerable<Model_Type> list;
if (WhereQuery == null) list = selectorfunc!.Invoke(await repo.GetEntries()).ToList();
else
{
list = selectorfunc.Invoke(await repo.GetEntries(WhereQuery)).ToList();

}

return list.Select(x => { var a = new DTO_Type(); a.Initialize(x); return a; }).ToList();
}

public static IEnumerable<DTO_Type> Gets<T>(IEnumerable<T> models, Func<IEnumerable<T>, IEnumerable<Model_Type>>? selectorfunc)
where T : class, ICustomModel
{
IEnumerable<Model_Type> list = selectorfunc.Invoke(models).ToList();

return list.Select(x => { var a = new DTO_Type(); a.Initialize(x); return a; }).ToList();
}

public static IEnumerable<DTO_Type> Gets(IEnumerable<Model_Type> models)
{
return models.Select(x => { var a = new DTO_Type(); a.Initialize(x); return a; }).ToList();
}

public static Payload<DTO_Type,Model_Type> toPayload(Model_Type model, string status = "success")
{
var a = new DTO_Type();
a.Initialize(model);

var p = new Payload<DTO_Type,Model_Type>();
p.Data = a;
p.Status = status;
return p;
}
public static Payload<IEnumerable<DTO_Type>, Model_Type> toPayload(IEnumerable<Model_Type> models, string status = "success")
{
var list = models.Select(x => { var a = new DTO_Type(); a.Initialize(x); return a; }).ToList();

var p = new Payload<IEnumerable<DTO_Type>,Model_Type>();
p.Data = list;
p.Status = status;
return p;
}
public static Payload<IEnumerable<DTO_Type>, Model_Type> toPayload(IEnumerable<DTO_Type> modelsDtoList, string status = "success")
{
var p = new Payload<IEnumerable<DTO_Type>,Model_Type>();
p.Data = modelsDtoList;
p.Status = status;
return p;
}

public static async Task<Payload<IEnumerable<DTO_Type>, Model_Type>> toPayload(IRepository<Model_Type> repo, string status = "success")

{
try
{
var p = new Payload<IEnumerable<DTO_Type>, Model_Type>();
var include_interf = typeof(DTO_Type).GetInterface(typeof(IDTO_Defines_Include<Model_Type>).Name);
if (include_interf != null)
{
var methodInfo = typeof(DTO_Type).GetMethod(
nameof(IDTO_Defines_Include<Model_Type>._includeData),
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
try
{
var queryArgs = (Func<IQueryable<Model_Type>, IQueryable<Model_Type>>)methodInfo.Invoke(null,null);
p.Data = await Gets(repo, queryArgs);
}
catch(ArgumentNullException ex)
{
throw new NotImplementedException($"{typeof(DTO_Type).Name} does not Include all members of {ex.TargetSite.DeclaringType.Name} in their `{nameof(IDTO_Defines_Include<Model_Type>)}` function; Ensure to include all required includes for {ex.TargetSite.DeclaringType.Name} dto class");
}
catch(NullReferenceException ex)
{
throw new NotImplementedException($"{typeof(DTO_Type).Name} does not Include all members of {ex.TargetSite.DeclaringType.Name} in their `{nameof(IDTO_Defines_Include<Model_Type>)}` function; Ensure to include all required includes for {ex.TargetSite.DeclaringType.Name} dto class");
}
}
else
p.Data = await Gets(repo);
p.Status = status;
return p;
}
catch (HttpRequestException ex)
{
var p = new Payload<IEnumerable<DTO_Type>, Model_Type>();
p.Data = [];
p.Status = "Failure";
return p;
}

}

public static async Task<Payload<IEnumerable<DTO_Type>, Model_Type>> toPayload<T>(IRepository<T> repo, Func<IQueryable<T>, IQueryable<T>> WhereQuery
, Func<IEnumerable<T>, IEnumerable<Model_Type>>? selectorfunc
, string status = "success"
)
where T : class, ICustomModel
{

try
{
var p = new Payload<IEnumerable<DTO_Type>, Model_Type>();
p.Data = await Gets<T>(repo, WhereQuery, selectorfunc);
p.Status = status;
return p;
}
catch (HttpRequestException ex)
{
var p = new Payload<IEnumerable<DTO_Type>, Model_Type>();
p.Data = [];
p.Status = "Failure";
return p;
}
}

public static async Task<Payload<IEnumerable<DTO_Type>, Model_Type>> toPayload(IRepository<Model_Type> repo, Func<IQueryable<Model_Type>, IQueryable<Model_Type>>? WhereQuery, string status = "success")
{
try
{
var p = new Payload<IEnumerable<DTO_Type>, Model_Type>();
p.Data = await Gets(repo, WhereQuery);
p.Status = status;
return p;
}
catch (HttpRequestException ex)
{
var p = new Payload<IEnumerable<DTO_Type>, Model_Type>();
p.Data = [];
p.Status = "Failure";
return p;
}

}


}
}
Loading