This commit is contained in:
@@ -13,7 +13,7 @@ namespace AyaNova.Api.Controllers
|
||||
|
||||
[ApiController]
|
||||
[ApiVersion("8.0")]
|
||||
[Route("api/v{version:apiVersion}/global-biz-setting")]
|
||||
[Route("api/v{version:apiVersion}/global-ops-setting")]
|
||||
[Produces("application/json")]
|
||||
[Authorize]
|
||||
public class GlobalOpsSettingsController : ControllerBase
|
||||
@@ -40,7 +40,7 @@ namespace AyaNova.Api.Controllers
|
||||
/// <summary>
|
||||
/// Get GlobalOpsSettings
|
||||
/// </summary>
|
||||
/// <returns>Global settings object</returns>
|
||||
/// <returns>Global ops settings object</returns>
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetGlobalOpsSettings()
|
||||
{
|
||||
@@ -74,16 +74,11 @@ namespace AyaNova.Api.Controllers
|
||||
{
|
||||
if (serverState.IsClosed)
|
||||
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
return BadRequest(new ApiErrorResponse(ModelState));
|
||||
|
||||
//Instantiate the business object handler
|
||||
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());
|
||||
|
||||
try
|
||||
{
|
||||
if (!await biz.ReplaceAsync(global))
|
||||
@@ -101,32 +96,24 @@ namespace AyaNova.Api.Controllers
|
||||
/// </summary>
|
||||
/// <returns>Global settings object</returns>
|
||||
[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)
|
||||
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
||||
|
||||
//Instantiate the business object handler
|
||||
// GlobalOpsSettingsBiz biz = GlobalOpsSettingsBiz.GetBiz(ct, HttpContext);
|
||||
|
||||
//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());
|
||||
|
||||
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
||||
GlobalOpsSettingsBiz biz = GlobalOpsSettingsBiz.GetBiz(ct, HttpContext);
|
||||
//this route is available to Ops role user only
|
||||
if (!Authorized.HasReadFullRole(HttpContext.Items, biz.BizType))
|
||||
return StatusCode(403, new ApiNotAuthorizedResponse());
|
||||
if (!ModelState.IsValid)
|
||||
return BadRequest(new ApiErrorResponse(ModelState));
|
||||
|
||||
// var o = await biz.GetAsync();
|
||||
// if (o == null)
|
||||
// return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
||||
|
||||
//new object with only relevant items in it
|
||||
var ret = new
|
||||
{
|
||||
SearchCaseSensitiveOnly = AyaNova.Util.ServerGlobalOpsSettings.SearchCaseSensitiveOnly
|
||||
};
|
||||
|
||||
return Ok(ApiOkResponse.Response(ret));
|
||||
var o = await biz.GetAsync();
|
||||
if (o == null)
|
||||
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
||||
return Ok(ApiOkResponse.Response(o));
|
||||
}
|
||||
|
||||
}//eoc
|
||||
|
||||
@@ -102,7 +102,8 @@ namespace AyaNova.Biz
|
||||
[CoreBizObject]
|
||||
WorkOrderTemplate = 45,
|
||||
[CoreBizObject]
|
||||
WorkOrderTemplateItem = 46
|
||||
WorkOrderTemplateItem = 46,
|
||||
GlobalOps=47
|
||||
|
||||
|
||||
//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
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using AyaNova.Util;
|
||||
@@ -16,7 +17,7 @@ namespace AyaNova.Biz
|
||||
UserId = currentUserId;
|
||||
UserTranslationId = userTranslationId;
|
||||
CurrentUserRoles = UserRoles;
|
||||
BizType = AyaType.Global;
|
||||
BizType = AyaType.GlobalOps;
|
||||
}
|
||||
|
||||
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
|
||||
var ret = await ct.GlobalOpsSettings.SingleOrDefaultAsync(m => m.Id == 1);
|
||||
if (logTheGetEvent && ret != null)
|
||||
{
|
||||
//Log
|
||||
|
||||
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, 1, BizType, AyaEvent.Retrieved), ct);
|
||||
}
|
||||
|
||||
|
||||
//not in db then get the default
|
||||
if (ret == null)
|
||||
{
|
||||
throw new System.Exception("GlobalOpsSettingsBiz::GetAsync -> Global OPS settings object not found in database!!");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -59,23 +58,26 @@ namespace AyaNova.Biz
|
||||
//
|
||||
|
||||
//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);
|
||||
if (dbObj == null)
|
||||
var dbObject = await ct.GlobalOpsSettings.FirstOrDefaultAsync(m => m.Id == 1);
|
||||
if (dbObject == null)
|
||||
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;
|
||||
|
||||
Validate(dbObj);
|
||||
//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)
|
||||
{
|
||||
putObject.LastBackup = DateTime.MinValue;
|
||||
}
|
||||
CopyObject.Copy(putObject, dbObject, "Id");
|
||||
ct.Entry(dbObject).OriginalValues["Concurrency"] = putObject.Concurrency;
|
||||
Validate(dbObject);
|
||||
if (HasErrors)
|
||||
return false;
|
||||
await ct.SaveChangesAsync();
|
||||
//Log modification and save context
|
||||
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, 1, BizType, AyaEvent.Modified), ct);
|
||||
//Update the static copy for the server
|
||||
ServerGlobalOpsSettings.Initialize(dbObj);
|
||||
ServerGlobalOpsSettings.Initialize(dbObject);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using AyaNova.Models;
|
||||
using AyaNova.Util;
|
||||
|
||||
|
||||
namespace AyaNova.Biz
|
||||
@@ -17,44 +18,43 @@ namespace AyaNova.Biz
|
||||
internal static class CoreJobBackup
|
||||
{
|
||||
private static ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger("CoreJobBackup");
|
||||
private static DateTime lastSweep = DateTime.MinValue;
|
||||
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)
|
||||
|
||||
private static bool BackupIsRunning = false;
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
//
|
||||
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
|
||||
if (DateTime.UtcNow - lastSweep < SWEEP_EVERY_INTERVAL)
|
||||
return;
|
||||
//get NOW in utc
|
||||
DateTime utcNow = DateTime.UtcNow;
|
||||
|
||||
//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");
|
||||
|
||||
//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
|
||||
//calculate cutoff to delete
|
||||
dtDeleteCutoff = DateTime.UtcNow - FAILED_JOBS_DELETE_AFTER_THIS_TIMESPAN;
|
||||
await sweepAsync(ct, dtDeleteCutoff, JobStatus.Failed);
|
||||
//*************
|
||||
|
||||
//BACKUP TORA TORA TORA!
|
||||
//***************
|
||||
|
||||
//KILL STUCK JOBS
|
||||
//calculate cutoff to delete
|
||||
DateTime dtRunningDeadline = DateTime.UtcNow - RUNNING_JOBS_BECOME_FAILED_AFTER_THIS_TIMESPAN;
|
||||
await killStuckJobsAsync(ct, dtRunningDeadline);
|
||||
|
||||
lastSweep = DateTime.UtcNow;
|
||||
//Update last backup
|
||||
BackupIsRunning = false;
|
||||
log.LogTrace("Backup completed");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"ContractRate": "Vertragssatz",
|
||||
"DispatchZone": "Zuweisungszone",
|
||||
"Global": "Global",
|
||||
"GlobalOps": "Global ops",
|
||||
"GlobalWikiPage": "Global Wiki page",
|
||||
"GridFilter": "GridFilter",
|
||||
"HeadOffice": "Hauptsitz",
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"ContractRate": "Contract rate",
|
||||
"DispatchZone": "Dispatch Zone",
|
||||
"Global": "Global",
|
||||
"GlobalOps": "Global ops",
|
||||
"GlobalWikiPage": "Global Wiki page",
|
||||
"GridFilter": "GridFilter",
|
||||
"HeadOffice": "Head Office",
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"ContractRate": "Tarifa de contrato",
|
||||
"DispatchZone": "Zona de reparto",
|
||||
"Global": "Global",
|
||||
"GlobalOps": "Global ops",
|
||||
"GlobalWikiPage": "Global Wiki page",
|
||||
"GridFilter": "GridFilter",
|
||||
"HeadOffice": "Sede",
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"ContractRate": "Tarif de contrat",
|
||||
"DispatchZone": "Zone d'expédition",
|
||||
"Global": "Général",
|
||||
"GlobalOps": "Global ops",
|
||||
"GlobalWikiPage": "Global Wiki page",
|
||||
"GridFilter": "GridFilter",
|
||||
"HeadOffice": "Siège social",
|
||||
|
||||
Reference in New Issue
Block a user