This commit is contained in:
@@ -13,7 +13,7 @@ namespace AyaNova.Api.Controllers
|
|||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[ApiVersion("8.0")]
|
[ApiVersion("8.0")]
|
||||||
[Route("api/v{version:apiVersion}/global-biz-setting")]
|
[Route("api/v{version:apiVersion}/global-ops-setting")]
|
||||||
[Produces("application/json")]
|
[Produces("application/json")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class GlobalOpsSettingsController : ControllerBase
|
public class GlobalOpsSettingsController : ControllerBase
|
||||||
@@ -40,7 +40,7 @@ namespace AyaNova.Api.Controllers
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get GlobalOpsSettings
|
/// Get GlobalOpsSettings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Global settings object</returns>
|
/// <returns>Global ops settings object</returns>
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<IActionResult> GetGlobalOpsSettings()
|
public async Task<IActionResult> GetGlobalOpsSettings()
|
||||||
{
|
{
|
||||||
@@ -74,16 +74,11 @@ namespace AyaNova.Api.Controllers
|
|||||||
{
|
{
|
||||||
if (serverState.IsClosed)
|
if (serverState.IsClosed)
|
||||||
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
return BadRequest(new ApiErrorResponse(ModelState));
|
return BadRequest(new ApiErrorResponse(ModelState));
|
||||||
|
|
||||||
//Instantiate the business object handler
|
|
||||||
GlobalOpsSettingsBiz biz = GlobalOpsSettingsBiz.GetBiz(ct, HttpContext);
|
GlobalOpsSettingsBiz biz = GlobalOpsSettingsBiz.GetBiz(ct, HttpContext);
|
||||||
|
if (!Authorized.HasModifyRole(HttpContext.Items, biz.BizType))
|
||||||
if (!Authorized.HasModifyRole(HttpContext.Items, biz.BizType))
|
|
||||||
return StatusCode(403, new ApiNotAuthorizedResponse());
|
return StatusCode(403, new ApiNotAuthorizedResponse());
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!await biz.ReplaceAsync(global))
|
if (!await biz.ReplaceAsync(global))
|
||||||
@@ -101,32 +96,24 @@ namespace AyaNova.Api.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Global settings object</returns>
|
/// <returns>Global settings object</returns>
|
||||||
[HttpGet("client")]
|
[HttpGet("client")]
|
||||||
public ActionResult GetClientGlobalOpsSettings()
|
public async Task<ActionResult> GetClientGlobalOpsSettings()
|
||||||
{
|
{
|
||||||
|
//NOTE: currently this looks like a dupe of get above and it is
|
||||||
|
//but it's kept here in case want to return a subset of the settings only to client users
|
||||||
|
//where some internal server only stuff might not be desired to send to user
|
||||||
|
|
||||||
if (serverState.IsClosed)
|
if (serverState.IsClosed)
|
||||||
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
||||||
|
GlobalOpsSettingsBiz biz = GlobalOpsSettingsBiz.GetBiz(ct, HttpContext);
|
||||||
//Instantiate the business object handler
|
//this route is available to Ops role user only
|
||||||
// GlobalOpsSettingsBiz biz = GlobalOpsSettingsBiz.GetBiz(ct, HttpContext);
|
if (!Authorized.HasReadFullRole(HttpContext.Items, biz.BizType))
|
||||||
|
return StatusCode(403, new ApiNotAuthorizedResponse());
|
||||||
//this route is available to any logged in user as it contains a subset of limited options relevant to any logged in user
|
|
||||||
// if (!Authorized.HasReadFullRole(HttpContext.Items, biz.BizType))
|
|
||||||
// return StatusCode(403, new ApiNotAuthorizedResponse());
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
return BadRequest(new ApiErrorResponse(ModelState));
|
return BadRequest(new ApiErrorResponse(ModelState));
|
||||||
|
var o = await biz.GetAsync();
|
||||||
// var o = await biz.GetAsync();
|
if (o == null)
|
||||||
// if (o == null)
|
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
||||||
// return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
return Ok(ApiOkResponse.Response(o));
|
||||||
|
|
||||||
//new object with only relevant items in it
|
|
||||||
var ret = new
|
|
||||||
{
|
|
||||||
SearchCaseSensitiveOnly = AyaNova.Util.ServerGlobalOpsSettings.SearchCaseSensitiveOnly
|
|
||||||
};
|
|
||||||
|
|
||||||
return Ok(ApiOkResponse.Response(ret));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}//eoc
|
}//eoc
|
||||||
|
|||||||
@@ -102,7 +102,8 @@ namespace AyaNova.Biz
|
|||||||
[CoreBizObject]
|
[CoreBizObject]
|
||||||
WorkOrderTemplate = 45,
|
WorkOrderTemplate = 45,
|
||||||
[CoreBizObject]
|
[CoreBizObject]
|
||||||
WorkOrderTemplateItem = 46
|
WorkOrderTemplateItem = 46,
|
||||||
|
GlobalOps=47
|
||||||
|
|
||||||
|
|
||||||
//NOTE: New objects added here need to also be added to the following classes:
|
//NOTE: New objects added here need to also be added to the following classes:
|
||||||
|
|||||||
@@ -339,6 +339,15 @@ namespace AyaNova.Biz
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//GLOBAL OPS SETTINGS
|
||||||
|
//
|
||||||
|
roles.Add(AyaType.GlobalOps, new BizRoleSet()
|
||||||
|
{
|
||||||
|
Change = AuthorizationRoles.OpsAdminFull,
|
||||||
|
ReadFullRecord = AuthorizationRoles.OpsAdminLimited
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//USER
|
//USER
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using AyaNova.Util;
|
using AyaNova.Util;
|
||||||
@@ -16,7 +17,7 @@ namespace AyaNova.Biz
|
|||||||
UserId = currentUserId;
|
UserId = currentUserId;
|
||||||
UserTranslationId = userTranslationId;
|
UserTranslationId = userTranslationId;
|
||||||
CurrentUserRoles = UserRoles;
|
CurrentUserRoles = UserRoles;
|
||||||
BizType = AyaType.Global;
|
BizType = AyaType.GlobalOps;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static GlobalOpsSettingsBiz GetBiz(AyContext ct, Microsoft.AspNetCore.Http.HttpContext httpContext = null)
|
internal static GlobalOpsSettingsBiz GetBiz(AyContext ct, Microsoft.AspNetCore.Http.HttpContext httpContext = null)
|
||||||
@@ -39,16 +40,14 @@ namespace AyaNova.Biz
|
|||||||
//first try to fetch from db
|
//first try to fetch from db
|
||||||
var ret = await ct.GlobalOpsSettings.SingleOrDefaultAsync(m => m.Id == 1);
|
var ret = await ct.GlobalOpsSettings.SingleOrDefaultAsync(m => m.Id == 1);
|
||||||
if (logTheGetEvent && ret != null)
|
if (logTheGetEvent && ret != null)
|
||||||
{
|
|
||||||
//Log
|
|
||||||
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, 1, BizType, AyaEvent.Retrieved), ct);
|
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, 1, BizType, AyaEvent.Retrieved), ct);
|
||||||
}
|
|
||||||
|
|
||||||
//not in db then get the default
|
//not in db then get the default
|
||||||
if (ret == null)
|
if (ret == null)
|
||||||
{
|
|
||||||
throw new System.Exception("GlobalOpsSettingsBiz::GetAsync -> Global OPS settings object not found in database!!");
|
throw new System.Exception("GlobalOpsSettingsBiz::GetAsync -> Global OPS settings object not found in database!!");
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,23 +58,26 @@ namespace AyaNova.Biz
|
|||||||
//
|
//
|
||||||
|
|
||||||
//put
|
//put
|
||||||
internal async Task<bool> ReplaceAsync(GlobalOpsSettings inObj)
|
internal async Task<bool> ReplaceAsync(GlobalOpsSettings putObject)
|
||||||
{
|
{
|
||||||
var dbObj = await ct.GlobalOpsSettings.FirstOrDefaultAsync(m => m.Id == 1);
|
var dbObject = await ct.GlobalOpsSettings.FirstOrDefaultAsync(m => m.Id == 1);
|
||||||
if (dbObj == null)
|
if (dbObject == null)
|
||||||
throw new System.Exception("GlobalOpsSettingsBiz::ReplaceAsync -> Global settings object not found in database!!");
|
throw new System.Exception("GlobalOpsSettingsBiz::ReplaceAsync -> Global settings object not found in database!!");
|
||||||
CopyObject.Copy(inObj, dbObj, "Id");
|
|
||||||
|
|
||||||
ct.Entry(dbObj).OriginalValues["Concurrency"] = inObj.Concurrency;
|
//If backup time has changed then reset last backup as well as it might block from taking effect
|
||||||
|
if (putObject.BackupTime.Hour != dbObject.BackupTime.Hour && putObject.BackupTime.Minute != dbObject.BackupTime.Minute)
|
||||||
Validate(dbObj);
|
{
|
||||||
|
putObject.LastBackup = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
CopyObject.Copy(putObject, dbObject, "Id");
|
||||||
|
ct.Entry(dbObject).OriginalValues["Concurrency"] = putObject.Concurrency;
|
||||||
|
Validate(dbObject);
|
||||||
if (HasErrors)
|
if (HasErrors)
|
||||||
return false;
|
return false;
|
||||||
await ct.SaveChangesAsync();
|
await ct.SaveChangesAsync();
|
||||||
//Log modification and save context
|
|
||||||
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, 1, BizType, AyaEvent.Modified), ct);
|
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, 1, BizType, AyaEvent.Modified), ct);
|
||||||
//Update the static copy for the server
|
//Update the static copy for the server
|
||||||
ServerGlobalOpsSettings.Initialize(dbObj);
|
ServerGlobalOpsSettings.Initialize(dbObject);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.Threading.Tasks;
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using AyaNova.Models;
|
using AyaNova.Models;
|
||||||
|
using AyaNova.Util;
|
||||||
|
|
||||||
|
|
||||||
namespace AyaNova.Biz
|
namespace AyaNova.Biz
|
||||||
@@ -17,44 +18,43 @@ namespace AyaNova.Biz
|
|||||||
internal static class CoreJobBackup
|
internal static class CoreJobBackup
|
||||||
{
|
{
|
||||||
private static ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger("CoreJobBackup");
|
private static ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger("CoreJobBackup");
|
||||||
private static DateTime lastSweep = DateTime.MinValue;
|
private static bool BackupIsRunning = false;
|
||||||
private static TimeSpan SWEEP_EVERY_INTERVAL = new TimeSpan(0, 30, 0);
|
|
||||||
private static TimeSpan SUCCEEDED_JOBS_DELETE_AFTER_THIS_TIMESPAN = new TimeSpan(24, 0, 0);//24 hours
|
|
||||||
private static TimeSpan FAILED_JOBS_DELETE_AFTER_THIS_TIMESPAN = new TimeSpan(14, 0, 0, 0);//14 days (gives people time to notice and look into it)
|
|
||||||
private static TimeSpan RUNNING_JOBS_BECOME_FAILED_AFTER_THIS_TIMESPAN = new TimeSpan(24, 0, 0);//24 hours (time running jobs are allowed to sit in "running" state before considered failed)
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
public static async Task DoWorkAsync(AyContext ct)
|
public static async Task DoWorkAsync(AyContext ct)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (BackupIsRunning) return;
|
||||||
|
|
||||||
//This will get triggered roughly every minute, but we don't want to sweep that frequently
|
//get NOW in utc
|
||||||
if (DateTime.UtcNow - lastSweep < SWEEP_EVERY_INTERVAL)
|
DateTime utcNow = DateTime.UtcNow;
|
||||||
return;
|
|
||||||
|
|
||||||
|
//what time should we backup today?
|
||||||
|
DateTime todayBackupTime = new DateTime(utcNow.Year, utcNow.Month, utcNow.Day, ServerGlobalOpsSettings.BackupTime.Hour, ServerGlobalOpsSettings.BackupTime.Minute, 0, DateTimeKind.Utc);//first start with NOW
|
||||||
|
|
||||||
|
//Are we there yet?
|
||||||
|
if (utcNow < todayBackupTime) return;//nope
|
||||||
|
|
||||||
|
//Yes, we've passed into the backup window time, but that's also true if we just ran the backup as well so
|
||||||
|
//need to check for that as well...
|
||||||
|
|
||||||
|
//Has last backup run more than 24 hours ago?
|
||||||
|
if (ServerGlobalOpsSettings.LastBackup > utcNow.AddHours(-24))
|
||||||
|
return;//nope, so we have already run today's backup
|
||||||
|
|
||||||
|
//Ok, we're into backup time and it's been more than 24 hours since it last ran so let's do this...
|
||||||
|
BackupIsRunning = true;
|
||||||
log.LogTrace("Backup starting");
|
log.LogTrace("Backup starting");
|
||||||
|
|
||||||
//lock the server
|
//*************
|
||||||
//serverState.SetSystemLock(msg);
|
|
||||||
//SWEEP SUCCESSFUL JOBS
|
|
||||||
//calculate cutoff to delete
|
|
||||||
DateTime dtDeleteCutoff = DateTime.UtcNow - SUCCEEDED_JOBS_DELETE_AFTER_THIS_TIMESPAN;
|
|
||||||
await sweepAsync(ct, dtDeleteCutoff, JobStatus.Completed);
|
|
||||||
|
|
||||||
//SWEEP FAILED JOBS
|
//BACKUP TORA TORA TORA!
|
||||||
//calculate cutoff to delete
|
//***************
|
||||||
dtDeleteCutoff = DateTime.UtcNow - FAILED_JOBS_DELETE_AFTER_THIS_TIMESPAN;
|
|
||||||
await sweepAsync(ct, dtDeleteCutoff, JobStatus.Failed);
|
|
||||||
|
|
||||||
|
//Update last backup
|
||||||
//KILL STUCK JOBS
|
BackupIsRunning = false;
|
||||||
//calculate cutoff to delete
|
log.LogTrace("Backup completed");
|
||||||
DateTime dtRunningDeadline = DateTime.UtcNow - RUNNING_JOBS_BECOME_FAILED_AFTER_THIS_TIMESPAN;
|
|
||||||
await killStuckJobsAsync(ct, dtRunningDeadline);
|
|
||||||
|
|
||||||
lastSweep = DateTime.UtcNow;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -445,6 +445,7 @@
|
|||||||
"ContractRate": "Vertragssatz",
|
"ContractRate": "Vertragssatz",
|
||||||
"DispatchZone": "Zuweisungszone",
|
"DispatchZone": "Zuweisungszone",
|
||||||
"Global": "Global",
|
"Global": "Global",
|
||||||
|
"GlobalOps": "Global ops",
|
||||||
"GlobalWikiPage": "Global Wiki page",
|
"GlobalWikiPage": "Global Wiki page",
|
||||||
"GridFilter": "GridFilter",
|
"GridFilter": "GridFilter",
|
||||||
"HeadOffice": "Hauptsitz",
|
"HeadOffice": "Hauptsitz",
|
||||||
|
|||||||
@@ -445,6 +445,7 @@
|
|||||||
"ContractRate": "Contract rate",
|
"ContractRate": "Contract rate",
|
||||||
"DispatchZone": "Dispatch Zone",
|
"DispatchZone": "Dispatch Zone",
|
||||||
"Global": "Global",
|
"Global": "Global",
|
||||||
|
"GlobalOps": "Global ops",
|
||||||
"GlobalWikiPage": "Global Wiki page",
|
"GlobalWikiPage": "Global Wiki page",
|
||||||
"GridFilter": "GridFilter",
|
"GridFilter": "GridFilter",
|
||||||
"HeadOffice": "Head Office",
|
"HeadOffice": "Head Office",
|
||||||
|
|||||||
@@ -445,6 +445,7 @@
|
|||||||
"ContractRate": "Tarifa de contrato",
|
"ContractRate": "Tarifa de contrato",
|
||||||
"DispatchZone": "Zona de reparto",
|
"DispatchZone": "Zona de reparto",
|
||||||
"Global": "Global",
|
"Global": "Global",
|
||||||
|
"GlobalOps": "Global ops",
|
||||||
"GlobalWikiPage": "Global Wiki page",
|
"GlobalWikiPage": "Global Wiki page",
|
||||||
"GridFilter": "GridFilter",
|
"GridFilter": "GridFilter",
|
||||||
"HeadOffice": "Sede",
|
"HeadOffice": "Sede",
|
||||||
|
|||||||
@@ -445,6 +445,7 @@
|
|||||||
"ContractRate": "Tarif de contrat",
|
"ContractRate": "Tarif de contrat",
|
||||||
"DispatchZone": "Zone d'expédition",
|
"DispatchZone": "Zone d'expédition",
|
||||||
"Global": "Général",
|
"Global": "Général",
|
||||||
|
"GlobalOps": "Global ops",
|
||||||
"GlobalWikiPage": "Global Wiki page",
|
"GlobalWikiPage": "Global Wiki page",
|
||||||
"GridFilter": "GridFilter",
|
"GridFilter": "GridFilter",
|
||||||
"HeadOffice": "Siège social",
|
"HeadOffice": "Siège social",
|
||||||
|
|||||||
Reference in New Issue
Block a user