private dynamic PatchResource( IRequest request, HttpRequestMethod requestMethod, PermissionHandler <TRelation, TUser> permissionHandler, string jsonData) { var jsonResolver = new APIJsonResolver <TRelation, TUser> { DbContext = dbContext, PermissionHandler = permissionHandler, ModelAction = ModelAction.Create, RequestMethod = requestMethod, IRequest = request, EngineService = EngineService, IncludeKey = true, IncludeBindNever = false }; var serializerSettings = JsonConvert.DefaultSettings(); serializerSettings.ContractResolver = jsonResolver; var model = JsonConvert.DeserializeObject( jsonData, request.Temp_ResourceType, serializerSettings); var oldModel = APIUtils.GetResource(dbContext, request); if (oldModel == null) { return(new NotFoundResult()); } if (oldModel is IdentityUser) { return(new BadRequestObjectResult(new APIError { Message = "User model can not edited by general api, this must be handled using an special AccountController." })); } var modelKey = model.GetType().GetPropertiesWithAttribute(typeof(KeyAttribute)).FirstOrDefault(); if (modelKey == null) { return(new ForbidResult()); } if (request.IdentifierName != modelKey.Name) { var identifierProperty = model.GetType().GetCustomAttributes <IdentifierValidatorAttribute> () .Where(attribute => attribute.PropertyName == request.IdentifierName) .FirstOrDefault(); if (identifierProperty == null) { return(new ForbidResult()); } modelKey.SetValue(model, modelKey.GetValue(oldModel)); } var modelKeyValue = modelKey.GetValue(model).ToString(); var isValidIdentifier = modelKeyValue != null && modelKeyValue != request.IdentifierValue; if (!isValidIdentifier || !verifyModelRelationChain(model)) { return(BadRequest(new APIError { Message = "Error: Invalid relation in received model, it can be happend when you are not " + "permitted for this action or there are some invalid id(s)." })); } // dbContext.Update (model); // ExcludeAttributes (model); IncludeAttributes(model); var intraction = new ModelInteraction <TRelation> { CreatorId = permissionHandler.getRequesterID(), FirstModelId = permissionHandler.getRequesterID(), SecondModelId = modelKeyValue, ModelAction = ModelAction.Update }; dbContext.MagicAddIntraction(intraction, EngineService.MapRelationToType("Global")); dbContext.SaveChanges(); EngineService.OnResourcePatched(dbContext, request, model); return(new OkResult()); }
public dynamic ReadCardList( string resourceName, string requesterID, string cursor ) { Cursor objCursor = null; if (cursor != null && !string.IsNullOrWhiteSpace(cursor)) { try { var decryptedCursor = cursor.DecryptString( engineService.GetCursorEncryptionKey() ); objCursor = JsonConvert.DeserializeObject <Cursor> (decryptedCursor); } catch (Exception) { } } var maxPage = engineService.GetMaxRangeReadPage(resourceName); var maxOPP = engineService.GetMaxRangeReadObjectPerPage(resourceName); if (objCursor == null) { objCursor = new Cursor(requesterID, resourceName); } else { if (objCursor.isExpired()) { return(new BadRequestObjectResult(new APIError { Message = "Cursor time limit has been expired." })); } if (objCursor.RequesterID != requesterID || objCursor.IssuedFor != resourceName) { return(new BadRequestObjectResult(new APIError { Message = "Cursor has been issued for someone else." })); } if (objCursor.PageNumber < 1 || objCursor.PageNumber > maxPage || objCursor.ObjPerPage < 1 || objCursor.ObjPerPage > maxOPP) { return(new BadRequestObjectResult(new APIError { Message = "Cursor page number or object/page is out of bound." })); } } var resourceType = modelParser.IsRangeReaderAllowed(resourceName); if (resourceType == null) { return(new NotFoundResult()); } var endPoint = objCursor.PageNumber * objCursor.ObjPerPage; var startpoint = endPoint - objCursor.ObjPerPage; var rangeAttribute = resourceType.GetCustomAttribute <RangeReaderAllowedAttribute> (); if (endPoint > rangeAttribute.MaxObjToRead) { return(new BadRequestObjectResult(new APIError { Message = "Requested range is exceeded from resource limitations (" + rangeAttribute.MaxObjToRead + ")" })); } var nextCursor = string.Empty; if (endPoint + objCursor.ObjPerPage <= rangeAttribute.MaxObjToRead && objCursor.PageNumber <= maxPage && objCursor.ObjPerPage <= maxOPP) { try { nextCursor = JsonConvert.SerializeObject( new Cursor( requesterID, resourceName, objCursor.PageNumber + 1, objCursor.ObjPerPage ) ) .EncryptString(engineService.GetCursorEncryptionKey()); } catch (Exception) { return(new BadRequestObjectResult(new APIError { Message = "Cursor creation has been failed" })); } } APIUtils utils = new APIUtils(); var result = utils.GetResourceWithRange( APIUtils.GetIQueryable(dbContext, resourceType.Name), startpoint, endPoint) as ICollection <Card>; if (result == null || result.Count == 0) { return(new CardList()); } var rangerIdProp = resourceType.GetProperties() .Where(prop => prop.IsDefined(typeof(KeyAttribute), false)) .FirstOrDefault(); var permissionHandler = new PermissionHandler <TRelation, TUser> ( requesterID, modelParser, engineService, dbContext); var iRequest = new IRequest { ResourceName = resourceType.Name, IdentifierName = rangerIdProp.Name }; foreach (var item in result) { iRequest.IdentifierValue = rangerIdProp.GetValue(item).ToString(); permissionHandler.CheckPermissionRequirements( iRequest, ModelAction.Read, HttpRequestMethod.Get, item); } return(new CardList { PageNumber = objCursor.PageNumber, Cursor = nextCursor, Cards = result.ToList(), }); }
private dynamic JoinResourceAsync( IRequest request, IRequest relatedRequest, TRelation relationType, PermissionHandler <TRelation, TUser> permissionHandler, HttpRequestMethod httpRequestMethod) { var oneWayRelation = relatedRequest == null || !relatedRequest.filledWithData(); if (oneWayRelation) { relatedRequest = request; } var resourceType = oneWayRelation ? typeof(TUser) : ModelParser.GetResourceType(request.ResourceName); var relatedResourceType = ModelParser.GetResourceType(relatedRequest.ResourceName); bool firstIdentifierNameIsKey = true; if (!oneWayRelation) { firstIdentifierNameIsKey = resourceType.GetProperties() .Where(property => property.Name.Equals(request.IdentifierName) && property.IsDefined(typeof(KeyAttribute), true)) .Any(); } bool secondIdentifierNameIsKey = relatedResourceType.GetProperties() .Where(prop => prop.Name.Equals(relatedRequest.IdentifierName) && prop.IsDefined(typeof(KeyAttribute), true)) .Any(); if (!firstIdentifierNameIsKey || !secondIdentifierNameIsKey) { return(BadRequest(new APIError { Message = "To create relation only key identifier is acceptable" })); } // Check whether request is exist or not var requestModel = oneWayRelation ? UserManager.FindByIdAsync(permissionHandler.getRequesterID()).Result : APIUtils.GetResource(dbContext, request); if (requestModel == null) { return(NotFound(request)); } // Check if relationType is valid for request var resourceCheck = permissionHandler.ModelValidation( Request: request, ModelType: resourceType, ModelAction: ModelAction.Relate, RequestMethod: httpRequestMethod, RelationType: relationType); if (!(resourceCheck is bool && (bool)resourceCheck)) { return(BadRequest(new APIError { Message = "Request Error: " + resourceCheck })); } // Check whether related request is exist or not var relatedRequestModel = APIUtils.GetResource(dbContext, relatedRequest); if (relatedRequestModel == null) { return(NotFound(relatedRequest)); } // Check if relationType is valid for related request var relatedSourceCheck = permissionHandler.ModelValidation( Request: relatedRequest, ModelType: relatedResourceType, ModelAction: ModelAction.Relate, RequestMethod: httpRequestMethod, RelationType: relationType); if (!(relatedSourceCheck is bool && (bool)relatedSourceCheck)) { return(BadRequest(new APIError { Message = "Request Error: " + relatedSourceCheck })); } if (!oneWayRelation) { // Check if relationType is valid for requesterID var userCheck = permissionHandler.ModelValidation( Request: request, ModelType: typeof(TUser), ModelAction: ModelAction.Relate, RequestMethod: httpRequestMethod, RelationType: relationType); if (!(userCheck is bool && (bool)userCheck)) { return(BadRequest(new APIError { Message = "Request Error: " + userCheck })); } } var intractionType = EngineService.MapRelationToType(relationType.ToString()); var queryable = dbContext.MagicDbSet(intractionType); var FirstModelId = oneWayRelation ? permissionHandler.getRequesterID() : request.IdentifierValue; var SecondModelId = relatedRequest.IdentifierValue; var relation = (queryable as IEnumerable <dynamic>) .Where(intraction => intraction.Valid && ((intraction.ValidUntil == null || intraction.ValidUntil.HasValue == false) || (intraction.ValidUntil.HasValue && DateTime.Now.CompareTo(intraction.ValidUntil.Value) < 0)) && (intraction.CreatorId.Equals(permissionHandler.getRequesterID()) && intraction.FirstModelId.Equals(FirstModelId) && intraction.SecondModelId.Equals(SecondModelId))) .Take(1) .FirstOrDefault(); // Create relation if (httpRequestMethod == HttpRequestMethod.Post) { if (relation != null) { return(new OkObjectResult(relation)); } relation = new ModelInteraction <TRelation> { CreatorId = permissionHandler.getRequesterID(), FirstModelId = FirstModelId, SecondModelId = SecondModelId, IntractionType = relationType }; MagicExtentions.MagicAddIntraction(queryable, relation, intractionType); EngineService.OnRelationCreated(dbContext, request, relatedRequest, relation); } else if (httpRequestMethod == HttpRequestMethod.Delete) { if (relation == null) { return(new OkResult()); } queryable.Remove(relation); relation.Valid = false; relation.ValidUntil = DateTime.Now; relation.Information = "Extinct by " + permissionHandler.getRequesterID(); dbContext.MagicAddIntraction(relation as object, EngineService.MapRelationToType("Invalid")); EngineService.OnRelationDeleted(dbContext, request, relatedRequest, relation); } else { return(BadRequest()); } ResolveRelationDependency( requestModel, permissionHandler.getRequesterID(), request, relatedRequest, relationType, httpRequestMethod); ResolveRelationDependency( relatedRequestModel, permissionHandler.getRequesterID(), request, relatedRequest, relationType, httpRequestMethod); dbContext.SaveChanges(); return(new OkObjectResult(relation)); }
private IActionResult Handle( IRequest request, ModelAction requestedAction, TRelation relationType, IRequest relatedRequest, string jsonObject) { try { // Parse type of request method to something we can understand if (!Enum.TryParse <HttpRequestMethod> ( Request.Method, true, out var httpRequestMethod)) { // Request method is not valid, it must be something like Post, Delete and ... return(BadRequest(new APIError { Message = "Request method is not valid, it must be " + "{Post | Get | Patch | Delete}" })); } var permissionHandler = new PermissionHandler <TRelation, TUser> ( UserManager.GetUserId(User), ModelParser, EngineService, dbContext); //* Security Checks *// //* Check whether this set is consistent or not {HttpRequestMethod, //* IRequest, ModelAction, RelationType} var consistentRequest = permissionHandler.ValidateRequest( httpRequestMethod, request, requestedAction, relationType); if (!(consistentRequest is bool && (bool)consistentRequest)) { return(BadRequest(new APIError { Message = consistentRequest })); } // If this is a relation request if (requestedAction == ModelAction.Relate) { if (relationType == null) { return(BadRequest(new APIError { Message = "Relation type must be determined" })); } if (relatedRequest == null || relatedRequest.ResourceName == null) { // if this isn't a relation request, related input args are better to be empty relatedRequest = null; } else { //* Check whether this set is consistent or not {HttpRequestMethod, //* IRequest, ModelAction, RelationType} var consistentRelatedRequest = permissionHandler.ValidateRequest( httpRequestMethod, relatedRequest, requestedAction, relationType); if (!(consistentRelatedRequest is bool && (bool)consistentRelatedRequest)) { return(BadRequest(new APIError { Message = consistentRelatedRequest })); } } } //* Get which user is trying to send this request switch (requestedAction) { case ModelAction.Create: return(CreateResource( request, httpRequestMethod, permissionHandler, jsonObject)); case ModelAction.Read: return(ReadResource( request, httpRequestMethod, permissionHandler)); case ModelAction.Delete: return(DeleteResource( request, relationType, relatedRequest, permissionHandler)); case ModelAction.Update: return(PatchResource( request, httpRequestMethod, permissionHandler, jsonObject)); case ModelAction.Relate: return(JoinResourceAsync( request, relatedRequest, relationType, permissionHandler, httpRequestMethod)); default: return(BadRequest(new APIError { Message = "Requested ModelAction is not supported yet" })); } } catch (Exception exception) { return(EngineService.OnRequestError(dbContext, exception, this)); } }