This commit is contained in:
@@ -30,3 +30,4 @@ Here are all the API level error codes that can be returned by the API server:
|
|||||||
| 2207 | Validation error - The start date must be earlier than the end date |
|
| 2207 | Validation error - The start date must be earlier than the end date |
|
||||||
| 2208 | Validation error - Modifying the object (usually a delete) would break the link to other records in the database and operation was disallowed to preserve data integrity |
|
| 2208 | Validation error - Modifying the object (usually a delete) would break the link to other records in the database and operation was disallowed to preserve data integrity |
|
||||||
| 2209 | Validation error - Indicates the attempted property change is invalid because the value is fixed and cannot be changed |
|
| 2209 | Validation error - Indicates the attempted property change is invalid because the value is fixed and cannot be changed |
|
||||||
|
| 2210 | Child object error - Indicates the attempted operation resulted in errors in linked child object |
|
||||||
@@ -27,7 +27,8 @@ namespace AyaNova.Biz
|
|||||||
VALIDATION_NOT_UNIQUE = 2206,
|
VALIDATION_NOT_UNIQUE = 2206,
|
||||||
VALIDATION_STARTDATE_AFTER_ENDDATE = 2207,
|
VALIDATION_STARTDATE_AFTER_ENDDATE = 2207,
|
||||||
VALIDATION_REFERENTIAL_INTEGRITY = 2208,
|
VALIDATION_REFERENTIAL_INTEGRITY = 2208,
|
||||||
VALIDATION_NOT_CHANGEABLE = 2209
|
VALIDATION_NOT_CHANGEABLE = 2209,
|
||||||
|
CHILD_OBJECT_ERROR = 2210
|
||||||
/*
|
/*
|
||||||
|
|
||||||
| 2000 | API closed - Server is running but access to the API has been closed to all users |
|
| 2000 | API closed - Server is running but access to the API has been closed to all users |
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ namespace AyaNova.Biz
|
|||||||
return "Modifying the object (usually a delete) would break the link to other records in the database and operation was disallowed to preserve data integrity";
|
return "Modifying the object (usually a delete) would break the link to other records in the database and operation was disallowed to preserve data integrity";
|
||||||
case ApiErrorCode.VALIDATION_NOT_CHANGEABLE:
|
case ApiErrorCode.VALIDATION_NOT_CHANGEABLE:
|
||||||
return "the value is fixed and cannot be changed";
|
return "the value is fixed and cannot be changed";
|
||||||
|
case ApiErrorCode.CHILD_OBJECT_ERROR:
|
||||||
|
return "Errors in child object during operation";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,12 @@ namespace AyaNova.Biz
|
|||||||
_errors.Add(new ValidationError() { Code = errorCode, Message = errorMessage, Target = propertyName });
|
_errors.Add(new ValidationError() { Code = errorCode, Message = errorMessage, Target = propertyName });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// //Add a bunch of errors, generally from a child object failed operastion
|
||||||
|
// public void AddErrors(List<ValidationError> errors)
|
||||||
|
// {
|
||||||
|
// _errors.AddRange(errors);
|
||||||
|
// }
|
||||||
|
|
||||||
public string GetErrorsAsString()
|
public string GetErrorsAsString()
|
||||||
{
|
{
|
||||||
if (!HasErrors) return string.Empty;
|
if (!HasErrors) return string.Empty;
|
||||||
|
|||||||
@@ -151,7 +151,8 @@ namespace AyaNova.Biz
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
Customer dbObject = await ct.Customer.SingleOrDefaultAsync(z => z.Id == id);
|
Customer dbObject = await ct.Customer.SingleOrDefaultAsync(z => z.Id == id);
|
||||||
if (dbObject == null){
|
if (dbObject == null)
|
||||||
|
{
|
||||||
AddError(ApiErrorCode.NOT_FOUND);
|
AddError(ApiErrorCode.NOT_FOUND);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -159,10 +160,38 @@ namespace AyaNova.Biz
|
|||||||
if (HasErrors)
|
if (HasErrors)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//todo: delete contacts and customer notes
|
|
||||||
//see workorder* collections and delete for transactional inclusion etc
|
//DELETE DIRECT CHILD OBJECTS
|
||||||
|
//(note: the convention is to allow deletion of children created *in* the same UI area so this will delete contacts, customer notes, but not workorders of this customer for example)
|
||||||
|
|
||||||
//Will need to possibly display refintegrity error from the *linked* object delete attemp, i.e. Contact for here
|
//Will need to possibly display refintegrity error from the *linked* object delete attemp, i.e. Contact for here
|
||||||
//so should test that out so that it flows to the UI so user understands they can't delete the Customer due to a Contact having links to other objects
|
//so should test that out so that it flows to the UI so user understands they can't delete the Customer due to a Contact having links to other objects
|
||||||
|
{
|
||||||
|
var ContactIds = await ct.User.AsNoTracking().Where(z => z.CustomerId == id).Select(z => z.Id).ToListAsync();
|
||||||
|
if (ContactIds.Count() > 0)
|
||||||
|
{
|
||||||
|
UserBiz b = new UserBiz(ct, UserId, UserTranslationId, CurrentUserRoles);
|
||||||
|
foreach (long ItemId in ContactIds)
|
||||||
|
if (!await b.DeleteAsync(ItemId, transaction))
|
||||||
|
{
|
||||||
|
AddError(ApiErrorCode.VALIDATION_REQUIRED,b.GetErrorsAsString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var CustomerNoteIds = await ct.CustomerNote.AsNoTracking().Where(z => z.CustomerId == id).Select(z => z.Id).ToListAsync();
|
||||||
|
if (CustomerNoteIds.Count() > 0)
|
||||||
|
{
|
||||||
|
CustomerNoteBiz b = new CustomerNoteBiz(ct, UserId, UserTranslationId, CurrentUserRoles);
|
||||||
|
foreach (long ItemId in CustomerNoteIds)
|
||||||
|
if (!await b.DeleteAsync(ItemId, transaction))
|
||||||
|
{
|
||||||
|
AddErrors(b.Errors);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ct.Customer.Remove(dbObject);
|
ct.Customer.Remove(dbObject);
|
||||||
await ct.SaveChangesAsync();
|
await ct.SaveChangesAsync();
|
||||||
@@ -177,6 +206,7 @@ namespace AyaNova.Biz
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
//NOTE: no need to rollback the transaction, it will auto-rollback if not committed and it is disposed when it goes out of scope either way
|
||||||
|
|
||||||
//Just re-throw for now, let exception handler deal, but in future may want to deal with this more here
|
//Just re-throw for now, let exception handler deal, but in future may want to deal with this more here
|
||||||
throw;
|
throw;
|
||||||
|
|||||||
@@ -109,39 +109,45 @@ namespace AyaNova.Biz
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//DELETE
|
//DELETE
|
||||||
//
|
//
|
||||||
internal async Task<bool> DeleteAsync(long id)
|
internal async Task<bool> DeleteAsync(long id, Microsoft.EntityFrameworkCore.Storage.IDbContextTransaction parentTransaction = null)
|
||||||
{
|
{
|
||||||
using (var transaction = await ct.Database.BeginTransactionAsync())
|
//this may be part of a larger delete operation involving other objects (e.g. Customer delete and remove contacts)
|
||||||
|
//if so then there will be a parent transaction otherwise we make our own
|
||||||
|
Microsoft.EntityFrameworkCore.Storage.IDbContextTransaction transaction = null;
|
||||||
|
if (parentTransaction == null)
|
||||||
|
transaction = await ct.Database.BeginTransactionAsync();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
CustomerNote dbObject = await ct.CustomerNote.SingleOrDefaultAsync(m => m.Id == id);
|
||||||
|
if (dbObject == null)
|
||||||
{
|
{
|
||||||
CustomerNote dbObject = await ct.CustomerNote.SingleOrDefaultAsync(m => m.Id == id);
|
AddError(ApiErrorCode.NOT_FOUND);
|
||||||
if (dbObject == null){
|
return false;
|
||||||
AddError(ApiErrorCode.NOT_FOUND);
|
}
|
||||||
return false;
|
if (HasErrors)
|
||||||
}
|
return false;
|
||||||
if (HasErrors)
|
if (HasErrors)
|
||||||
return false;
|
return false;
|
||||||
if (HasErrors)
|
ct.CustomerNote.Remove(dbObject);
|
||||||
return false;
|
await ct.SaveChangesAsync();
|
||||||
ct.CustomerNote.Remove(dbObject);
|
|
||||||
await ct.SaveChangesAsync();
|
|
||||||
|
|
||||||
|
|
||||||
await EventLogProcessor.DeleteObjectLogAsync(UserId, BizType, dbObject.Id, "CustomerNote", ct);
|
await EventLogProcessor.DeleteObjectLogAsync(UserId, BizType, dbObject.Id, "CustomerNote", ct);
|
||||||
await Search.ProcessDeletedObjectKeywordsAsync(dbObject.Id, BizType, ct);
|
await Search.ProcessDeletedObjectKeywordsAsync(dbObject.Id, BizType, ct);
|
||||||
await TagBiz.ProcessDeleteTagsInRepositoryAsync(ct, dbObject.Tags);
|
await TagBiz.ProcessDeleteTagsInRepositoryAsync(ct, dbObject.Tags);
|
||||||
await FileUtil.DeleteAttachmentsForObjectAsync(BizType, dbObject.Id, ct);
|
await FileUtil.DeleteAttachmentsForObjectAsync(BizType, dbObject.Id, ct);
|
||||||
|
//all good do the commit if it's ours
|
||||||
|
if (parentTransaction == null)
|
||||||
await transaction.CommitAsync();
|
await transaction.CommitAsync();
|
||||||
// await NotifyEventProcessor.HandlePotentialNotificationEvent(AyaEvent.Deleted, dbObject);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//Just re-throw for now, let exception handler deal, but in future may want to deal with this more here
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//Just re-throw for now, let exception handler deal, but in future may want to deal with this more here
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -442,65 +442,71 @@ namespace AyaNova.Biz
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//DELETE
|
//DELETE
|
||||||
//
|
//
|
||||||
internal async Task<bool> DeleteAsync(long id)
|
internal async Task<bool> DeleteAsync(long id, Microsoft.EntityFrameworkCore.Storage.IDbContextTransaction parentTransaction = null)
|
||||||
{
|
{
|
||||||
|
//this may be part of a larger delete operation involving other objects (e.g. Customer delete and remove contacts)
|
||||||
using (var transaction = await ct.Database.BeginTransactionAsync())
|
//if so then there will be a parent transaction otherwise we make our own
|
||||||
|
Microsoft.EntityFrameworkCore.Storage.IDbContextTransaction transaction = null;
|
||||||
|
if (parentTransaction == null)
|
||||||
|
transaction = await ct.Database.BeginTransactionAsync();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
User dbObject = await ct.User.SingleOrDefaultAsync(z => z.Id == id);
|
||||||
|
if (dbObject == null)
|
||||||
{
|
{
|
||||||
User dbObject = await ct.User.SingleOrDefaultAsync(z => z.Id == id);
|
AddError(ApiErrorCode.NOT_FOUND);
|
||||||
if (dbObject == null)
|
return false;
|
||||||
{
|
}
|
||||||
AddError(ApiErrorCode.NOT_FOUND);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Also used for Contacts (customer type user or ho type user)
|
//Also used for Contacts (customer type user or ho type user)
|
||||||
//by users with no User right but with Customer rights so need to double check here
|
//by users with no User right but with Customer rights so need to double check here
|
||||||
if (
|
if (
|
||||||
(dbObject.IsOutsideUser && !Authorized.HasDeleteRole(CurrentUserRoles, AyaType.Customer)) ||
|
(dbObject.IsOutsideUser && !Authorized.HasDeleteRole(CurrentUserRoles, AyaType.Customer)) ||
|
||||||
(!dbObject.IsOutsideUser && !Authorized.HasDeleteRole(CurrentUserRoles, AyaType.User))
|
(!dbObject.IsOutsideUser && !Authorized.HasDeleteRole(CurrentUserRoles, AyaType.User))
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
AddError(ApiErrorCode.NOT_AUTHORIZED);
|
AddError(ApiErrorCode.NOT_AUTHORIZED);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
await ValidateCanDelete(dbObject);
|
await ValidateCanDelete(dbObject);
|
||||||
if (HasErrors)
|
if (HasErrors)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//Delete sibling objects
|
//Delete sibling objects
|
||||||
//USEROPTIONS
|
//USEROPTIONS
|
||||||
await ct.Database.ExecuteSqlInterpolatedAsync($"delete from auseroptions where userid = {dbObject.Id}");
|
await ct.Database.ExecuteSqlInterpolatedAsync($"delete from auseroptions where userid = {dbObject.Id}");
|
||||||
//NOTIFY SUBSCRIPTIONS
|
//NOTIFY SUBSCRIPTIONS
|
||||||
await ct.Database.ExecuteSqlInterpolatedAsync($"delete from anotifysubscription where userid = {dbObject.Id}");
|
await ct.Database.ExecuteSqlInterpolatedAsync($"delete from anotifysubscription where userid = {dbObject.Id}");
|
||||||
//personal datalistview
|
//personal datalistview
|
||||||
await ct.Database.ExecuteSqlInterpolatedAsync($"delete from adatalistview where public = {false} and userid = {dbObject.Id}");
|
await ct.Database.ExecuteSqlInterpolatedAsync($"delete from adatalistview where public = {false} and userid = {dbObject.Id}");
|
||||||
//Dashboard view
|
//Dashboard view
|
||||||
await ct.Database.ExecuteSqlInterpolatedAsync($"delete from adashboardview where userid = {dbObject.Id}");
|
await ct.Database.ExecuteSqlInterpolatedAsync($"delete from adashboardview where userid = {dbObject.Id}");
|
||||||
|
|
||||||
await EventLogProcessor.DeleteObjectLogAsync(UserId, BizType, dbObject.Id, dbObject.Name, ct);
|
//Remove the object
|
||||||
await Search.ProcessDeletedObjectKeywordsAsync(dbObject.Id, BizType, ct);
|
ct.User.Remove(dbObject);
|
||||||
await TagBiz.ProcessDeleteTagsInRepositoryAsync(ct, dbObject.Tags);
|
await ct.SaveChangesAsync();
|
||||||
await FileUtil.DeleteAttachmentsForObjectAsync(BizType, dbObject.Id, ct);
|
|
||||||
|
|
||||||
//Remove the object
|
await EventLogProcessor.DeleteObjectLogAsync(UserId, BizType, dbObject.Id, dbObject.Name, ct);
|
||||||
ct.User.Remove(dbObject);
|
await Search.ProcessDeletedObjectKeywordsAsync(dbObject.Id, BizType, ct);
|
||||||
await ct.SaveChangesAsync();
|
await TagBiz.ProcessDeleteTagsInRepositoryAsync(ct, dbObject.Tags);
|
||||||
|
await FileUtil.DeleteAttachmentsForObjectAsync(BizType, dbObject.Id, ct);
|
||||||
|
|
||||||
|
//all good do the commit if it's ours
|
||||||
|
if (parentTransaction == null)
|
||||||
await transaction.CommitAsync();
|
await transaction.CommitAsync();
|
||||||
await NotifyEventProcessor.HandlePotentialNotificationEvent(AyaEvent.Deleted, dbObject);
|
await NotifyEventProcessor.HandlePotentialNotificationEvent(AyaEvent.Deleted, dbObject);
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//Just re-throw for now, let exception handler deal, but in future may want to deal with this more here
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//Just re-throw for now, let exception handler deal, but in future may want to deal with this more here
|
||||||
|
//no need to rollback, the transaction will rollback automatically if it's disposed without committing
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
//Note: Transaction does not need to be disposed it will automatically when it goes out of scope due to Using statement
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1616,6 +1616,7 @@
|
|||||||
"ErrorAPI2207": "Das Startdatum muss vor dem Enddatum liegen",
|
"ErrorAPI2207": "Das Startdatum muss vor dem Enddatum liegen",
|
||||||
"ErrorAPI2208": "Dieses Objekt ist mit anderen verknüpft und kann auf diese Weise nicht geändert werden",
|
"ErrorAPI2208": "Dieses Objekt ist mit anderen verknüpft und kann auf diese Weise nicht geändert werden",
|
||||||
"ErrorAPI2209": "Dieser Wert kann nicht geändert werden",
|
"ErrorAPI2209": "Dieser Wert kann nicht geändert werden",
|
||||||
|
"ErrorAPI2210": "Untergeordneter Objektfehler",
|
||||||
"ErrorServerUnresponsive": "Der Server reagiert nicht (E17)",
|
"ErrorServerUnresponsive": "Der Server reagiert nicht (E17)",
|
||||||
"ErrorUserNotAuthenticated": "Nicht authentifiziert (E16)",
|
"ErrorUserNotAuthenticated": "Nicht authentifiziert (E16)",
|
||||||
"ErrorUserNotAuthorized": "Nicht autorisiert",
|
"ErrorUserNotAuthorized": "Nicht autorisiert",
|
||||||
|
|||||||
@@ -1616,6 +1616,7 @@
|
|||||||
"ErrorAPI2207": "Start date must be before end date",
|
"ErrorAPI2207": "Start date must be before end date",
|
||||||
"ErrorAPI2208": "This object is linked to others and can not be changed this way",
|
"ErrorAPI2208": "This object is linked to others and can not be changed this way",
|
||||||
"ErrorAPI2209": "This value cannot be changed",
|
"ErrorAPI2209": "This value cannot be changed",
|
||||||
|
"ErrorAPI2210": "Child object error",
|
||||||
"ErrorServerUnresponsive": "Server not responding (E17)",
|
"ErrorServerUnresponsive": "Server not responding (E17)",
|
||||||
"ErrorUserNotAuthenticated": "Not authenticated (E16)",
|
"ErrorUserNotAuthenticated": "Not authenticated (E16)",
|
||||||
"ErrorUserNotAuthorized": "Not authorized",
|
"ErrorUserNotAuthorized": "Not authorized",
|
||||||
|
|||||||
@@ -1616,6 +1616,7 @@
|
|||||||
"ErrorAPI2207": "La fecha de inicio debe ser anterior a la fecha de finalización",
|
"ErrorAPI2207": "La fecha de inicio debe ser anterior a la fecha de finalización",
|
||||||
"ErrorAPI2208": "Este objeto está vinculado a otros y no puede ser cambiado de esta manera",
|
"ErrorAPI2208": "Este objeto está vinculado a otros y no puede ser cambiado de esta manera",
|
||||||
"ErrorAPI2209": "Este valor no puede ser cambiado",
|
"ErrorAPI2209": "Este valor no puede ser cambiado",
|
||||||
|
"ErrorAPI2210": "Error de objeto secundario",
|
||||||
"ErrorServerUnresponsive": "El servidor no responde (E17)",
|
"ErrorServerUnresponsive": "El servidor no responde (E17)",
|
||||||
"ErrorUserNotAuthenticated": "No autenticado (E16)",
|
"ErrorUserNotAuthenticated": "No autenticado (E16)",
|
||||||
"ErrorUserNotAuthorized": "No autorizado",
|
"ErrorUserNotAuthorized": "No autorizado",
|
||||||
|
|||||||
@@ -1616,6 +1616,7 @@
|
|||||||
"ErrorAPI2207": "La date de début doit être antérieure à la date de fin",
|
"ErrorAPI2207": "La date de début doit être antérieure à la date de fin",
|
||||||
"ErrorAPI2208": "Cet objet est lié à d'autres et ne peut pas être modifié de cette façon",
|
"ErrorAPI2208": "Cet objet est lié à d'autres et ne peut pas être modifié de cette façon",
|
||||||
"ErrorAPI2209": "Cette valeur ne peut pas être changée",
|
"ErrorAPI2209": "Cette valeur ne peut pas être changée",
|
||||||
|
"ErrorAPI2210": "Erreur d'objet enfant",
|
||||||
"ErrorServerUnresponsive": "Le serveur ne répond pas (E17)",
|
"ErrorServerUnresponsive": "Le serveur ne répond pas (E17)",
|
||||||
"ErrorUserNotAuthenticated": "Non authentifié (E16)",
|
"ErrorUserNotAuthenticated": "Non authentifié (E16)",
|
||||||
"ErrorUserNotAuthorized": "Non autorisé",
|
"ErrorUserNotAuthorized": "Non autorisé",
|
||||||
|
|||||||
Reference in New Issue
Block a user