This commit is contained in:
@@ -26,7 +26,9 @@ namespace AyaNova.Biz
|
|||||||
TrialSeeder = 11,
|
TrialSeeder = 11,
|
||||||
Metrics = 12,
|
Metrics = 12,
|
||||||
Locale = 13,
|
Locale = 13,
|
||||||
UserOptions=14
|
UserOptions=14,
|
||||||
|
TagGroup = 15,
|
||||||
|
TagGroupMap = 16
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,26 @@ namespace AyaNova.Biz
|
|||||||
ReadFullRecord = AuthorizationRoles.AnyRole
|
ReadFullRecord = AuthorizationRoles.AnyRole
|
||||||
});
|
});
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//TAGGROUP - MIRROR TAGS
|
||||||
|
//Full roles can make new tags and can edit or delete existing tags
|
||||||
|
roles.Add(AyaType.TagGroup, new BizRoleSet()
|
||||||
|
{
|
||||||
|
Change = AuthorizationRoles.BizAdminFull | AuthorizationRoles.DispatchFull | AuthorizationRoles.InventoryFull | AuthorizationRoles.TechFull | AuthorizationRoles.AccountingFull,
|
||||||
|
EditOwn = AuthorizationRoles.NoRole,
|
||||||
|
ReadFullRecord = AuthorizationRoles.AnyRole
|
||||||
|
});
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//TAGGROUPMAP - MIRROR TAGMAP
|
||||||
|
//Any roles can tag objects and remove tags as per their rights to the taggable object type in question
|
||||||
|
roles.Add(AyaType.TagGroupMap, new BizRoleSet()
|
||||||
|
{
|
||||||
|
Change = AuthorizationRoles.AnyRole,
|
||||||
|
EditOwn = AuthorizationRoles.NoRole,
|
||||||
|
ReadFullRecord = AuthorizationRoles.AnyRole
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//OPERATIONS / JOBS
|
//OPERATIONS / JOBS
|
||||||
|
|||||||
426
server/AyaNova/biz/TagGroupBiz.cs
Normal file
426
server/AyaNova/biz/TagGroupBiz.cs
Normal file
@@ -0,0 +1,426 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.JsonPatch;
|
||||||
|
using EnumsNET;
|
||||||
|
using AyaNova.Util;
|
||||||
|
using AyaNova.Api.ControllerHelpers;
|
||||||
|
using AyaNova.Biz;
|
||||||
|
using AyaNova.Models;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace AyaNova.Biz
|
||||||
|
{
|
||||||
|
|
||||||
|
internal class TagGroupBiz : BizObject, IImportAyaNova7Object
|
||||||
|
{
|
||||||
|
private readonly AyContext ct;
|
||||||
|
public readonly long userId;
|
||||||
|
private readonly AuthorizationRoles userRoles;
|
||||||
|
|
||||||
|
public bool V7ValidationImportMode { get; set; }
|
||||||
|
|
||||||
|
internal TagGroupBiz(AyContext dbcontext, long currentUserId, AuthorizationRoles UserRoles)
|
||||||
|
{
|
||||||
|
ct = dbcontext;
|
||||||
|
userId = currentUserId;
|
||||||
|
userRoles = UserRoles;
|
||||||
|
V7ValidationImportMode = false;//default
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//CREATE
|
||||||
|
internal async Task<TagGroup> CreateAsync(string inObj)
|
||||||
|
{
|
||||||
|
inObj = CleanTagGroupName(inObj);
|
||||||
|
Validate(inObj, true);
|
||||||
|
if (HasErrors)
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//do stuff with TagGroup
|
||||||
|
TagGroup outObj = new TagGroup()
|
||||||
|
{
|
||||||
|
Name = inObj,
|
||||||
|
OwnerId = userId
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
await ct.TagGroup.AddAsync(outObj);
|
||||||
|
return outObj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string CleanTagGroupName(string inObj)
|
||||||
|
{
|
||||||
|
//Must be lowercase per rules
|
||||||
|
//This may be naive when we get international customers but for now supporting utf-8 and it appears it's safe to do this with unicode
|
||||||
|
inObj = inObj.ToLowerInvariant();
|
||||||
|
//No spaces in TagGroups, replace with dashes
|
||||||
|
inObj = inObj.Replace(" ", "-");
|
||||||
|
//Remove multiple dash sequences
|
||||||
|
inObj = System.Text.RegularExpressions.Regex.Replace(inObj, "-+", "-");
|
||||||
|
//Ensure doesn't start or end with a dash
|
||||||
|
inObj = inObj.Trim('-');
|
||||||
|
//No longer than 255 characters
|
||||||
|
inObj = StringUtil.MaxLength(inObj, 255);
|
||||||
|
return inObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// GET
|
||||||
|
|
||||||
|
//Get one
|
||||||
|
internal async Task<TagGroup> GetAsync(long fetchId)
|
||||||
|
{
|
||||||
|
//This is simple so nothing more here, but often will be copying to a different output object or some other ops
|
||||||
|
return await ct.TagGroup.SingleOrDefaultAsync(m => m.Id == fetchId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//get picklist (paged)
|
||||||
|
//Unlike most picklists, this one only checks for starts with and wildcards are not supported / treated as part of TagGroup name
|
||||||
|
internal async Task<ApiPagedResponse<NameIdItem>> GetPickListAsync(IUrlHelper Url, string routeName, PagingOptions pagingOptions, string q)
|
||||||
|
{
|
||||||
|
pagingOptions.Offset = pagingOptions.Offset ?? PagingOptions.DefaultOffset;
|
||||||
|
pagingOptions.Limit = pagingOptions.Limit ?? PagingOptions.DefaultLimit;
|
||||||
|
|
||||||
|
NameIdItem[] items;
|
||||||
|
int totalRecordCount = 0;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(q))
|
||||||
|
{
|
||||||
|
//TagGroups are allow saved this way so search this way too
|
||||||
|
q = q.ToLowerInvariant();
|
||||||
|
|
||||||
|
items = await ct.TagGroup
|
||||||
|
//There is some debate on this for efficiency
|
||||||
|
//I chose this method because I think it escapes potential wildcards in the string automatically
|
||||||
|
//and I don't want people using wildcards with this, only starts with is supported
|
||||||
|
//https://stackoverflow.com/questions/45708715/entity-framework-ef-functions-like-vs-string-contains
|
||||||
|
.Where(m => m.Name.StartsWith(q))
|
||||||
|
// .Where(m => EF.Functions.ILike(m.Name, q))
|
||||||
|
.OrderBy(m => m.Name)
|
||||||
|
.Skip(pagingOptions.Offset.Value)
|
||||||
|
.Take(pagingOptions.Limit.Value)
|
||||||
|
.Select(m => new NameIdItem()
|
||||||
|
{
|
||||||
|
Id = m.Id,
|
||||||
|
Name = m.Name
|
||||||
|
}).ToArrayAsync();
|
||||||
|
|
||||||
|
totalRecordCount = await ct.TagGroup.Where(m => m.Name.StartsWith(q)).CountAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
items = await ct.TagGroup
|
||||||
|
.OrderBy(m => m.Name)
|
||||||
|
.Skip(pagingOptions.Offset.Value)
|
||||||
|
.Take(pagingOptions.Limit.Value)
|
||||||
|
.Select(m => new NameIdItem()
|
||||||
|
{
|
||||||
|
Id = m.Id,
|
||||||
|
Name = m.Name
|
||||||
|
}).ToArrayAsync();
|
||||||
|
|
||||||
|
totalRecordCount = await ct.TagGroup.CountAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var pageLinks = new PaginationLinkBuilder(Url, routeName, null, pagingOptions, totalRecordCount).PagingLinksObject();
|
||||||
|
|
||||||
|
ApiPagedResponse<NameIdItem> pr = new ApiPagedResponse<NameIdItem>(items, pageLinks);
|
||||||
|
return pr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//UPDATE
|
||||||
|
//
|
||||||
|
|
||||||
|
//put
|
||||||
|
internal bool Put(TagGroup dbObj, TagGroup inObj)
|
||||||
|
{
|
||||||
|
//Ensure it follows the rules
|
||||||
|
inObj.Name = CleanTagGroupName(inObj.Name);
|
||||||
|
|
||||||
|
//Replace the db object with the PUT object
|
||||||
|
CopyObject.Copy(inObj, dbObj, "Id");
|
||||||
|
//Set "original" value of concurrency token to input token
|
||||||
|
//this will allow EF to check it out
|
||||||
|
ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = inObj.ConcurrencyToken;
|
||||||
|
|
||||||
|
Validate(dbObj.Name, false);
|
||||||
|
if (HasErrors)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//patch
|
||||||
|
internal bool Patch(TagGroup dbObj, JsonPatchDocument<TagGroup> objectPatch, uint concurrencyToken)
|
||||||
|
{
|
||||||
|
//Validate Patch is allowed
|
||||||
|
if (!ValidateJsonPatch<TagGroup>.Validate(this, objectPatch)) return false;
|
||||||
|
|
||||||
|
//Do the patching
|
||||||
|
objectPatch.ApplyTo(dbObj);
|
||||||
|
ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = concurrencyToken;
|
||||||
|
//Ensure it follows the rules
|
||||||
|
dbObj.Name = CleanTagGroupName(dbObj.Name);
|
||||||
|
Validate(dbObj.Name, false);
|
||||||
|
if (HasErrors)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//DELETE
|
||||||
|
//
|
||||||
|
|
||||||
|
internal bool Delete(TagGroup dbObj)
|
||||||
|
{
|
||||||
|
//Determine if the object can be deleted, do the deletion tentatively
|
||||||
|
|
||||||
|
ValidateCanDelete(dbObj);
|
||||||
|
if (HasErrors)
|
||||||
|
return false;
|
||||||
|
ct.TagGroup.Remove(dbObj);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//VALIDATION
|
||||||
|
//
|
||||||
|
|
||||||
|
//Can save or update?
|
||||||
|
private void Validate(string inObj, bool isNew)
|
||||||
|
{
|
||||||
|
//run validation and biz rules
|
||||||
|
|
||||||
|
//Name required
|
||||||
|
if (string.IsNullOrWhiteSpace(inObj))
|
||||||
|
AddError(ValidationErrorType.RequiredPropertyEmpty, "Name");
|
||||||
|
|
||||||
|
//Name must be less than 255 characters
|
||||||
|
if (inObj.Length > 255)
|
||||||
|
AddError(ValidationErrorType.LengthExceeded, "Name", "255 char max");
|
||||||
|
|
||||||
|
//Name must be unique
|
||||||
|
if (ct.TagGroup.Where(m => m.Name == inObj).FirstOrDefault() != null)
|
||||||
|
AddError(ValidationErrorType.NotUnique, "Name");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Can delete?
|
||||||
|
private void ValidateCanDelete(TagGroup inObj)
|
||||||
|
{
|
||||||
|
//whatever needs to be check to delete this object
|
||||||
|
|
||||||
|
//See if any TagGroupmaps exist with this TagGroup in which case it's not deleteable
|
||||||
|
if (ct.TagGroupMap.Any(e => e.TagGroupId == inObj.Id))
|
||||||
|
{
|
||||||
|
AddError(ValidationErrorType.ReferentialIntegrity, "object", "Can't be deleted while has relations");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// IMPORT v7 implementation
|
||||||
|
public async Task<bool> ImportV7Async(JObject j, List<ImportAyaNova7MapItem> importMap, Guid jobId)
|
||||||
|
{
|
||||||
|
//NO TASK TYPE, IT'S ALL THE SAME, KEEPING THIS FOR POSSIBLE FUTURE PURPOSES LIKE APPENDING OBJECT TYPE OR SOMETHING
|
||||||
|
string SourceType = j["V7_TYPE"].Value<string>();
|
||||||
|
switch (SourceType)
|
||||||
|
{
|
||||||
|
case "GZTW.AyaNova.BLL.Region":
|
||||||
|
case "GZTW.AyaNova.BLL.UnitModelCategory":
|
||||||
|
case "GZTW.AyaNova.BLL.UnitServiceType":
|
||||||
|
case "GZTW.AyaNova.BLL.WorkorderItemType":
|
||||||
|
case "GZTW.AyaNova.BLL.ClientGroup":
|
||||||
|
case "GZTW.AyaNova.BLL.WorkorderCategory":
|
||||||
|
case "GZTW.AyaNova.BLL.PartCategory":
|
||||||
|
case "GZTW.AyaNova.BLL.DispatchZone":
|
||||||
|
case "GZTW.AyaNova.BLL.ScheduleableUserGroup":
|
||||||
|
{
|
||||||
|
switch (j["IMPORT_TASK"].Value<string>())
|
||||||
|
{
|
||||||
|
case "main":
|
||||||
|
{
|
||||||
|
#region main import task
|
||||||
|
var NewTagGroupName = j["Name"].Value<string>();
|
||||||
|
|
||||||
|
var ShortTypeName = string.Empty;
|
||||||
|
switch (SourceType)
|
||||||
|
{
|
||||||
|
case "GZTW.AyaNova.BLL.Region":
|
||||||
|
ShortTypeName = "rgn";
|
||||||
|
break;
|
||||||
|
case "GZTW.AyaNova.BLL.UnitModelCategory":
|
||||||
|
ShortTypeName = "unitmdlctgry";
|
||||||
|
break;
|
||||||
|
case "GZTW.AyaNova.BLL.UnitServiceType":
|
||||||
|
ShortTypeName = "unitsvtyp";
|
||||||
|
break;
|
||||||
|
case "GZTW.AyaNova.BLL.WorkorderItemType":
|
||||||
|
ShortTypeName = "woitemtyp";
|
||||||
|
break;
|
||||||
|
case "GZTW.AyaNova.BLL.ClientGroup":
|
||||||
|
ShortTypeName = "clntgrp";
|
||||||
|
break;
|
||||||
|
case "GZTW.AyaNova.BLL.WorkorderCategory":
|
||||||
|
ShortTypeName = "woctgry";
|
||||||
|
break;
|
||||||
|
case "GZTW.AyaNova.BLL.PartCategory":
|
||||||
|
ShortTypeName = "prtctgry";
|
||||||
|
break;
|
||||||
|
case "GZTW.AyaNova.BLL.DispatchZone":
|
||||||
|
ShortTypeName = "dspchzn";
|
||||||
|
break;
|
||||||
|
case "GZTW.AyaNova.BLL.ScheduleableUserGroup":
|
||||||
|
ShortTypeName = "schdusrgrp";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NewTagGroupName += "." + ShortTypeName;
|
||||||
|
var OldV7Id = new Guid(j["ID"].Value<string>());
|
||||||
|
|
||||||
|
//Ensure it follows the rules
|
||||||
|
NewTagGroupName = CleanTagGroupName(NewTagGroupName);
|
||||||
|
|
||||||
|
//There might already be a TagGroup of the same name since so many different types of V7 objects are becoming TagGroups
|
||||||
|
//Weighed the pros and cons of uniquifying by object type versus just using the same name for different object types:
|
||||||
|
//it seems to me at this point that people might desire the same exact name because if they used it that way they probably
|
||||||
|
//intended it that way, so decision is to check if it already exists and then use that ID in the importMap instead
|
||||||
|
//for matching other objects imported to TagGroups
|
||||||
|
|
||||||
|
//Already present?
|
||||||
|
var ExistingTagGroup = ct.TagGroup.Where(m => m.Name == NewTagGroupName).FirstOrDefault();
|
||||||
|
if (ExistingTagGroup != null)
|
||||||
|
{
|
||||||
|
//map it to the existing TagGroup of same name
|
||||||
|
var mapItem = new ImportAyaNova7MapItem(OldV7Id, AyaType.TagGroup, ExistingTagGroup.Id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
TagGroup o = await CreateAsync(NewTagGroupName);
|
||||||
|
if (HasErrors)
|
||||||
|
{
|
||||||
|
//If there are any validation errors, log in joblog and move on
|
||||||
|
JobsBiz.LogJob(jobId, $"TagGroupBiz::ImportV7Async -> import object \"{NewTagGroupName}\" of type \"{SourceType}\" source id {OldV7Id.ToString()} failed validation and was not imported: {GetErrorsAsString()} ", ct);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ct.SaveChangesAsync();
|
||||||
|
var mapItem = new ImportAyaNova7MapItem(OldV7Id, AyaType.TagGroup, o.Id);
|
||||||
|
importMap.Add(mapItem);
|
||||||
|
await ImportAyaNova7Biz.LogEventCreatedModifiedEvents(j, importMap, AyaType.TagGroup, ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "scheduleableusergroupTagGroups":
|
||||||
|
{
|
||||||
|
#region attribute sched user group TagGroups
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
"ID": "871e77b2-979a-4f26-930b-46f7c05fc19f",
|
||||||
|
"Created": "08/30/2018 08:12 AM",
|
||||||
|
"Modified": "08/30/2018 08:13 AM",
|
||||||
|
"Creator": "2ecc77fc-69e2-4a7e-b88d-bd0ecaf36aed",
|
||||||
|
"Modifier": "2ecc77fc-69e2-4a7e-b88d-bd0ecaf36aed",
|
||||||
|
"Name": "Yet another test group",
|
||||||
|
"Active": true,
|
||||||
|
"Description": "More testing yay!",
|
||||||
|
"ScheduleableUsers": [
|
||||||
|
{
|
||||||
|
"Created": "08/30/2018 08:13 AM",
|
||||||
|
"Creator": "2ecc77fc-69e2-4a7e-b88d-bd0ecaf36aed",
|
||||||
|
"Modified": "08/30/2018 08:13 AM",
|
||||||
|
"Modifier": "2ecc77fc-69e2-4a7e-b88d-bd0ecaf36aed",
|
||||||
|
"ID": "676475be-8301-47d0-bd54-af9dbd1fe7eb",
|
||||||
|
"ScheduleableUserID": "1d859264-3f32-462a-9b0c-a67dddfdf4d3",
|
||||||
|
"ScheduleableUserGroupID": "871e77b2-979a-4f26-930b-46f7c05fc19f"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Created": "08/30/2018 08:13 AM",
|
||||||
|
"Creator": "2ecc77fc-69e2-4a7e-b88d-bd0ecaf36aed",
|
||||||
|
"Modified": "08/30/2018 08:13 AM",
|
||||||
|
"Modifier": "2ecc77fc-69e2-4a7e-b88d-bd0ecaf36aed",
|
||||||
|
"ID": "173499c3-a616-42a0-b08c-74008f8fa352",
|
||||||
|
"ScheduleableUserID": "42b282bb-100b-4b31-aa14-5c831d7cda66",
|
||||||
|
"ScheduleableUserGroupID": "871e77b2-979a-4f26-930b-46f7c05fc19f"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Created": "08/30/2018 08:13 AM",
|
||||||
|
"Creator": "2ecc77fc-69e2-4a7e-b88d-bd0ecaf36aed",
|
||||||
|
"Modified": "08/30/2018 08:13 AM",
|
||||||
|
"Modifier": "2ecc77fc-69e2-4a7e-b88d-bd0ecaf36aed",
|
||||||
|
"ID": "19c9b3d6-eeb2-44ac-be4e-6ec93d15b02a",
|
||||||
|
"ScheduleableUserID": "e6ff9bc6-a550-4242-8c41-857f740e2841",
|
||||||
|
"ScheduleableUserGroupID": "871e77b2-979a-4f26-930b-46f7c05fc19f"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
var V7Id = new Guid(j["ID"].Value<string>());
|
||||||
|
var RavenTagGroupId = importMap.Where(m => m.V7ObjectId == V7Id).First().NewObjectAyaTypeId.ObjectId;
|
||||||
|
|
||||||
|
foreach (JToken t in j["ScheduleableUsers"])
|
||||||
|
{
|
||||||
|
var techId = new Guid(t["ScheduleableUserID"].Value<String>());
|
||||||
|
var RavenUserId = importMap.Where(m => m.V7ObjectId == techId).First().NewObjectAyaTypeId.ObjectId;
|
||||||
|
var Creator = importMap.Where(m => m.V7ObjectId == new Guid(t["Creator"].Value<string>())).First().NewObjectAyaTypeId.ObjectId;
|
||||||
|
|
||||||
|
TagGroupMap tm = new TagGroupMap();
|
||||||
|
tm.TagGroupToObjectId = RavenUserId;
|
||||||
|
tm.TagGroupToObjectType=AyaType.User;
|
||||||
|
tm.TagGroupId = RavenTagGroupId;
|
||||||
|
tm.OwnerId = Creator;
|
||||||
|
ct.TagGroupMap.Add(tm);
|
||||||
|
}
|
||||||
|
ct.SaveChanges();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//this is the equivalent of returning void for a Task signature with nothing to return
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
}//eoc
|
||||||
|
|
||||||
|
//
|
||||||
|
}//eons
|
||||||
|
|
||||||
177
server/AyaNova/biz/TagGroupMapBiz.cs
Normal file
177
server/AyaNova/biz/TagGroupMapBiz.cs
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.JsonPatch;
|
||||||
|
using EnumsNET;
|
||||||
|
using AyaNova.Util;
|
||||||
|
using AyaNova.Api.ControllerHelpers;
|
||||||
|
using AyaNova.Biz;
|
||||||
|
using AyaNova.Models;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
|
||||||
|
namespace AyaNova.Biz
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
internal class TagGroupMapBiz : BizObject
|
||||||
|
{
|
||||||
|
private readonly AyContext ct;
|
||||||
|
public readonly long userId;
|
||||||
|
private readonly AuthorizationRoles userRoles;
|
||||||
|
|
||||||
|
|
||||||
|
internal TagGroupMapBiz(AyContext dbcontext, long currentUserId, AuthorizationRoles UserRoles)
|
||||||
|
{
|
||||||
|
ct = dbcontext;
|
||||||
|
userId = currentUserId;
|
||||||
|
userRoles = UserRoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//CREATE
|
||||||
|
internal async Task<TagGroupMap> CreateAsync(TagGroupMapInfo inObj)
|
||||||
|
{
|
||||||
|
|
||||||
|
Validate(inObj, true);
|
||||||
|
if (HasErrors)
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//do stuff with TagGroupMap
|
||||||
|
TagGroupMap outObj = new TagGroupMap()
|
||||||
|
{
|
||||||
|
TagId = inObj.TagId,
|
||||||
|
TagToObjectId = inObj.TagToObjectId,
|
||||||
|
TagToObjectType = inObj.TagToObjectType,
|
||||||
|
OwnerId = userId
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
await ct.TagGroupMap.AddAsync(outObj);
|
||||||
|
return outObj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// GET
|
||||||
|
|
||||||
|
//Get one
|
||||||
|
internal async Task<TagGroupMap> GetAsync(long fetchId)
|
||||||
|
{
|
||||||
|
//This is simple so nothing more here, but often will be copying to a different output object or some other ops
|
||||||
|
return await ct.TagGroupMap.SingleOrDefaultAsync(m => m.Id == fetchId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal async Task<List<NameIdItem>> GetTagsOnObjectListAsync(AyaTypeId tid)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
|
||||||
|
NOTES: This will be a bit of a "hot" path as every fetch of any main object will involve this
|
||||||
|
for now, just make it work and later can improve performance
|
||||||
|
|
||||||
|
Also is sort going to be adequate, it's supposed to be based on invariant culture
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
List<NameIdItem> l = new List<NameIdItem>();
|
||||||
|
|
||||||
|
//Get the list of tags on the object
|
||||||
|
var TagGroupMapsOnObject = await ct.TagGroupMap
|
||||||
|
.Where(m => m.TagToObjectId == tid.ObjectId && m.TagToObjectType == tid.ObjectType)
|
||||||
|
.Select(m => m.TagId)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
foreach (long tagId in TagGroupMapsOnObject)
|
||||||
|
{
|
||||||
|
var tagFromDb = await ct.Tag.SingleOrDefaultAsync(m => m.Id == tagId);
|
||||||
|
if (tagFromDb != null)
|
||||||
|
{
|
||||||
|
l.Add(new NameIdItem() { Id = tagFromDb.Id, Name = tagFromDb.Name });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Return the list sorted alphabetically
|
||||||
|
//Note if this is commonly required then maybe make a helper / extension for it
|
||||||
|
return (l.OrderBy(o => o.Name).ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//DELETE
|
||||||
|
//
|
||||||
|
|
||||||
|
internal bool Delete(TagGroupMap dbObj)
|
||||||
|
{
|
||||||
|
//Determine if the object can be deleted, do the deletion tentatively
|
||||||
|
|
||||||
|
ValidateCanDelete(dbObj);
|
||||||
|
if (HasErrors)
|
||||||
|
return false;
|
||||||
|
ct.TagGroupMap.Remove(dbObj);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//DELETE ALL TagGroupMapS FOR OBJECT
|
||||||
|
//
|
||||||
|
|
||||||
|
static internal bool DeleteAllForObject(AyaTypeId parentObj, AyContext ct)
|
||||||
|
{
|
||||||
|
//Be careful in future, if you put ToString at the end of each object in the string interpolation
|
||||||
|
//npgsql driver will assume it's a string and put quotes around it triggering an error that a string can't be compared to an int
|
||||||
|
ct.Database.ExecuteSqlCommand($"delete from aTagGroupMap where tagtoobjectid={parentObj.ObjectId} and tagtoobjecttype={parentObj.ObjectTypeAsInt}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//VALIDATION
|
||||||
|
//
|
||||||
|
|
||||||
|
//Can save or update?
|
||||||
|
private void Validate(TagGroupMapInfo inObj, bool isNew)
|
||||||
|
{
|
||||||
|
//run validation and biz rules
|
||||||
|
|
||||||
|
// //Name required
|
||||||
|
// if (string.IsNullOrWhiteSpace(inObj))
|
||||||
|
// AddError(ValidationErrorType.RequiredPropertyEmpty, "Name");
|
||||||
|
|
||||||
|
// //Name must be less than 255 characters
|
||||||
|
// if (inObj.Length > 255)
|
||||||
|
// AddError(ValidationErrorType.LengthExceeded, "Name", "255 char max");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Can delete?
|
||||||
|
private void ValidateCanDelete(TagGroupMap inObj)
|
||||||
|
{
|
||||||
|
//whatever needs to be check to delete this object
|
||||||
|
|
||||||
|
//See if any TagGroupMaps exist with this tag in which case it's not deleteable
|
||||||
|
// if (ct.TagGroupMap.Any(e => e.TagGroupMapId == inObj.Id))
|
||||||
|
// {
|
||||||
|
// AddError(ValidationErrorType.ReferentialIntegrity, "object", "Can't be deleted while has relations");
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}//eoc
|
||||||
|
|
||||||
|
|
||||||
|
}//eons
|
||||||
|
|
||||||
@@ -16,6 +16,8 @@ namespace AyaNova.Models
|
|||||||
public virtual DbSet<FileAttachment> FileAttachment { get; set; }
|
public virtual DbSet<FileAttachment> FileAttachment { get; set; }
|
||||||
public virtual DbSet<Tag> Tag { get; set; }
|
public virtual DbSet<Tag> Tag { get; set; }
|
||||||
public virtual DbSet<TagMap> TagMap { get; set; }
|
public virtual DbSet<TagMap> TagMap { get; set; }
|
||||||
|
public virtual DbSet<TagGroup> TagGroup { get; set; }
|
||||||
|
public virtual DbSet<TagGroupMap> TagGroupMap { get; set; }
|
||||||
public virtual DbSet<OpsJob> OpsJob { get; set; }
|
public virtual DbSet<OpsJob> OpsJob { get; set; }
|
||||||
public virtual DbSet<OpsJobLog> OpsJobLog { get; set; }
|
public virtual DbSet<OpsJobLog> OpsJobLog { get; set; }
|
||||||
public virtual DbSet<Locale> Locale { get; set; }
|
public virtual DbSet<Locale> Locale { get; set; }
|
||||||
|
|||||||
21
server/AyaNova/models/TagGroup.cs
Normal file
21
server/AyaNova/models/TagGroup.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using AyaNova.Biz;
|
||||||
|
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace AyaNova.Models
|
||||||
|
{
|
||||||
|
|
||||||
|
public partial class TagGroup
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
public uint ConcurrencyToken { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public long OwnerId { get; set; }
|
||||||
|
[Required, MaxLength(255)]
|
||||||
|
public string Name { get; set; }//max 255 characters ascii set
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
23
server/AyaNova/models/TagGroupMap.cs
Normal file
23
server/AyaNova/models/TagGroupMap.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using AyaNova.Biz;
|
||||||
|
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace AyaNova.Models
|
||||||
|
{
|
||||||
|
|
||||||
|
public partial class TagGroupMap
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
public uint ConcurrencyToken { get; set; }
|
||||||
|
[Required]
|
||||||
|
public long OwnerId { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public long TagId { get; set; }
|
||||||
|
[Required]
|
||||||
|
public long TagGroupId { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -144,7 +144,7 @@ namespace AyaNova.Util
|
|||||||
"dlkey text, dlkeyexpire timestamp, usertype integer not null, employeenumber varchar(255), notes text, clientid bigint, headofficeid bigint, subvendorid bigint)");
|
"dlkey text, dlkeyexpire timestamp, usertype integer not null, employeenumber varchar(255), notes text, clientid bigint, headofficeid bigint, subvendorid bigint)");
|
||||||
|
|
||||||
//Add user options table
|
//Add user options table
|
||||||
exec("CREATE TABLE auseroptions (id BIGSERIAL PRIMARY KEY, ownerid bigint not null, "+
|
exec("CREATE TABLE auseroptions (id BIGSERIAL PRIMARY KEY, ownerid bigint not null, " +
|
||||||
"userid bigint not null, timezoneoffset decimal(19,5) not null default 0, emailaddress text, uicolor int not null default 0)");
|
"userid bigint not null, timezoneoffset decimal(19,5) not null default 0, emailaddress text, uicolor int not null default 0)");
|
||||||
|
|
||||||
|
|
||||||
@@ -211,6 +211,10 @@ namespace AyaNova.Util
|
|||||||
exec("CREATE TABLE atagmap (id BIGSERIAL PRIMARY KEY, ownerid bigint not null," +
|
exec("CREATE TABLE atagmap (id BIGSERIAL PRIMARY KEY, ownerid bigint not null," +
|
||||||
"tagid bigint not null REFERENCES atag (id), tagtoobjectid bigint not null, tagtoobjecttype integer not null)");
|
"tagid bigint not null REFERENCES atag (id), tagtoobjectid bigint not null, tagtoobjecttype integer not null)");
|
||||||
|
|
||||||
|
//Taggroup
|
||||||
|
exec("CREATE TABLE ataggroup (id BIGSERIAL PRIMARY KEY, ownerid bigint not null, name varchar(255) not null)");
|
||||||
|
exec("CREATE TABLE ataggroupmap (id BIGSERIAL PRIMARY KEY, ownerid bigint not null, tagid bigint not null REFERENCES atag (id), taggroupid bigint not null)");
|
||||||
|
|
||||||
setSchemaLevel(++currentSchema);
|
setSchemaLevel(++currentSchema);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user