using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using AyaNova.Util; using AyaNova.Api.ControllerHelpers; using AyaNova.Models; using System.Linq; namespace AyaNova.Biz { internal class NotifySubscriptionBiz : BizObject//, IJobObject, ISearchAbleObject { internal NotifySubscriptionBiz(AyContext dbcontext, long currentUserId, long userTranslationId, AuthorizationRoles UserRoles) { ct = dbcontext; UserId = currentUserId; UserTranslationId = userTranslationId; CurrentUserRoles = UserRoles; BizType = AyaType.NotifySubscription; } internal static NotifySubscriptionBiz GetBiz(AyContext ct, Microsoft.AspNetCore.Http.HttpContext httpContext = null) { if (httpContext != null) return new NotifySubscriptionBiz(ct, UserIdFromContext.Id(httpContext.Items), UserTranslationIdFromContext.Id(httpContext.Items), UserRolesFromContext.Roles(httpContext.Items)); else return new NotifySubscriptionBiz(ct, 1, ServerBootConfig.AYANOVA_DEFAULT_TRANSLATION_ID, AuthorizationRoles.BizAdmin); } //////////////////////////////////////////////////////////////////////////////////////////////// //EXISTS internal async Task ExistsAsync(long id) { return await ct.NotifySubscription.AnyAsync(z => z.Id == id); } //////////////////////////////////////////////////////////////////////////////////////////////// //CREATE // internal async Task CreateAsync(NotifySubscription newObject) { await ValidateAsync(newObject); if (HasErrors) return null; else { newObject.Tags = TagBiz.NormalizeTags(newObject.Tags); await ct.NotifySubscription.AddAsync(newObject); await ct.SaveChangesAsync(); await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct); await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, newObject.Tags, null); return newObject; } } //////////////////////////////////////////////////////////////////////////////////////////////// // GET // internal async Task GetAsync(long id, bool logTheGetEvent = true) { var ret = await ct.NotifySubscription.AsNoTracking().SingleOrDefaultAsync(z => z.Id == id && z.UserId == UserId); if (logTheGetEvent && ret != null) await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, id, BizType, AyaEvent.Retrieved), ct); return ret; } //////////////////////////////////////////////////////////////////////////////////////////////// //UPDATE // internal async Task PutAsync(NotifySubscription putObject) { //TODO: Must remove all prior events and replace them var dbObject = await GetAsync(putObject.Id, false); if (dbObject == null) { AddError(ApiErrorCode.NOT_FOUND, "id"); return null; } if (dbObject.Concurrency != putObject.Concurrency) { AddError(ApiErrorCode.CONCURRENCY_CONFLICT); return null; } putObject.Tags = TagBiz.NormalizeTags(putObject.Tags); await ValidateAsync(putObject); if (HasErrors) return null; ct.Replace(dbObject, putObject); if (HasErrors) return null; try { await ct.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!await ExistsAsync(putObject.Id)) AddError(ApiErrorCode.NOT_FOUND); else AddError(ApiErrorCode.CONCURRENCY_CONFLICT); return null; } await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, BizType, AyaEvent.Modified), ct); await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, putObject.Tags, dbObject.Tags); return putObject; } //////////////////////////////////////////////////////////////////////////////////////////////// //DELETE // internal async Task DeleteAsync(long id) { using (var transaction = await ct.Database.BeginTransactionAsync()) { var dbObject = await GetAsync(id, false); if (dbObject == null) { AddError(ApiErrorCode.NOT_FOUND); return false; } //ValidateCanDelete(dbObject); if (HasErrors) return false; { var IDList = await ct.Review.AsNoTracking().Where(x => x.AType == AyaType.NotifySubscription && x.ObjectId == id).Select(x => x.Id).ToListAsync(); if (IDList.Count() > 0) { ReviewBiz b = new ReviewBiz(ct, UserId, UserTranslationId, CurrentUserRoles); foreach (long ItemId in IDList) if (!await b.DeleteAsync(ItemId, transaction)) { AddError(ApiErrorCode.CHILD_OBJECT_ERROR, null, $"Review [{ItemId}]: {b.GetErrorsAsString()}"); return false; } } } ct.NotifySubscription.Remove(dbObject); await ct.SaveChangesAsync(); //Log event await EventLogProcessor.DeleteObjectLogAsync(UserId, BizType, dbObject.Id, dbObject.EventType.ToString(), ct); // await Search.ProcessDeletedObjectKeywordsAsync(dbObject.Id, BizType, ct); await TagBiz.ProcessDeleteTagsInRepositoryAsync(ct, dbObject.Tags); //TODO: DELETE RELATED RECORDS HERE //all good do the commit await transaction.CommitAsync(); return true; } } //////////////////////////////////////////////////////////////////////////////////////////////// //VALIDATION // private async Task ValidateAsync(NotifySubscription proposedObj) { //############################################################################### //todo: validate subscription is valid //perhaps check if customer type user doesn't have non customer notification etc //todo: notifysubscriptionbiz Check for duplicate before accepting new / edit in validator //DISALLOW entirely duplicate notifications (down to email address) //USE NAME DUPE CHECK PATTERN BELOW //############################################################################### //ensure user exists and need it for other shit later var user = await ct.User.AsNoTracking().FirstOrDefaultAsync(z => z.Id == proposedObj.UserId); if (user == null) { AddError(ApiErrorCode.VALIDATION_REQUIRED, "UserId"); } else { //Validate user can see this subscription type if (user.UserType == UserType.Customer || user.UserType == UserType.HeadOffice) { //Outside users can't choose inside user type notification events switch (proposedObj.EventType) { case NotifyEventType.CSRAccepted: case NotifyEventType.CSRRejected: case NotifyEventType.CustomerServiceImminent: case NotifyEventType.WorkorderCompleted: case NotifyEventType.WorkorderCreatedForCustomer: break; default: AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "EventType"); break; } } else { //Inside users can't use Outside (customer) users notification types switch (proposedObj.EventType) { case NotifyEventType.CSRAccepted: case NotifyEventType.CSRRejected: case NotifyEventType.CustomerServiceImminent: AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "EventType"); break; default: break; } } } if (proposedObj.DeliveryMethod == NotifyDeliveryMethod.App && !string.IsNullOrEmpty(proposedObj.DeliveryAddress)) { AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "DeliveryAddress", "In app delivery should not specify a delivery address"); } if (proposedObj.EventType == NotifyEventType.UnitMeterReadingMultipleExceeded) { //validate decvalue is a long try { long lValue= System.Convert.ToInt64(proposedObj.DecValue); if(lValue < 5){//arbitrary value AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "DecValue", "Value is too small, must be 5 or higher"); } } catch (System.OverflowException) { AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "DecValue", "Value is too large, must be less than 9,223,372,036,854,775,807"); } } } ///////////////////////////////////////////////////////////////////// }//eoc }//eons