Files
sockeye/server/biz/GlobalBizSettingsBiz.cs
2022-12-28 17:53:36 +00:00

404 lines
19 KiB
C#

using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Sockeye.Util;
using Sockeye.Api.ControllerHelpers;
using Sockeye.Models;
using System.Collections.Generic;
using System;
using System.Text;
using System.IO;
using System.Net.Http;
using System.Linq;
using Microsoft.Extensions.Logging;
//JSON KEY
using Org.BouncyCastle.Security;
using Org.BouncyCastle.OpenSsl;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Net.Http.Headers;
namespace Sockeye.Biz
{
internal class GlobalBizSettingsBiz : BizObject
{
internal GlobalBizSettingsBiz(AyContext dbcontext, long currentUserId, long userTranslationId, AuthorizationRoles UserRoles)
{
ct = dbcontext;
UserId = currentUserId;
UserTranslationId = userTranslationId;
CurrentUserRoles = UserRoles;
BizType = SockType.Global;
}
internal static GlobalBizSettingsBiz GetBiz(AyContext ct, Microsoft.AspNetCore.Http.HttpContext httpContext = null)
{
if (httpContext != null)
return new GlobalBizSettingsBiz(ct, UserIdFromContext.Id(httpContext.Items), UserTranslationIdFromContext.Id(httpContext.Items), UserRolesFromContext.Roles(httpContext.Items));
else
return new GlobalBizSettingsBiz(ct, 1, ServerBootConfig.SOCKEYE_DEFAULT_TRANSLATION_ID, AuthorizationRoles.BizAdmin);
}
////////////////////////////////////////////////////////////////////////////////////////////////
/// GET
//Get one
internal async Task<GlobalBizSettings> GetAsync(bool logTheGetEvent = true)
{
//first try to fetch from db
var ret = await ct.GlobalBizSettings.AsNoTracking().SingleOrDefaultAsync(m => m.Id == 1);
if (logTheGetEvent && ret != null)
{
//Log
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, 1, BizType, SockEvent.Retrieved), ct);
}
//not in db then get the default
if (ret == null)
{
throw new System.Exception("GlobalBizSettingsBiz::GetAsync -> Global settings object not found in database!!");
}
return ret;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//UPDATE
//
internal async Task<GlobalBizSettings> PutAsync(GlobalBizSettings putObject)
{
var dbObject = await GetAsync(false);
if (dbObject == null)
throw new System.Exception("GlobalBizSettingsBiz::PutAsync -> Global settings object not found in database. Contact support immediately!");
if (dbObject.Concurrency != putObject.Concurrency)
{
AddError(ApiErrorCode.CONCURRENCY_CONFLICT);
return null;
}
Validate(putObject, dbObject);
if (HasErrors) return null;
List<string> originalTags = dbObject.AllTags();
List<string> newTags = putObject.AllTags();
ct.Replace(dbObject, putObject);
try
{
await ct.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
AddError(ApiErrorCode.CONCURRENCY_CONFLICT);
return null;
}
//Update cache
ServerGlobalBizSettings.Initialize(putObject, null);
//Log modification and save context
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, 1, BizType, SockEvent.Modified), ct);
await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, newTags, originalTags);
return putObject;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//VALIDATION
//
//Can save or update?
private void Validate(GlobalBizSettings proposedObj, GlobalBizSettings currentObj)
{
//currently nothing to validate
}
//IMPORT FROM ROCKFISH
public async Task ImportRockfish(AyContext ct, ILogger log)
{
//Authenticate to rockfish
//string sUrl = $"{LICENSE_SERVER_URL_ROCKFISH}rvr";
string URL_ROCKFISH = "https://rockfish.ayanova.com/";
try
{
//var content = new StringContent("login=john&password=b43698c255365ee739c05ba0d42855e96c2365c76bb2f9b9eb149cec7b52174c");
var content = new StringContent(JsonConvert.SerializeObject(new
{
login = "john",
password = "b43698c255365ee739c05ba0d42855e96c2365c76bb2f9b9eb149cec7b52174c"
}), Encoding.UTF8, "application/json");
var client = ServiceProviderProvider.HttpClientFactory.CreateClient();
//AUTHENTICATE
var res = await client.PostAsync($"{URL_ROCKFISH}authenticate?login=john&password=b43698c255365ee739c05ba0d42855e96c2365c76bb2f9b9eb149cec7b52174c", content);
var responseText = await res.Content.ReadAsStringAsync();
if (res.IsSuccessStatusCode)
{
log.LogInformation(responseText);
}
else log.LogError($"E1020 - Error authenticating to rockfish: {res.ReasonPhrase}");
var responseJson = JObject.Parse(responseText);
var authToken = responseJson["token"].Value<string>();
var dlKey = responseJson["dlkey"].Value<string>();
var userId = responseJson["id"].Value<long>();
//client.DefaultRequestHeaders.Add("Bearer", authToken);
var contentType = new MediaTypeWithQualityHeaderValue("application/json");
client.DefaultRequestHeaders.Accept.Add(contentType);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
res = await client.GetAsync($"{URL_ROCKFISH}api/customer/list");
responseText = await res.Content.ReadAsStringAsync();
var jaCustomerList = JArray.Parse(responseText);
foreach (JObject jCustomerListItem in jaCustomerList)
{
res = await client.GetAsync($"{URL_ROCKFISH}api/customer/{jCustomerListItem["id"].Value<long>()}");
var jCustomer = JObject.Parse(await res.Content.ReadAsStringAsync());
//SITES
res = await client.GetAsync($"{URL_ROCKFISH}api/customer/{jCustomerListItem["id"].Value<long>()}/sites");
var jaSiteList = JArray.Parse(await res.Content.ReadAsStringAsync());
bool multiSite = jaSiteList.Count() > 1;
foreach (JObject jSite in jaSiteList)
{
var CustomerName = jCustomer["name"].Value<string>();
if (multiSite)
CustomerName += " - " + jSite["name"].Value<string>();
long CurrentCustomerId = 0;
//Create customer if we don't have one already
if (await ct.Customer.AnyAsync(z => z.Name == CustomerName))
continue;//already have this one so no need to process it again
{
//CREATE CUSTOMER
Customer c = new Customer();
c.Name = CustomerName;
c.Country = jSite["country"].Value<string>();
c.Region = jSite["stateProvince"].Value<string>();
c.DoNotContact = jCustomer["doNotContact"].Value<bool>();
c.Notes = jCustomer["notes"].Value<string>();
c.DbId = jSite["dbId"].Value<string>();
if (c.DbId == "v7_no_dbid")
{
c.DbId = null;
c.Tags.Add("v7");
}
else
c.Tags.Add("raven");
if (jSite["hosted"].Value<bool>() == true)
c.Tags.Add("hosted");
var adminEmail = jCustomer["adminEmail"].Value<string>();
if (!string.IsNullOrWhiteSpace(adminEmail))
c.Notes += "\nAdmin Email: " + adminEmail;
c.EmailAddress = jCustomer["adminEmail"].Value<string>();
CustomerBiz biz = CustomerBiz.GetBiz(ct);
var NewObject = await biz.CreateAsync(c);
CurrentCustomerId = NewObject.Id;
}//customer creation
//SITE PURCHASES
res = await client.GetAsync($"{URL_ROCKFISH}api/site/{jSite["id"].Value<long>()}/purchases");
var jaPurchaseList = JArray.Parse(await res.Content.ReadAsStringAsync());
foreach (JObject jPurchase in jaPurchaseList)
{
//create product if not exist then import
//Get product id if exists
var ProductName = jPurchase["name"].Value<string>();
ProductName = ProductName.Replace("- Renewal", "").Replace(" Renewal", "").Replace(" RENEWAL", "").Replace("CANCELLED ", "").Replace("CANCELED ", "");
var p = await ct.Product.AsNoTracking().FirstOrDefaultAsync(z => z.VendorCode == jPurchase["productCode"].Value<string>());
if (p == null)
{
//Create it here
p = new Product();
p.Name = ProductName;
p.Active = true;//not entirely true but we can always deactivate there aren't many products
p.VendorId = 1;
p.OurCode = p.VendorCode = jPurchase["productCode"].Value<string>();
if (p.VendorCode == "301028468")//subscription yearly
{
p.LicenseInterval = new TimeSpan(365, 0, 0, 0); //actual length, in license is where I pad to cover them
}
if (p.VendorCode == "301028467")//subscription monthly
{
p.LicenseInterval = new TimeSpan(31, 0, 0, 0);//there is no concept beyond days for timespan so a month is 31 days max
p.MaintInterval = new TimeSpan(31, 0, 0, 0);//the only product less than one year of maintenance save the ones with no maintenance which can be edited manually later as there are so few of them
}
else
p.MaintInterval = new TimeSpan(365, 0, 0, 0);
ProductBiz biz = ProductBiz.GetBiz(ct);
p = await biz.CreateAsync(p);
}
//Now we can add the sale that we have the product
if (!await ct.Purchase.AnyAsync(z => z.SalesOrderNumber == jPurchase["salesOrderNumber"].Value<string>()))
{
var s = new Purchase();
s.VendorId = 1;
s.ProductId = p.Id;
s.CustomerId = CurrentCustomerId;
s.CancelDate = DateUtil.EpochToDateNullIsNull(jPurchase["cancelDate"].Value<long?>());
s.CouponCode = jPurchase["couponCode"].Value<string>();
s.ExpireDate = DateUtil.EpochToDateNullIsNull(jPurchase["expireDate"].Value<long?>());
s.Name = p.Name;
s.ProcessedDate = s.PurchaseDate = DateUtil.EpochToDateNullIsMin(jPurchase["purchaseDate"].Value<long?>());
s.Quantity = jPurchase["quantity"].Value<int>();
s.RenewNoticeSent = jPurchase["renewNoticeSent"].Value<bool>();
s.SalesOrderNumber = jPurchase["salesOrderNumber"].Value<string>();
s.VendorData = jPurchase["notes"].Value<string>();
PurchaseBiz biz = PurchaseBiz.GetBiz(ct);
await biz.CreateAsync(s);
}
}
}//site loop
}//end of all customers iteration
#region CASES
//case projects to be tags
List<NameIdItem> CaseProjectList = new List<NameIdItem>();
{
res = await client.GetAsync($"{URL_ROCKFISH}api/rfcaseproject");
responseText = await res.Content.ReadAsStringAsync();
var jaRFCaseProjectList = JArray.Parse(responseText);
foreach (JObject jRFCaseProject in jaRFCaseProjectList)
{
CaseProjectList.Add(new NameIdItem() { Name = jRFCaseProject["name"].Value<string>(), Id = jRFCaseProject["id"].Value<long>() });
}
}
{
res = await client.GetAsync($"{URL_ROCKFISH}api/rfcase/list");
responseText = await res.Content.ReadAsStringAsync();
var jaRFCaseList = JArray.Parse(responseText);
//some cases are missing the start date so substitute a close other case date (not critical but sb at least in the ballpark for list viewing purposes)
DateTime dtTempCreated = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc);
foreach (JObject jRFCase in jaRFCaseList)
{
var g = new GZCase();
g.CaseId = jRFCase["id"].Value<long>();
g.Closed = DateUtil.EpochToDateNullIsNull(jRFCase["dtClosed"].Value<long?>());
//fuckery to try to insert a at least semi close date when created date is missing
DateTime? dtTemp = DateUtil.EpochToDateNullIsNull(jRFCase["dtCreated"].Value<long?>());
if (dtTemp == null)
{
dtTemp = dtTempCreated;
}
else
{
dtTempCreated = (DateTime)dtTemp;
}
g.Created = (DateTime)dtTemp;
g.Name = jRFCase["title"].Value<string>();
g.Notes = jRFCase["notes"].Value<string>();
var ver = jRFCase["releaseVersion"].Value<string>();
if (!string.IsNullOrWhiteSpace(ver))
g.Notes += $"\nRelease version:{ver}";
var releaseNotes = jRFCase["releaseNotes"].Value<string>();
if (!string.IsNullOrWhiteSpace(releaseNotes))
g.Notes += $"\nRelease notes:{releaseNotes}";
//Project name to tags
g.Tags.Add(CaseProjectList.FirstOrDefault(z => z.Id == jRFCase["rfCaseProjectId"].Value<long>()).Name.Replace("z_", "legacy-"));
//priority to tags
g.Tags.Add($"{jRFCase["priority"].Value<long>()}-priority");
GZCaseBiz biz = GZCaseBiz.GetBiz(ct);
await biz.CreateAsync(g);
/*
{
"id": 4057,
"title": "sockeye:forking-case:Fork AyaNova to new RockFish replacement called \"Sockeye\"",
"rfCaseProjectId": 44,
"priority": 1,
"notes": "Replace RockFish with a new server app forked from AyaNova 8 called \"Sockeye\".\nWas going to try to put rockfish code into Ayanova itself but that's not practical too many differences in biz objects but the bones are similar and if I keep it close can help drive parallel development.\n\nTODO:\nfork RAVEN to sockeye, change AyaNova db name stuff to sockeye so can boot and work and replace db at any time\nstrip out licensing code right away to make life easier for the rest\n\nDetermine what overlaps and needs to be kept and what should go, document it fully here step by step\nAyaNova's expected routes and the mycommerce route called with sales data need to be replicated exactly so there is no loss\nWhat objects need to be added and accomodating future cases\n\nduplicate raven to sockeye then get stripping and set up in a parallel route on devops for testing etc.\n=-=-=-\n\n- Import from rockfish via api calls so can do it anytime and won't be a problem of dupes or anything",
"dtCreated": null,
"dtClosed": null,
"releaseVersion": "",
"releaseNotes": ""
}
*/
//attachments example
// /api/rfcase/4360/attachments
//{"dlkey":"ZFkAUpo1L0Gi3Q9aO5szkA","attach":[{"id":259,"name":"desired weight calcs.txt"}]}
}
}
#endregion cases
}
catch (Exception ex)
{
var msg = "Error importing rockfish";
log.LogError(ex, msg);
}
log.LogInformation("FINISHED IMPORTING");
//in the correct order retrieve every object and if it's not already present in sockeye, import it
//this should be callable any time and it will just update so it can be test live in sync / parallel until ready to switch over
//await Task.CompletedTask;
}
/////////////////////////////////////////////////////////////////////
}//eoc
}//eons