/// <summary> /// Remove the representation. /// </summary> /// <exception cref="System.ArgumentNullException">Thrown when the id is null or empty</exception> /// <param name="id">Representation's id</param> /// <returns>StatusCode with the content.</returns> public async Task <ApiActionResult> Execute( string id) { if (string.IsNullOrWhiteSpace(id)) { throw new ArgumentNullException(nameof(id)); } // 1. Get the representation var representation = await _representationStore.GetRepresentation(id); // 2. If the representation doesn't exist then 404 is returned if (representation == null) { return(_apiResponseFactory.CreateError( HttpStatusCode.NotFound, string.Format(ErrorMessages.TheResourceDoesntExist, id))); } // 3. Remove the representation if (!await _representationStore.RemoveRepresentation(representation)) { return(_apiResponseFactory.CreateError(HttpStatusCode.InternalServerError, ErrorMessages.TheRepresentationCannotBeRemoved)); } // 4. Returns the result. return(_apiResponseFactory.CreateEmptyResult(HttpStatusCode.NoContent, representation.Version, representation.Id)); }
public async Task <ApiActionResult> Execute(JObject jObj, string locationPattern, string schemaId, string resourceType, string id) { if (jObj == null) { throw new ArgumentNullException(nameof(jObj)); } _parametersValidator.ValidateLocationPattern(locationPattern); if (string.IsNullOrWhiteSpace(schemaId)) { throw new ArgumentNullException(nameof(schemaId)); } if (string.IsNullOrWhiteSpace(resourceType)) { throw new ArgumentNullException(nameof(resourceType)); } if (string.IsNullOrWhiteSpace(id)) { throw new ArgumentNullException(nameof(id)); } // 1. Check resource exists. if (await _representationStore.GetRepresentation(id) != null) { return(_apiResponseFactory.CreateError( HttpStatusCode.InternalServerError, string.Format(ErrorMessages.TheResourceAlreadyExist, id))); } // 2. Parse the request var result = await _requestParser.Parse(jObj, schemaId, CheckStrategies.Strong); if (!result.IsParsed) { return(_apiResponseFactory.CreateError(HttpStatusCode.InternalServerError, result.ErrorMessage)); } // 3. Set parameters result.Representation.Id = id; result.Representation.Created = DateTime.UtcNow; result.Representation.LastModified = DateTime.UtcNow; result.Representation.ResourceType = resourceType; result.Representation.Version = Guid.NewGuid().ToString(); // 4. Save the request await _representationStore.AddRepresentation(result.Representation); // 5. Transform and returns the representation. var response = await _responseParser.Parse(result.Representation, locationPattern.Replace("{id}", result.Representation.Id), schemaId, OperationTypes.Modification); return(_apiResponseFactory.CreateResultWithContent(HttpStatusCode.Created, response.Object, response.Location, result.Representation.Version, result.Representation.Id)); }
/// <summary> /// Get the representation. /// </summary> /// <exception cref="ArgumentNullException">Thrown when a parameter is null or empty</exception> /// <param name="identifier">Identifier of the representation.</param> /// <param name="locationPattern">Location pattern of the representation.</param> /// <param name="schemaId">Identifier of the schema.</param> /// <returns>Representation or null if it doesn't exist.</returns> public async Task <ApiActionResult> Execute(string identifier, string locationPattern, string schemaId) { // 1. Check parameters. if (string.IsNullOrWhiteSpace(identifier)) { throw new ArgumentNullException(nameof(identifier)); } _parametersValidator.ValidateLocationPattern(locationPattern); if (string.IsNullOrWhiteSpace(schemaId)) { throw new ArgumentNullException(nameof(schemaId)); } // 2. Check representation exists. var representation = await _representationStore.GetRepresentation(identifier); if (representation == null) { return(_apiResponseFactory.CreateError( HttpStatusCode.NotFound, string.Format(ErrorMessages.TheResourceDoesntExist, identifier))); } // 3. Parse the result and returns the representation. var result = await _responseParser.Parse(representation, locationPattern.Replace("{id}", representation.Id), schemaId, OperationTypes.Query); return(_apiResponseFactory.CreateResultWithContent(HttpStatusCode.OK, result.Object, result.Location, representation.Version, representation.Id)); }
public async Task <ApiActionResult> Execute(string id, JObject jObj, string schemaId, string locationPattern) { // 1. Check parameters. if (string.IsNullOrWhiteSpace(id)) { throw new ArgumentNullException(nameof(id)); } if (jObj == null) { throw new ArgumentNullException(nameof(jObj)); } if (string.IsNullOrWhiteSpace(schemaId)) { throw new ArgumentNullException(nameof(schemaId)); } _parametersValidator.ValidateLocationPattern(locationPattern); // 2. Check representation exists var representation = await _representationStore.GetRepresentation(id); if (representation == null) { return(_apiResponseFactory.CreateError( HttpStatusCode.NotFound, string.Format(ErrorMessages.TheResourceDoesntExist, id))); } // 3. Get patch operations. ErrorResponse errorResponse; var operations = _patchRequestParser.Parse(jObj, out errorResponse); if (operations == null) { return(_apiResponseFactory.CreateError( (HttpStatusCode)errorResponse.Status, errorResponse)); } // 4. Process operations. foreach (var operation in operations) { // 4.1 Check path is filled-in. if (operation.Type == PatchOperations.remove && string.IsNullOrWhiteSpace(operation.Path)) { return(_apiResponseFactory.CreateError( HttpStatusCode.BadRequest, _errorResponseFactory.CreateError(ErrorMessages.ThePathNeedsToBeSpecified, HttpStatusCode.BadRequest, Common.Constants.ScimTypeValues.InvalidSyntax))); } // 4.2 Check value is filled-in. if ((operation.Type == PatchOperations.add || operation.Type == PatchOperations.replace) && operation.Value == null) { return(_apiResponseFactory.CreateError( HttpStatusCode.BadRequest, _errorResponseFactory.CreateError(ErrorMessages.TheValueNeedsToBeSpecified, HttpStatusCode.BadRequest, Common.Constants.ScimTypeValues.InvalidSyntax))); } // 4.3 Process filter & get values. IEnumerable <RepresentationAttribute> attrs = null; IEnumerable <RepresentationAttribute> filteredAttrs = null; if (!string.IsNullOrWhiteSpace(operation.Path)) { // 4.3.1 Process filter. var filter = _filterParser.Parse(operation.Path); var filtered = filter.Evaluate(representation); if (filtered == null || !filtered.Any()) { return(_apiResponseFactory.CreateError( HttpStatusCode.BadRequest, _errorResponseFactory.CreateError(ErrorMessages.TheFilterIsNotCorrect, HttpStatusCode.BadRequest, Common.Constants.ScimTypeValues.InvalidFilter) )); } // 4.3.2 Get targeted attributes. var target = _filterParser.GetTarget(operation.Path); var filterRepresentation = _filterParser.Parse(target); attrs = filterRepresentation.Evaluate(representation); if (operation.Type == PatchOperations.remove) { // 4.3.3 If operation = remove then values are not retrieved. filteredAttrs = filtered; } else { // 4.3.4 if operation = replace or add then retrieve values. var name = filtered.First().SchemaAttribute.Name; var token = operation.Value.SelectToken(name); if (token == null) { token = new JObject(); token[name] = operation.Value; } var value = _jsonParser.GetRepresentation(token, filtered.First().SchemaAttribute, CheckStrategies.Standard); if (!value.IsParsed) { return(_apiResponseFactory.CreateError( HttpStatusCode.BadRequest, _errorResponseFactory.CreateError(value.ErrorMessage, HttpStatusCode.BadRequest, Common.Constants.ScimTypeValues.InvalidSyntax))); } filteredAttrs = new[] { value.RepresentationAttribute }; } } // 4.4 If there's no filter then parse the value with the schema. if (filteredAttrs == null) { if (operation.Value != null) { var repr = await _representationRequestParser.Parse(operation.Value, schemaId, CheckStrategies.Standard); if (!repr.IsParsed) { return(_apiResponseFactory.CreateError( HttpStatusCode.BadRequest, _errorResponseFactory.CreateError(repr.ErrorMessage, HttpStatusCode.BadRequest, Common.Constants.ScimTypeValues.InvalidSyntax))); } filteredAttrs = repr.Representation.Attributes; attrs = representation.Attributes; } } foreach (var filteredAttr in filteredAttrs) { var attr = attrs.FirstOrDefault(a => a.SchemaAttribute.Name == filteredAttr.SchemaAttribute.Name); // 4.5.1 Check mutability. if (filteredAttr.SchemaAttribute.Mutability == Common.Constants.SchemaAttributeMutability.Immutable || filteredAttr.SchemaAttribute.Mutability == Common.Constants.SchemaAttributeMutability.ReadOnly) { return(_apiResponseFactory.CreateError( HttpStatusCode.BadRequest, _errorResponseFactory.CreateError(string.Format(ErrorMessages.TheImmutableAttributeCannotBeUpdated, filteredAttr.SchemaAttribute.Name), HttpStatusCode.BadRequest, Common.Constants.ScimTypeValues.Mutability))); } // 4.5.2 Check uniqueness if (filteredAttr.SchemaAttribute.Uniqueness == Common.Constants.SchemaAttributeUniqueness.Server) // TH : SELECT THE VALUE AND CHECK THE UNIQUENESS. { var filter = _filterParser.Parse(filteredAttr.FullPath); var uniqueAttrs = await _representationStore.SearchValues(representation.ResourceType, filter); if (uniqueAttrs.Any()) { if (uniqueAttrs.Any(a => a.CompareTo(filteredAttr) == 0)) { return(_apiResponseFactory.CreateError( HttpStatusCode.BadRequest, _errorResponseFactory.CreateError(string.Format(ErrorMessages.TheAttributeMustBeUnique, filteredAttr.SchemaAttribute.Name), HttpStatusCode.BadRequest, Common.Constants.ScimTypeValues.Uniqueness))); } } } switch (operation.Type) { // 4.5.3.1 Remove attributes. case PatchOperations.remove: if (attr == null) { return(_apiResponseFactory.CreateError( HttpStatusCode.BadRequest, _errorResponseFactory.CreateError(string.Format(ErrorMessages.TheAttributeDoesntExist, filteredAttr.SchemaAttribute.Name), HttpStatusCode.BadRequest) )); } if (filteredAttr.SchemaAttribute.MultiValued) { // 4.5.3.1.1 Remove attribute from array if (!Remove(attr, filteredAttr)) { return(_apiResponseFactory.CreateError( HttpStatusCode.BadRequest, _errorResponseFactory.CreateError(ErrorMessages.TheRepresentationCannotBeRemoved, HttpStatusCode.BadRequest) )); } } else { // 4.5.3.1.2 Remove attribute from complex representation. if (attr.Parent != null) { var complexParent = attr.Parent as ComplexRepresentationAttribute; if (complexParent == null) { continue; } complexParent.Values = complexParent.Values.Where(v => !v.Equals(attr)); } else { representation.Attributes = representation.Attributes.Where(v => !v.Equals(attr)); } } break; // 4.5.3.2 Add attribute. case PatchOperations.add: if (string.IsNullOrWhiteSpace(operation.Path) && attr == null) { representation.Attributes = representation.Attributes.Concat(new[] { filteredAttr }); continue; } if (attr == null) { return(_apiResponseFactory.CreateError( HttpStatusCode.BadRequest, _errorResponseFactory.CreateError(string.Format(ErrorMessages.TheAttributeDoesntExist, filteredAttr.SchemaAttribute.Name), HttpStatusCode.BadRequest) )); } if (!filteredAttr.SchemaAttribute.MultiValued) { if (!Set(attr, filteredAttr)) { return(_apiResponseFactory.CreateError( HttpStatusCode.BadRequest, _errorResponseFactory.CreateError(ErrorMessages.TheRepresentationCannotBeSet, HttpStatusCode.BadRequest) )); } } else { if (!Add(attr, filteredAttr)) { return(_apiResponseFactory.CreateError( HttpStatusCode.BadRequest, _errorResponseFactory.CreateError(ErrorMessages.TheRepresentationCannotBeAdded, HttpStatusCode.BadRequest) )); } } break; // 4.5.3.3 Replace attribute case PatchOperations.replace: if (attr == null) { return(_apiResponseFactory.CreateError( HttpStatusCode.BadRequest, _errorResponseFactory.CreateError(string.Format(ErrorMessages.TheAttributeDoesntExist, filteredAttr.SchemaAttribute.Name), HttpStatusCode.BadRequest) )); } if (attr.SchemaAttribute.MultiValued) { if (!SetEnum(attr, filteredAttr)) { return(_apiResponseFactory.CreateError( HttpStatusCode.BadRequest, _errorResponseFactory.CreateError(ErrorMessages.TheRepresentationCannotBeSet, HttpStatusCode.BadRequest) )); } } else { if (!Set(attr, filteredAttr)) { return(_apiResponseFactory.CreateError( HttpStatusCode.BadRequest, _errorResponseFactory.CreateError(ErrorMessages.TheRepresentationCannotBeSet, HttpStatusCode.BadRequest) )); } } break; } } } // 5. Save the representation. representation.Version = Guid.NewGuid().ToString(); await _representationStore.UpdateRepresentation(representation); // 6. Returns the JSON representation. var response = await _responseParser.Parse(representation, locationPattern.Replace("{id}", id), schemaId, OperationTypes.Modification); return(_apiResponseFactory.CreateResultWithContent(HttpStatusCode.OK, response.Object, response.Location, representation.Version, representation.Id)); }
public async Task <ApiActionResult> Execute(string id, JObject jObj, string schemaId, string locationPattern, string resourceType) { // 1. Check parameters. if (string.IsNullOrWhiteSpace(id)) { throw new ArgumentNullException(nameof(id)); } if (jObj == null) { throw new ArgumentNullException(nameof(jObj)); } if (string.IsNullOrWhiteSpace(schemaId)) { throw new ArgumentNullException(nameof(schemaId)); } _parametersValidator.ValidateLocationPattern(locationPattern); if (string.IsNullOrWhiteSpace(resourceType)) { throw new ArgumentNullException(nameof(resourceType)); } // 2. Parse the request. var representation = await _requestParser.Parse(jObj, schemaId, CheckStrategies.Strong); if (!representation.IsParsed) { return(_apiResponseFactory.CreateError( HttpStatusCode.BadRequest, representation.ErrorMessage)); } var record = await _representationStore.GetRepresentation(id); // 3. If the representation doesn't exist then 404 is returned. if (record == null) { return(_apiResponseFactory.CreateError( HttpStatusCode.NotFound, string.Format(ErrorMessages.TheResourceDoesntExist, id))); } // 4. Update attributes. // var allRepresentations = (await _representationStore.GetRepresentations(record.ResourceType)).Where(r => r.Id != record.Id); var updateRepr = await UpdateRepresentation(record, representation.Representation); if (updateRepr.IsError) { return(_apiResponseFactory.CreateError(HttpStatusCode.BadRequest, updateRepr.ErrorResponse)); } // 5. Store the new representation. record.LastModified = DateTime.UtcNow; record.Version = Guid.NewGuid().ToString(); if (!await _representationStore.UpdateRepresentation(record)) { return(_apiResponseFactory.CreateError(HttpStatusCode.InternalServerError, ErrorMessages.TheRepresentationCannotBeUpdated)); } // 6. Parse the new representation. var response = await _responseParser.Parse(record, locationPattern.Replace("{id}", id), schemaId, OperationTypes.Modification); return(_apiResponseFactory.CreateResultWithContent(HttpStatusCode.OK, response.Object, response.Location, record.Version, record.Id)); }
public async Task <ApiActionResult> Execute(JObject jObj, string baseUrl) { // 1. Check parameter. if (jObj == null) { throw new ArgumentNullException(nameof(jObj)); } // 2. Parse the request. var bulk = await _bulkRequestParser.Parse(jObj, baseUrl); if (!bulk.IsParsed) { return(_apiResponseFactory.CreateError(HttpStatusCode.InternalServerError, bulk.ErrorResponse)); } // 3. Execute bulk operation. var numberOfErrors = 0; var operationsResult = new JArray(); foreach (var operation in bulk.BulkResult.Operations) { ApiActionResult operationResult = null; if (operation.Method == HttpMethod.Post) { operationResult = await _addRepresentationAction.Execute(operation.Data, operation.LocationPattern, operation.SchemaId, operation.ResourceType); } else if (operation.Method == HttpMethod.Put) { operationResult = await _updateRepresentationAction.Execute(operation.ResourceId, operation.Data, operation.SchemaId, operation.LocationPattern, operation.ResourceType); } else if (operation.Method == HttpMethod.Delete) { operationResult = await _deleteRepresentationAction.Execute(operation.ResourceId); } else if (operation.Method.Method == "PATCH") { operationResult = await _patchRepresentationAction.Execute(operation.ResourceId, operation.Data, operation.SchemaId, operation.LocationPattern); } // 3.2. If maximum number of errors has been reached then return an error. if (!operationResult.IsSucceed()) { numberOfErrors++; if (bulk.BulkResult.FailOnErrors.HasValue && numberOfErrors > bulk.BulkResult.FailOnErrors) { return(_apiResponseFactory.CreateError(HttpStatusCode.InternalServerError, _errorResponseFactory.CreateError( string.Format(ErrorMessages.TheMaximumNumberOfErrorHasBeenReached, bulk.BulkResult.FailOnErrors), HttpStatusCode.InternalServerError, Common.Constants.ScimTypeValues.TooMany))); } } operationsResult.Add(CreateOperationResponse(operationResult, operation)); } var response = CreateResponse(operationsResult); return(_apiResponseFactory.CreateResultWithContent(HttpStatusCode.OK, response)); }