public async Task <QueryResult <InAppMessageQueryDto> > GetByUserId(Guid userId , ODataQueryOptions <InAppMessageQueryDto> options) { options.Validate(ValidationSettings); var uid = GetCurrentUser(); if (!uid.HasValue) { return(Query.Error(GeneralErrorCodes.TokenInvalid("UserId"))); } var tenants = _context.GetTenantsForUser(uid.Value); var shareTenant = tenants.Any(t => t.Users.Any(u => u.Id == userId)); // Check if the calling User shares a Tenant with the UserId passed in if (!shareTenant) { return(Query.Error(EntityErrorCode.EntityNotFound)); } var results = await Task.Run(() => _context.GetInAppMessagesForUser(userId) .Select(_mapper.Map <InAppMessage, InAppMessageQueryDto>) .AsQueryable()) .ConfigureAwait(false); return(Query.Result(results)); }
/// <summary> /// Deletes a dashboard option. /// </summary> /// <param name="id">ID that identifies the entity to be deleted.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// </returns> public override async Task <CommandResult <DashboardOptionQueryDto, Guid> > Delete(Guid id) { var userId = Thread.CurrentPrincipal == null ? null : Thread.CurrentPrincipal.GetUserIdFromPrincipal(); if (userId == null) { return(Command.Error <DashboardOptionQueryDto>(GeneralErrorCodes.TokenInvalid("UserId"))); } var userDashboardOptions = _context.GetDashboardOptionsForUser(Guid.Parse(userId)); var entity = userDashboardOptions.SingleOrDefault(x => x.Id == id); if (entity == null) { return(Command.Error <DashboardOptionQueryDto>(EntityErrorCode.EntityNotFound)); } if (_context.Dashboards.Any(x => x.DashboardOptionId == id)) { return(Command.Error <DashboardOptionQueryDto>(EntityErrorCode.EntityCouldNotBeDeleted)); } _context.DashboardOptions.Remove(entity); await _context.SaveChangesAsync().ConfigureAwait(false); return(Command.NoContent <DashboardOptionQueryDto>()); }
/// <summary> /// Creates a dashboard. /// </summary> /// <param name="dto">Data Transfer Object (DTO) used to create an entity.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// If successful, the task result contains the DTO associated with the entity created. /// </returns> public override async Task <CommandResult <DashboardQueryDto, Guid> > Create(DashboardBaseDto dto) { var userId = Thread.CurrentPrincipal == null ? null : Thread.CurrentPrincipal.GetUserIdFromPrincipal(); if (userId == null) { return(Command.Error <DashboardQueryDto>(GeneralErrorCodes.TokenInvalid("UserId"))); } var userIdGuid = Guid.Parse(userId); var validationResponse = ValidatorCreate.Validate(dto); if (dto == null) { return(Command.Error <DashboardQueryDto>(validationResponse)); } if (dto.Id != Guid.Empty) { validationResponse.FFErrors.Add(ValidationErrorCode.PropertyIsInvalid("Id")); } var userTenants = _context.GetTenantsForUser(userIdGuid); if (dto.TenantId != Guid.Empty && !userTenants.Any(x => x.Id == dto.TenantId)) { validationResponse.FFErrors.Add(ValidationErrorCode.ForeignKeyValueDoesNotExist("TenantId")); } if (_context.Dashboards.Any(x => x.OwnerUserId == userIdGuid && x.Name == dto.Name)) { validationResponse.FFErrors.Add(EntityErrorCode.EntityAlreadyExists); } var userDashboardOptions = _context.GetDashboardOptionsForUser(userIdGuid); if (dto.DashboardOptionId != Guid.Empty && !userDashboardOptions.Any(x => x.Id == dto.DashboardOptionId)) { validationResponse.FFErrors.Add(ValidationErrorCode.ForeignKeyValueDoesNotExist("DashboardOptionId")); } if (validationResponse.IsInvalid) { return(Command.Error <DashboardQueryDto>(validationResponse)); } var newEntity = new Dashboard(); _mapper.Map(dto, newEntity); newEntity.Id = Guid.NewGuid(); newEntity.SetAuditFieldsOnCreate(userId); newEntity.OwnerUserId = userIdGuid; _context.Dashboards.Add(newEntity); await _context.SaveChangesAsync().ConfigureAwait(false); return(Command.Created(_mapper.Map(newEntity, new DashboardQueryDto()), newEntity.Id)); }
/// <summary> /// Gets a list of dashboard options from the data store. /// </summary> /// <param name="queryOptions">OData query options.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// If successful, the task result contains the list of DTOs retrieved. /// </returns> public override async Task <QueryResult <DashboardOptionQueryDto> > Get(ODataQueryOptions <DashboardOptionQueryDto> queryOptions) { queryOptions.Validate(ValidationSettings); var userId = Thread.CurrentPrincipal == null ? null : Thread.CurrentPrincipal.GetUserIdFromPrincipal(); if (userId == null) { return(Query.Error(GeneralErrorCodes.TokenInvalid("UserId"))); } try { var result = await Task.Run(() => _context.GetDashboardOptionsForUser(Guid.Parse(userId)) .Select(_mapper.Map <DashboardOption, DashboardOptionQueryDto>) .AsQueryable()) .ConfigureAwait(false); return(Query.Result(result)); } catch (Exception ex) { throw; } }
/// <summary> /// Deletes a location. /// </summary> /// <param name="id">ID that identifies the location to be deleted.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// </returns> public override async Task <CommandResult <LocationQueryDto, Guid> > Delete(Guid id) { // Thread.CurrentPrincipal is not available in the constructor. Do not try and move this var uid = GetCurrentUser(); if (!uid.HasValue) { return(Command.Error <LocationQueryDto>(GeneralErrorCodes.TokenInvalid("UserId"))); } var location = await _context.GetLocationsForUser(uid.Value) .Include(l => l.Locations) .SingleOrDefaultAsync(l => l.Id == id) .ConfigureAwait(false); if (location == null) { return(Command.Error <LocationQueryDto>(EntityErrorCode.EntityNotFound)); } if (location.Locations.Count > 0) { return(Command.Error <LocationQueryDto>(EntityErrorCode.EntityCouldNotBeDeleted)); } _context.Locations.Remove(location); await _context.SaveChangesAsync().ConfigureAwait(false); return(Command.NoContent <LocationQueryDto>()); }
public static string GetSyncErrorMessage(string status) { if (string.IsNullOrEmpty(status)) { return(string.Empty); } int code = -1; if (int.TryParse(status, out code)) { if (GeneralErrorCodes.ContainsKey(code)) { return(GeneralErrorCodes[code]); } else if (SyncErrorCodes.ContainsKey(code)) { return(SyncErrorCodes[code]); } else { return("UnknownError"); } } return(status); }
/// <summary> /// Gets a single location from the data store. /// </summary> /// <param name="id">ID that uniquely identifies the location to be retrieved.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// If successful, the task result includes the location DTO retrieved. /// </returns> public override async Task <QueryResult <LocationQueryDto> > Get(Guid id) { var uid = GetCurrentUser(); if (!uid.HasValue) { return(Query.Error(GeneralErrorCodes.TokenInvalid("UserId"))); } var result = await Task.Run(() => _context.GetLocationsForUser(uid.Value) .Include(x => x.LocationType) .Include(x => x.Parent) .Include(x => x.Locations.Select(y => y.Locations)) .Include(x => x.ProductOfferingTenantLocations) .FirstOrDefault(l => l.Id == id)) .ConfigureAwait(false); if (result == null) { return(Query.Error(EntityErrorCode.EntityNotFound)); } var locationDto = _mapper.Map <Location, LocationQueryDto>(result); return(Query.Result(locationDto)); }
/// <summary> /// Updates a dashboard option using a <see cref="Delta"/> object. /// </summary> /// <param name="id">ID of the entity to be updated.</param> /// <param name="delta"> /// Delta containing a list of entity properties. Web Api does the magic of converting the JSON to /// a delta. /// </param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// </returns> public override async Task <CommandResult <DashboardOptionBaseDto, Guid> > Update(Guid id, Delta <DashboardOptionBaseDto> delta) { var userId = Thread.CurrentPrincipal == null ? null : Thread.CurrentPrincipal.GetUserIdFromPrincipal(); if (userId == null) { return(Command.Error <DashboardOptionBaseDto>(GeneralErrorCodes.TokenInvalid("UserId"))); } if (delta == null) { return(Command.Error <DashboardOptionBaseDto>(EntityErrorCode.EntityFormatIsInvalid)); } var userDashboardOptions = _context.GetDashboardOptionsForUser(Guid.Parse(userId)); var entity = userDashboardOptions.SingleOrDefault(x => x.Id == id); if (entity == null) { return(Command.Error <DashboardOptionBaseDto>(EntityErrorCode.EntityNotFound)); } var dto = _mapper.Map(entity, new DashboardOptionBaseDto()); delta.Patch(dto); var validationResponse = ValidatorUpdate.Validate(dto); var userTenants = _context.GetTenantsForUser(Guid.Parse(userId)); if (dto.TenantId != Guid.Empty && !userTenants.Any(x => x.Id == dto.TenantId)) { validationResponse.FFErrors.Add(ValidationErrorCode.ForeignKeyValueDoesNotExist("TenantId")); } else if (_context.DashboardOptions.Any(x => x.Id != id && x.TenantId == dto.TenantId)) { validationResponse.FFErrors.Add(EntityErrorCode.EntityAlreadyExists); } // Including the original Id in the Patch request will not return an error but attempting to change the Id is not allowed. if (dto.Id != id) { validationResponse.FFErrors.Add(ValidationErrorCode.EntityIDUpdateNotAllowed("Id")); } if (validationResponse.IsInvalid) { return(Command.Error <DashboardOptionBaseDto>(validationResponse)); } _context.DashboardOptions.Attach(entity); _mapper.Map(dto, entity); entity.SetAuditFieldsOnUpdate(userId); await _context.SaveChangesAsync().ConfigureAwait(false); return(Command.NoContent <DashboardOptionBaseDto>()); }
/// <summary> /// Updates a Location Log Entry using a <see cref="Delta"/> object. /// </summary> /// <param name="id">ID of the Location Log Entry to be updated.</param> /// <param name="delta"> /// Delta containing a list of Location Log Entry properties. Web Api does the magic of converting the JSON to /// a delta. /// </param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// </returns> public override async Task <CommandResult <LocationLogEntryBaseDto, Guid> > Update(Guid id, Delta <LocationLogEntryBaseDto> delta) { // User ID should always be available, but if not ... var userId = GetCurrentUser(); if (!userId.HasValue) { return(Command.Error <LocationLogEntryBaseDto>(GeneralErrorCodes.TokenInvalid("UserId"))); } if (delta == null) { return(Command.Error <LocationLogEntryBaseDto>(EntityErrorCode.EntityFormatIsInvalid)); } var locationLogEntry = await _context.GetLocationLogEntriesForUser(userId.Value) .SingleOrDefaultAsync(l => l.Id == id) .ConfigureAwait(false); if (locationLogEntry == null) { return(Command.Error <LocationLogEntryBaseDto>(EntityErrorCode.EntityNotFound)); } var dto = _mapper.Map(locationLogEntry, new LocationLogEntryQueryDto()); delta.Patch(dto); var validationResponse = ValidatorUpdate.Validate(dto); // Including the original ID in the Patch request will not return an error but attempting to change the Id is not allowed. if (dto.Id != id) { validationResponse.FFErrors.Add(ValidationErrorCode.EntityIDUpdateNotAllowed("Id")); } var locationExists = await DoesLocationExist(dto.LocationId); if (!locationExists) { validationResponse.FFErrors.Add(ValidationErrorCode.ForeignKeyValueDoesNotExist(nameof(LocationLogEntry.LocationId))); } if (validationResponse.IsInvalid) { return(Command.Error <LocationLogEntryBaseDto>(validationResponse)); } _context.LocationLogEntries.Attach(locationLogEntry); _mapper.Map(dto, locationLogEntry); locationLogEntry.SetAuditFieldsOnUpdate(userId.Value); await _context.SaveChangesAsync().ConfigureAwait(false); return(Command.NoContent <LocationLogEntryBaseDto>()); }
/// <summary> /// Updates a limit type using a <see cref="Delta"/> object. /// </summary> /// <param name="id">ID of the entity to be updated.</param> /// <param name="delta"> /// Delta containing a list of entity properties. Web Api does the magic of converting the JSON to /// a delta. /// </param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// </returns> public override async Task <CommandResult <LimitTypeBaseDto, Guid> > Update(Guid id, Delta <LimitTypeBaseDto> delta) { var userId = Thread.CurrentPrincipal == null ? null : Thread.CurrentPrincipal.GetUserIdFromPrincipal(); if (userId == null) { return(Command.Error <LimitTypeBaseDto>(GeneralErrorCodes.TokenInvalid("UserId"))); } if (delta == null) { return(Command.Error <LimitTypeBaseDto>(EntityErrorCode.EntityFormatIsInvalid)); } var entity = await _context.LimitTypes .SingleOrDefaultAsync(x => x.Id == id) .ConfigureAwait(false); if (entity == null) { return(Command.Error <LimitTypeBaseDto>(EntityErrorCode.EntityNotFound)); } var dto = _mapper.Map(entity, new LimitTypeBaseDto()); delta.Patch(dto); var validationResponse = ValidatorUpdate.Validate(dto); if (_context.LimitTypes.Any(x => x.Id != id && x.I18NKeyName == dto.I18NKeyName)) { validationResponse.FFErrors.Add(ValidationErrorCode.EntityPropertyDuplicateNotAllowed(nameof(LocationType.I18NKeyName))); } // Including the original Id in the Patch request will not return an error but attempting to change the Id is not allowed. if (dto.Id != id) { validationResponse.FFErrors.Add(ValidationErrorCode.EntityIDUpdateNotAllowed("Id")); } if (validationResponse.IsInvalid) { return(Command.Error <LimitTypeBaseDto>(validationResponse)); } _context.LimitTypes.Attach(entity); _mapper.Map(dto, entity); entity.SetAuditFieldsOnUpdate(userId); await _context.SaveChangesAsync().ConfigureAwait(false); return(Command.NoContent <LimitTypeBaseDto>()); }
/// <summary> /// Creates a Location Log Entry. /// </summary> /// <param name="dto">Data Transfer Object (DTO) used to create a Location Log Entry.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// If successful, the task result contains the DTO associated with the Location Log Entry. /// </returns> public override async Task <CommandResult <LocationLogEntryQueryDto, Guid> > Create(LocationLogEntryBaseDto dto) { // User ID should always be available, but if not ... var userId = GetCurrentUser(); if (!userId.HasValue) { return(Command.Error <LocationLogEntryQueryDto>(GeneralErrorCodes.TokenInvalid("UserId"))); } var validationResponse = ValidatorCreate.Validate(dto); if (dto == null) { return(Command.Error <LocationLogEntryQueryDto>(validationResponse)); } if (dto.Id != Guid.Empty) { validationResponse.FFErrors.Add(ValidationErrorCode.PropertyIsInvalid(nameof(LocationLogEntry.Id))); } var locationExists = await DoesLocationExist(dto.LocationId); if (!locationExists) { validationResponse.FFErrors.Add(ValidationErrorCode.ForeignKeyValueDoesNotExist(nameof(LocationLogEntry.LocationId))); } if (validationResponse.IsInvalid) { return(Command.Error <LocationLogEntryQueryDto>(validationResponse)); } var locationLogEntry = new LocationLogEntry { Id = Guid.NewGuid() }; _mapper.Map(dto, locationLogEntry); locationLogEntry.SetAuditFieldsOnCreate(userId.Value); _context.LocationLogEntries.Add(locationLogEntry); await _context.SaveChangesAsync().ConfigureAwait(false); return(Command.Created(_mapper.Map(locationLogEntry, new LocationLogEntryQueryDto()), locationLogEntry.Id)); }
/// <summary> /// Gets a single chemical form types from the data store. /// </summary> /// <param name="id">ID that uniquely identifies the entity to be retrieved.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// If successful, the task result includes the DTO retrieved. /// </returns> public override async Task <QueryResult <ChemicalFormTypeQueryDto> > Get(Guid id) { var userId = Thread.CurrentPrincipal == null ? null : Thread.CurrentPrincipal.GetUserIdFromPrincipal(); if (userId == null) { return(Query.Error(GeneralErrorCodes.TokenInvalid("UserId"))); } var result = await _context.ChemicalFormTypes .FirstOrDefaultAsync(x => x.Id == id) .ConfigureAwait(false); return(result == null ? Query.Error(EntityErrorCode.EntityNotFound) : Query.Result(_mapper.Map <ChemicalFormType, ChemicalFormTypeQueryDto>(result))); }
/// <summary> /// Gets a list of limit types from the data store. /// </summary> /// <param name="queryOptions">OData query options.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// If successful, the task result contains the list of DTOs retrieved. /// </returns> public override async Task <QueryResult <LimitTypeQueryDto> > Get(ODataQueryOptions <LimitTypeQueryDto> queryOptions) { queryOptions.Validate(ValidationSettings); var userId = Thread.CurrentPrincipal == null ? null : Thread.CurrentPrincipal.GetUserIdFromPrincipal(); if (userId == null) { return(Query.Error(GeneralErrorCodes.TokenInvalid("UserId"))); } var results = await Task.Run(() => _context.LimitTypes .Select(_mapper.Map <LimitType, LimitTypeQueryDto>) .AsQueryable()) .ConfigureAwait(false); return(Query.Result(results)); }
/// <summary> /// Gets a single dashboard option from the data store. /// </summary> /// <param name="id">ID that uniquely identifies the entity to be retrieved.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// If successful, the task result includes the DTO retrieved. /// </returns> public override async Task <QueryResult <DashboardOptionQueryDto> > Get(Guid id) { var userId = Thread.CurrentPrincipal == null ? null : Thread.CurrentPrincipal.GetUserIdFromPrincipal(); if (userId == null) { return(Query.Error(GeneralErrorCodes.TokenInvalid("UserId"))); } var result = await Task.Run(() => _context.GetDashboardOptionsForUser(Guid.Parse(userId)) .FirstOrDefault(x => x.Id == id)) .ConfigureAwait(false); return(result == null ? Query.Error(EntityErrorCode.EntityNotFound) : Query.Result(_mapper.Map <DashboardOption, DashboardOptionQueryDto>(result))); }
/// <summary> /// Creates a limit type. /// </summary> /// <param name="dto">Data Transfer Object (DTO) used to create an entity.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// If successful, the task result contains the DTO associated with the entity created. /// </returns> public override async Task <CommandResult <LimitTypeQueryDto, Guid> > Create(LimitTypeBaseDto dto) { var userId = Thread.CurrentPrincipal == null ? null : Thread.CurrentPrincipal.GetUserIdFromPrincipal(); if (userId == null) { return(Command.Error <LimitTypeQueryDto>(GeneralErrorCodes.TokenInvalid("UserId"))); } var validationResponse = ValidatorCreate.Validate(dto); if (dto == null) { return(Command.Error <LimitTypeQueryDto>(validationResponse)); } if (dto.Id != Guid.Empty) { validationResponse.FFErrors.Add(ValidationErrorCode.PropertyIsInvalid("Id")); } if (_context.LimitTypes.Any(x => x.I18NKeyName == dto.I18NKeyName)) { validationResponse.FFErrors.Add(EntityErrorCode.EntityAlreadyExists); } if (validationResponse.IsInvalid) { return(Command.Error <LimitTypeQueryDto>(validationResponse)); } var newEntity = new LimitType(); _mapper.Map(dto, newEntity); newEntity.Id = Guid.NewGuid(); newEntity.SetAuditFieldsOnCreate(userId); _context.LimitTypes.Add(newEntity); await _context.SaveChangesAsync().ConfigureAwait(false); return(Command.Created(_mapper.Map(newEntity, new LimitTypeQueryDto()), newEntity.Id)); }
/// <summary> /// Gets a list of Location Log Entries from the data store. /// </summary> /// <param name="queryOptions">OData query options.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// If successful, the task result contains the list of Location Log Entry DTOs retrieved. /// </returns> public override async Task <QueryResult <LocationLogEntryQueryDto> > Get(ODataQueryOptions <LocationLogEntryQueryDto> queryOptions) { queryOptions.Validate(ValidationSettings); // User ID should always be available, but if not ... var userId = GetCurrentUser(); if (!userId.HasValue) { return(Query.Error(GeneralErrorCodes.TokenInvalid("UserId"))); } var results = await Task.Run(() => _context.GetLocationLogEntriesForUser(userId.Value) .Select(_mapper.Map <LocationLogEntry, LocationLogEntryQueryDto>) .AsQueryable()) .ConfigureAwait(false); return(Query.Result(results)); }
/// <summary> /// Gets a list of Location Types from the data store. /// </summary> /// <param name="queryOptions">OData query options.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// If successful, the task result contains the list of Location Type DTOs retrieved. /// </returns> public override async Task<QueryResult<LocationTypeQueryDto>> Get(ODataQueryOptions<LocationTypeQueryDto> queryOptions) { // Thread.CurrentPrincipal is not available in the constructor. Do not try to move this. var uid = GetCurrentUser(); if (!uid.HasValue) return Query.Error(GeneralErrorCodes.TokenInvalid("UserId")); queryOptions.Validate(ValidationSettings); var results = await Task.Run(() => _context.LocationTypes .Include(x => x.LocationTypeGroup) .Include(x => x.LocationTypes) .Include(x => x.Parent) .Select(_mapper.Map<LocationType, LocationTypeQueryDto>) .AsQueryable()) .ConfigureAwait(false); return Query.Result(results); }
/// <summary> /// Gets a single limit type from the data store. /// </summary> /// <param name="id">ID that uniquely identifies the entity to be retrieved.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// If successful, the task result includes the DTO retrieved. /// </returns> public override async Task <QueryResult <LimitTypeQueryDto> > Get(Guid id) { var userId = Thread.CurrentPrincipal == null ? null : Thread.CurrentPrincipal.GetUserIdFromPrincipal(); if (userId == null) { return(Query.Error(GeneralErrorCodes.TokenInvalid("UserId"))); } var result = await Task.Run(() => _context.LimitTypes .FirstOrDefault(x => x.Id == id)) .ConfigureAwait(false); if (result == null) { return(Query.Error(EntityErrorCode.EntityNotFound)); } var dto = _mapper.Map <LimitType, LimitTypeQueryDto>(result); return(Query.Result(dto)); }
/// <summary> /// Gets a single Location Type from the data store. /// </summary> /// <param name="id">ID that uniquely identifies the Location Type to be retrieved.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// If successful, the task result includes the Location Type DTO retrieved. /// </returns> public override async Task<QueryResult<LocationTypeQueryDto>> Get(Guid id) { // Thread.CurrentPrincipal is not available in the constructor. Do not try to move this. var uid = GetCurrentUser(); if (!uid.HasValue) return Query.Error(GeneralErrorCodes.TokenInvalid("UserId")); var result = await Task.Run(() => _context.LocationTypes .Include(x => x.LocationTypeGroup) .Include(x => x.LocationTypes) .Include(x => x.Parent) .FirstOrDefault(l => l.Id == id)) .ConfigureAwait(false); if (result == null) return Query.Error(EntityErrorCode.EntityNotFound); var locationTypeDto = _mapper.Map<LocationType, LocationTypeQueryDto>(result); return Query.Result(locationTypeDto); }
/// <summary> /// Gets a list of locations from the data store based on the user /// </summary> /// <param name="queryOptions">OData query options.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// If successful, the task result contains the list of location DTOs retrieved. /// </returns> public override async Task <QueryResult <LocationQueryDto> > Get(ODataQueryOptions <LocationQueryDto> queryOptions) { queryOptions.Validate(ValidationSettings); var uid = GetCurrentUser(); if (!uid.HasValue) { return(Query.Error(GeneralErrorCodes.TokenInvalid("UserId"))); } var results = await Task.Run(() => _context.GetLocationsForUser(uid.Value) .Include(x => x.LocationType) .Include(x => x.LocationType.LocationTypeGroup) .Include(x => x.Parent) .Include(x => x.Locations.Select(y => y.Locations)) .Include(x => x.ProductOfferingTenantLocations) .Select(_mapper.Map <Location, LocationQueryDto>) .AsQueryable()) .ConfigureAwait(false); return(Query.Result(results)); }
/// <summary> /// Deletes a limit type. /// </summary> /// <param name="id">ID that identifies the entity to be deleted.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// </returns> public override async Task <CommandResult <LimitTypeQueryDto, Guid> > Delete(Guid id) { var userId = Thread.CurrentPrincipal == null ? null : Thread.CurrentPrincipal.GetUserIdFromPrincipal(); if (userId == null) { return(Command.Error <LimitTypeQueryDto>(GeneralErrorCodes.TokenInvalid("UserId"))); } var entity = await _context.LimitTypes .SingleOrDefaultAsync(x => x.Id == id) .ConfigureAwait(false); if (entity == null) { return(Command.Error <LimitTypeQueryDto>(EntityErrorCode.EntityNotFound)); } _context.LimitTypes.Remove(entity); await _context.SaveChangesAsync().ConfigureAwait(false); return(Command.NoContent <LimitTypeQueryDto>()); }
/// <summary> /// Gets a single Location Log Entry from the data store. /// </summary> /// <param name="id">ID that uniquely identifies the Location Log Entry to be retrieved.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// If successful, the task result includes the Location Log Entry DTO retrieved. /// </returns> public override async Task <QueryResult <LocationLogEntryQueryDto> > Get(Guid id) { // User ID should always be available, but if not ... var userId = GetCurrentUser(); if (!userId.HasValue) { return(Query.Error(GeneralErrorCodes.TokenInvalid("UserId"))); } var result = await _context.GetLocationLogEntriesForUser(userId.Value) .FirstOrDefaultAsync(l => l.Id == id) .ConfigureAwait(false); if (result == null) { return(Query.Error(EntityErrorCode.EntityNotFound)); } var locationLogEntryQueryDto = _mapper.Map <LocationLogEntry, LocationLogEntryQueryDto>(result); return(Query.Result(locationLogEntryQueryDto)); }
/// <summary> /// Deletes a Location Log Entry. /// </summary> /// <param name="id">ID that identifies the Location Log Entry to be deleted.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// </returns> public override async Task <CommandResult <LocationLogEntryQueryDto, Guid> > Delete(Guid id) { // User ID should always be available, but if not ... var userId = GetCurrentUser(); if (!userId.HasValue) { return(Command.Error <LocationLogEntryQueryDto>(GeneralErrorCodes.TokenInvalid("UserId"))); } var locationLogEntry = await _context.GetLocationLogEntriesForUser(userId.Value) .SingleOrDefaultAsync(l => l.Id == id) .ConfigureAwait(false); if (locationLogEntry == null) { return(Command.Error <LocationLogEntryQueryDto>(EntityErrorCode.EntityNotFound)); } _context.LocationLogEntries.Remove(locationLogEntry); await _context.SaveChangesAsync().ConfigureAwait(false); return(Command.NoContent <LocationLogEntryQueryDto>()); }
/// <summary> /// Updates a location using a <see cref="Delta"/> object. /// </summary> /// <param name="id">ID of the location to be updated.</param> /// <param name="delta"> /// Delta containing a list of location properties. Web Api does the magic of converting the JSON to /// a delta. /// </param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// </returns> public override async Task <CommandResult <LocationBaseDto, Guid> > Update(Guid id, Delta <LocationBaseDto> delta) { // Thread.CurrentPrincipal is not available in the constrtor. Do not try and move this var uid = GetCurrentUser(); // User ID should always be available, but if not ... if (!uid.HasValue) { return(Command.Error <LocationBaseDto>(GeneralErrorCodes.TokenInvalid("UserId"))); } if (delta == null) { return(Command.Error <LocationBaseDto>(EntityErrorCode.EntityFormatIsInvalid)); } var location = await _context.GetLocationsForUser(uid.Value) .SingleOrDefaultAsync(l => l.Id == id) .ConfigureAwait(false); if (location == null) { return(Command.Error <LocationBaseDto>(EntityErrorCode.EntityNotFound)); } var locationDto = _mapper.Map(location, new LocationBaseDto()); delta.Patch(locationDto); var validationResponse = ValidatorUpdate.Validate(locationDto); if (locationDto.ParentId.HasValue) { var existingTask = _context.Locations.AnyAsync(l => l.Id == locationDto.ParentId.Value); if (!existingTask.Result) { validationResponse.FFErrors.Add(ValidationErrorCode.ForeignKeyValueDoesNotExist(nameof(Location.ParentId))); } else { // Check for circular references if (await LocationValidator.IsCircularReference(_context.Locations, locationDto, id)) { validationResponse.FFErrors.Add(ValidationErrorCode.CircularReferenceNotAllowed(nameof(Location.ParentId))); } } } // Check that Location Type exists if (locationDto.LocationTypeId != Guid.Empty && !_context.LocationTypes.Any(lt => lt.Id == locationDto.LocationTypeId)) { validationResponse.FFErrors.Add(ValidationErrorCode.ForeignKeyValueDoesNotExist(nameof(Location.LocationTypeId))); } // Including the original Id in the Patch request will not return an error but attempting to change the Id is not allowed. if (locationDto.Id != id) { validationResponse.FFErrors.Add(ValidationErrorCode.EntityIDUpdateNotAllowed("Id")); } // Check that unique fields are still unique if (_context.Locations.Any(l => l.Id != id && l.Name == locationDto.Name)) { validationResponse.FFErrors.Add(ValidationErrorCode.EntityPropertyDuplicateNotAllowed(nameof(Location.Name))); } if (validationResponse.IsInvalid) { return(Command.Error <LocationBaseDto>(validationResponse)); } _context.Locations.Attach(location); _mapper.Map(locationDto, location); location.SetAuditFieldsOnUpdate(uid.Value); await _context.SaveChangesAsync().ConfigureAwait(false); return(Command.NoContent <LocationBaseDto>()); }
/// <summary> /// Deletes the requested operation if the operation has no measurements associated to it's locations. /// </summary> /// <param name="operationId">Guid identitifer of the operation to delete</param> /// <returns>Task that returns the request result.</returns> public async Task <CommandResultNoDto> Delete(Guid?operationId) { var errors = new List <FFErrorCode>(); var userId = Thread.CurrentPrincipal == null ? null : Thread.CurrentPrincipal.GetUserIdFromPrincipal(); if (string.IsNullOrEmpty(userId)) { errors.Add(GeneralErrorCodes.TokenInvalid("UserId")); } if (!operationId.HasValue || operationId == Guid.Empty) { errors.Add(ValidationErrorCode.PropertyRequired("OperationId")); } if (errors.Count > 0) { return(NoDtoHelpers.CreateCommandResult(errors)); } var userIdGuid = Guid.Parse(userId); List <Location> locations = new List <Location>(); List <LocationParameterLimit> locationParameterLimits = new List <LocationParameterLimit>(); List <LocationParameter> locationParameters = new List <LocationParameter>(); List <LocationLogEntry> locationLocationLogEntries = new List <LocationLogEntry>(); // Check that the Location exists and if it's an operation if (!_context.Locations.Any(x => x.Id == operationId.Value && x.LocationType.LocationTypeGroup.Id == Data.Constants.LocationTypeGroups.Operation.Id)) { errors.Add(EntityErrorCode.EntityNotFound); } else { // Check if user is in the proper tenant. if (!_context.Locations.Single(x => x.Id == operationId.Value) .ProductOfferingTenantLocations.Any(x => x.Tenant.Users.Any(u => u.Id == userIdGuid))) { errors.Add(ValidationErrorCode.ForeignKeyValueDoesNotExist("TenantId")); } // Check that the operation has no measurements or notes and can be deleted // NOTE : This method will not scale beyond more than 4 or 5 levels max var operation = _context.Locations.Include("Locations").Single(x => x.Id == operationId.Value); locations.Add(operation); var systems = operation.Locations; locations.AddRange(systems); foreach (var system in systems) { locations.AddRange(_context.Locations.Where(x => x.ParentId == system.Id).ToList()); } var locationIds = locations.Select(l => l.Id); locationParameters = _context.LocationParameters.Where(x => locationIds.Contains(x.LocationId)).ToList(); var locationParamIds = locationParameters.Select(lp => lp.Id); locationParameterLimits = _context.LocationParameterLimits.Where( x => locationParamIds.Contains(x.LocationParameterId)).ToList(); var hasLocationLocationLogEntries = _context.LocationLogEntries.Any(x => locationIds.Contains(x.LocationId)); var hasMeasurements = _context.Measurements.Any(x => locationParamIds.Contains(x.LocationParameterId)); var hasParameterNotes = _context.LocationParameterNotes.Any( x => locationParamIds.Contains(x.LocationParameterId)); var hasMeasurementTransactions = _context.MeasurementTransactions.Any(x => locationIds.Contains(x.LocationId)); if (hasParameterNotes || hasMeasurements || hasLocationLocationLogEntries || hasMeasurementTransactions) { errors.Add(EntityErrorCode.EntityCouldNotBeDeleted); } } if (errors.Count > 0) { return(NoDtoHelpers.CreateCommandResult(errors)); } _context.LocationParameterLimits.RemoveRange(locationParameterLimits); _context.LocationParameters.RemoveRange(locationParameters); _context.Locations.RemoveRange(locations); _context.LocationLogEntries.RemoveRange(locationLocationLogEntries); await _context.SaveChangesAsync().ConfigureAwait(false); var commandResult = NoDtoHelpers.CreateCommandResult(errors); // CreateCommandResult will either return BadRequest(400) or Ok(200) // Overriding the Status code to return a 204 on a successful delete commandResult.StatusCode = FacadeStatusCode.NoContent; return(commandResult); }
/// <summary> /// Creates a location. /// </summary> /// <param name="dto">Data Transfer Object (DTO) used to create a location.</param> /// <returns> /// An asynchronous task result containing information needed to create an API response message. /// If successful, the task result contains the DTO associated with the location. /// </returns> /// <remarks> /// Note that there is no checking for a circular reference for creating a location. This is /// because the created item does not have children. So, there cannot be a circular reference. /// </remarks> public override async Task <CommandResult <LocationQueryDto, Guid> > Create(LocationBaseDto dto) { // Thread.CurrentPrincipal is not available in the constructor. Do not try to move this. var uid = GetCurrentUser(); // User ID should always be available, but if not ... if (!uid.HasValue) { return(Command.Error <LocationQueryDto>(GeneralErrorCodes.TokenInvalid("UserId"))); } var user = await _context.Users .Include(x => x.Tenants.Select(y => y.ProductOfferings)) .FirstOrDefaultAsync(u => u.Id == uid.Value); if (user == null) { return(Command.Error <LocationQueryDto>(GeneralErrorCodes.TokenInvalid("UserId"))); } var validationResponse = ValidatorCreate.Validate(dto); if (dto == null) { return(Command.Error <LocationQueryDto>(validationResponse)); } if (dto.Id != Guid.Empty) { validationResponse.FFErrors.Add(ValidationErrorCode.PropertyIsInvalid(nameof(Location.Id))); } var existing = await _context.Locations.AnyAsync(l => l.Name == dto.Name).ConfigureAwait(false); if (existing) { validationResponse.FFErrors.Add(EntityErrorCode.EntityAlreadyExists); } if (dto.ParentId.HasValue) { existing = await _context.Locations.AnyAsync(l => l.Id == dto.ParentId.Value).ConfigureAwait(false); if (!existing) { validationResponse.FFErrors.Add(ValidationErrorCode.ForeignKeyValueDoesNotExist(nameof(Location.ParentId))); } } if (dto.LocationTypeId != Guid.Empty && !_context.LocationTypes.Any(lt => lt.Id == dto.LocationTypeId)) { validationResponse.FFErrors.Add(ValidationErrorCode.ForeignKeyValueDoesNotExist(nameof(Location.LocationTypeId))); } if (validationResponse.IsInvalid) { return(Command.Error <LocationQueryDto>(validationResponse)); } var location = new Location { Id = Guid.NewGuid() }; _mapper.Map(dto, location); location.CreatedById = uid.Value; location.CreatedOn = DateTime.UtcNow; location.SetAuditFieldsOnUpdate(uid.Value); _context.Locations.Add(location); // Add the Location to the Product Offering / Tenant / Location List if (user.Tenants.Count > 0) { // Only care about the first tenant in the list. In the future, the list of tenants // will contain only one element and may be replaced by a scalar. var tenant = user.Tenants.ElementAt(0); // Add a Product Offering / Tenant / Location for the Collect PO // TODO: This is going to break if we change the name of the productOffering var productOffering = tenant.ProductOfferings.FirstOrDefault(x => x.Name == "Collect"); if (productOffering == null) { return(Command.Error <LocationQueryDto>(EntityErrorCode.ReferencedEntityNotFound)); } var productOfferingTenantLocation = new ProductOfferingTenantLocation { ProductOfferingId = productOffering.Id, TenantId = tenant.Id, LocationId = location.Id }; _context.ProductOfferingTenantLocations.Add(productOfferingTenantLocation); } await _context.SaveChangesAsync().ConfigureAwait(false); return(Command.Created(_mapper.Map(location, new LocationQueryDto()), location.Id)); }
/// <summary> /// Accepts a single xls file that contains operation configuration. /// </summary> /// <param name="fileMetadata">Metadata associated with the file upload request.</param> /// <param name="authenticationHeader">Authentication header for the request.</param> /// <param name="requestTenantId">The selected Tenant Id from the request import the Operation Config to</param> /// <returns>A task that returns the result of the upload option.</returns> public async Task <CommandResultNoDto> Upload(FileUploadMetadataDto fileMetadata, string authenticationHeader, Guid requestTenantId) { var errors = new List <FFErrorCode>(); var odataHelper = new Core.Api.OData.ODataHelper(); var userId = Thread.CurrentPrincipal == null ? null : Thread.CurrentPrincipal.GetUserIdFromPrincipal(); if (userId == null) { errors.Add(GeneralErrorCodes.TokenInvalid("UserId")); } if (errors.Count > 0) { return(NoDtoHelpers.CreateCommandResult(errors)); } // ReSharper disable once AssignNullToNotNullAttribute var userIdGuid = Guid.Parse(userId); // Check that the Tenant Id in the request body is in the user's claim tenants var tenants = odataHelper.GetTenantIds(Thread.CurrentPrincipal) as List <Guid>; // Check user has no tenants in their claim or if the tenantid in the request body is not in the claim if (tenants == null || tenants.All(x => x != requestTenantId)) { errors.Add(ValidationErrorCode.ForeignKeyValueDoesNotExist("TenantId")); } if (errors.Count > 0) { return(NoDtoHelpers.CreateCommandResult(errors)); } // Store file in blob storage. var result = await _blobManager.StoreAsync(_blobStorageConnectionString, _blobStorageContainerName, fileMetadata.SavedFileName); // Add file metadata to documentDB to later be retrieved by request // An Id property is created by documentDB and in populated in the result object await _documentDb.CreateItemAsync( new UploadTransaction { OriginalFileName = fileMetadata.OriginalFileName, TenantIds = tenants, UploadTransactionType = fileMetadata.TransactionType, UserId = userIdGuid, UtcTimestamp = DateTime.UtcNow }); var queueMessage = new BlobQueueMessage { BlobName = result.BlobName, BlobSize = result.BlobSize, BlobUrl = result.BlobUrl, BlobTransactionType = fileMetadata.TransactionType, UserId = userIdGuid, AuthenticationHeader = authenticationHeader, // TenantId should be checked by the blob processor that it matches the tenant in the Operation Config to be processed TenantId = requestTenantId }; var msg = JsonConvert.SerializeObject(queueMessage); // Add message to queue. await _queueManager.AddAsync(_blobStorageConnectionString, _queueStorageContainerName, msg); return(NoDtoHelpers.CreateCommandResult(errors)); }
public async Task <IHttpActionResult> Post() { var errors = new List <FFErrorCode>(); // Parse Request Content var provider = new MultipartFormDataStreamProvider(Path.GetTempPath()); var parts = await Request.Content.ReadAsMultipartAsync(provider).ConfigureAwait(false); // Validate the request body if (string.IsNullOrEmpty(parts.FormData["uploadTransactionType"])) { errors.Add(GeneralErrorCodes.FormDataFieldMissing("uploadTransactionType")); } var tenantIdString = parts.FormData["tenantId"]; if (string.IsNullOrEmpty(tenantIdString)) { errors.Add(GeneralErrorCodes.FormDataFieldMissing("tenantId")); } var tenantIdGuid = Guid.Empty; if (!Guid.TryParse(tenantIdString, out tenantIdGuid) || tenantIdGuid == Guid.Empty) { errors.Add(GeneralErrorCodes.FormDataFieldInvalid("tenantId")); } // Get files var files = parts.FileData.Select(x => x.LocalFileName); var enumeratedFiles = files as IList <string> ?? files.ToList(); if (!enumeratedFiles.Any()) { errors.Add(GeneralErrorCodes.FormDataFilesMissing()); } if (errors.Any()) { return(Request.CreateApiResponse(NoDtoHelpers.CreateCommandResult(errors))); } var fileToUpload = enumeratedFiles.First(); var originalFileName = parts.FileData[0].Headers.ContentDisposition.FileName.Replace("\"", string.Empty); var fileUploadMetadata = new FileUploadMetadataDto { SavedFileName = fileToUpload, OriginalFileName = originalFileName, TransactionType = parts.FormData["uploadTransactionType"].Replace("\"", string.Empty) }; var authHeader = Request.Headers.Authorization.ToString(); var result = await _facade.Upload(fileUploadMetadata, authHeader, tenantIdGuid); foreach (var file in enumeratedFiles) { File.Delete(file); } return(Request.CreateApiResponse(result)); }
public override async Task <CommandResult <InAppMessageBaseDto, Guid> > Update(Guid id, Delta <InAppMessageBaseDto> delta) { // Check user has proper access to update the message var uid = GetCurrentUser(); if (!uid.HasValue) { return(Command.Error <InAppMessageBaseDto>(GeneralErrorCodes.TokenInvalid("UserId"))); } if (delta == null) { return(Command.Error <InAppMessageBaseDto>(EntityErrorCode.EntityFormatIsInvalid)); } var entity = _context.InAppMessages.SingleOrDefault(msg => msg.Id == id); if (entity == null) { return(Command.Error <InAppMessageBaseDto>(EntityErrorCode.EntityNotFound)); } // Check if the calling User shares a Tenant with the UserId passed in var tenants = _context.GetTenantsForUser(uid.Value); var shareTenant = tenants.Any(t => t.Users.Any(u => u.Id == entity.UserId)); if (!shareTenant) { return(Command.Error <InAppMessageBaseDto>(ValidationErrorCode.ForeignKeyValueDoesNotExist("UserId"))); } var dto = _mapper.Map(entity, new InAppMessageBaseDto()); delta.Patch(dto); var validationResponse = ValidatorUpdate.Validate(dto); // Including the original Id in the Patch request will not return an error but attempting to change the Id is not allowed. if (dto.Id != id) { validationResponse.FFErrors.Add(ValidationErrorCode.EntityIDUpdateNotAllowed("Id")); } if (validationResponse.IsInvalid) { return(Command.Error <InAppMessageBaseDto>(validationResponse)); } // Apply the update _context.InAppMessages.Attach(entity); //if the entity's IsRead flag get set to true from false, then set the DateRead to now if (dto.IsRead == true == !entity.IsRead) { entity.DateRead = DateTime.UtcNow; } else if (dto.IsRead == false == !entity.IsRead) { entity.DateRead = null; } _mapper.Map(dto, entity); entity.SetAuditFieldsOnUpdate(uid.Value); await _context.SaveChangesAsync().ConfigureAwait(false); return(Command.NoContent <InAppMessageBaseDto>()); }
/// <summary> /// Retrieves the indicated file. /// </summary> /// <param name="id"> /// ID that uniquely identifies the file to be retrieved. The ID is is the key of the /// metadata stored in DocumentDb. /// </param> /// <returns>The file indicated by the specified ID.</returns> public async Task <HttpResponseMessage> Get(Guid?id) { // Check that token contains a user ID var userId = Thread.CurrentPrincipal == null ? null : Thread.CurrentPrincipal.GetUserIdFromPrincipal(); if (userId == null) { return(HandleErrors(GeneralErrorCodes.TokenInvalid("UserId"), HttpStatusCode.Unauthorized)); } // Make sure user ID is active var userIdGuid = new Guid(userId); var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == userIdGuid); if (user == null || !user.IsActive) { return(HandleErrors(GeneralErrorCodes.TokenInvalid("UserId"), HttpStatusCode.Unauthorized)); } // Make sure there's a tenant associated with the user if (user.Tenants.Count < 1) { return(HandleErrors(GeneralErrorCodes.TokenInvalid("UserId"), HttpStatusCode.Unauthorized)); } // Validate the argument (invalid Guid's are received as nulls) if (id == null) { return(HandleErrors(ValidationErrorCode.PropertyIsInvalid(nameof(id)), HttpStatusCode.BadRequest)); } // Retrieve the metadata associated with the specified ID var metadata = await _documentDb.GetItemAsync(id.ToString()); if (metadata == null || string.IsNullOrWhiteSpace(metadata.BlobStorageContainerName) || string.IsNullOrWhiteSpace(metadata.BlobStorageBlobName)) { return(HandleErrors(EntityErrorCode.EntityNotFound, HttpStatusCode.NotFound)); } // Make sure the user is authorized (intentionally returns Not Found even though it's an authorization problem) if (metadata.TenantIds.Count < 1 || !metadata.TenantIds.Intersect(user.Tenants.Select(u => u.Id)).Any()) { return(HandleErrors(EntityErrorCode.EntityNotFound, HttpStatusCode.NotFound)); } // Retrieve the blob var stream = new MemoryStream(); BlobDownloadResult result; try { result = await _blobManager.DownloadBlobAsync(stream, _blobStorageConnectionString, metadata.BlobStorageContainerName, metadata.BlobStorageBlobName); } catch (Exception ex) { FFLogManager.LogException(ex); return(HandleErrors(EntityErrorCode.EntityNotFound, HttpStatusCode.NotFound)); } if (stream.Length == 0) { return(HandleErrors(EntityErrorCode.EntityNotFound, HttpStatusCode.NotFound)); } // Create the response stream.Position = 0; var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StreamContent(stream) }; // Determine file name string filename = result.BlobName; if (!string.IsNullOrWhiteSpace(metadata.OriginalFileName)) { var fileInfo = new FileInfo(metadata.OriginalFileName); if (!string.IsNullOrWhiteSpace(fileInfo.Name)) { filename = fileInfo.Name; } } // Set response content headers response.Content.Headers.ContentLength = stream.Length; response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = filename, Size = stream.Length }; return(response); }