This commit is contained in:
17
server/kpi/IAyaKPI.cs
Normal file
17
server/kpi/IAyaKPI.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using Sockeye.Biz;
|
||||
namespace Sockeye.KPI
|
||||
{
|
||||
internal interface IAyaKPI
|
||||
{
|
||||
//allowed roles to access this kpi
|
||||
AuthorizationRoles AllowedRoles { get; }
|
||||
|
||||
//build the data and meta queries based on the criteria and this kpi's standard query
|
||||
void BuildQuery(KPIRequestOptions options, long userId);
|
||||
string MetaQuery{get;}//Query to fetch json meta data for report purposes mainly (lookup stuff like names etc where applicable)
|
||||
string DataQuery{get;}//Query to fetch json format data for result set
|
||||
string ErrorMessage{get;}//if there was a problem then this is set with the error message
|
||||
|
||||
}
|
||||
}
|
||||
33
server/kpi/KPIFactory.cs
Normal file
33
server/kpi/KPIFactory.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace Sockeye.KPI
|
||||
{
|
||||
internal static class KPIFactory
|
||||
{
|
||||
|
||||
//Instantiate list object specified from type
|
||||
internal static IAyaKPI GetAyaKPI(string name)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
|
||||
default:
|
||||
throw new System.NotImplementedException($"KPI {name} NOT IMPLEMENTED");
|
||||
|
||||
}
|
||||
//return null;
|
||||
}
|
||||
|
||||
// //List all the KPI types available
|
||||
// internal static List<string> GetListOfAllKPI()
|
||||
// {
|
||||
// List<string> ret = new List<string>();
|
||||
|
||||
// ret.Add("WorkOrderItemLaborQuantitySummary");
|
||||
// ret.Add("WorkOrderUnscheduledOpenList");
|
||||
|
||||
// return ret;
|
||||
// }
|
||||
}//eoc
|
||||
}//eons
|
||||
158
server/kpi/KPIFetcher.cs
Normal file
158
server/kpi/KPIFetcher.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
//#define AYSHOWKPIQUERYINFO
|
||||
|
||||
using Sockeye.Biz;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sockeye.Models;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Sockeye.KPI
|
||||
{
|
||||
internal static class KPIFetcher
|
||||
{
|
||||
|
||||
#if (AYSHOWKPIQUERYINFO)
|
||||
#if (DEBUG)
|
||||
#warning FYI AYSHOWKPIQUERYINFO is defined
|
||||
#else
|
||||
#error ### HOLDUP: AYSHOWKPIQUERYINFO is defined in a RELEASE BUILD!!!!
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//case 4200
|
||||
//### WARNING: IF CHANGE HERE **must** update CLIENT dash-base.js same named constant as it relies on it's own copy of this CONSTANT value to indicate if there are possibly more
|
||||
internal const int KPI_LIST_MAX_ITEMS_TO_RETURN = 100;//Maximum number of items to return from a KPI dashboard query so as not to overwhelm the client with too much data
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// Get the kpi data requested
|
||||
//
|
||||
//
|
||||
internal static async Task<JObject> GetResponseAsync(AyContext ct, KPIRequestOptions options, AuthorizationRoles userRoles, ILogger log, long userId)
|
||||
{
|
||||
|
||||
/*
|
||||
return a jobject like:
|
||||
{
|
||||
error: "if error this key present",
|
||||
meta: {username:"joe blow","date range:blah to blah"}
|
||||
data:[{r1},{r2},{r3}]
|
||||
}
|
||||
*/
|
||||
//instantiate the list
|
||||
var kpi = KPIFactory.GetAyaKPI(options.KPIName);
|
||||
|
||||
if (!Sockeye.Api.ControllerHelpers.Authorized.HasAnyRole(userRoles, kpi.AllowedRoles))
|
||||
{
|
||||
return JObject.FromObject(new
|
||||
{
|
||||
error = "NOT AUTHORIZED"
|
||||
});
|
||||
}
|
||||
|
||||
kpi.BuildQuery(options, userId);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(kpi.ErrorMessage))
|
||||
{
|
||||
return JObject.FromObject(new
|
||||
{
|
||||
error = kpi.ErrorMessage
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
JArray jData = new JArray();
|
||||
JArray jMeta = new JArray();
|
||||
|
||||
#if (DEBUG && AYSHOWKPIQUERYINFO)
|
||||
System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
|
||||
|
||||
#endif
|
||||
//QUERY THE DB
|
||||
using (var command = ct.Database.GetDbConnection().CreateCommand())
|
||||
{
|
||||
await ct.Database.OpenConnectionAsync();
|
||||
|
||||
//GET DATA RETURN ROWS
|
||||
command.CommandText = kpi.DataQuery;
|
||||
try
|
||||
{
|
||||
#if (DEBUG && AYSHOWKPIQUERYINFO)
|
||||
stopWatch.Start();
|
||||
#endif
|
||||
using (var dr = await command.ExecuteReaderAsync())
|
||||
{
|
||||
#if (DEBUG && AYSHOWKPIQUERYINFO)
|
||||
stopWatch.Stop();
|
||||
log.LogInformation($"(debug) KPIFetcher:GetResponse DATA query took {stopWatch.ElapsedMilliseconds}ms to execute: {kpi.DataQuery}");
|
||||
stopWatch.Reset();
|
||||
#endif
|
||||
|
||||
while (dr.Read())
|
||||
{
|
||||
//only one column and it's the zeroth json string column
|
||||
if (!dr.IsDBNull(0))
|
||||
jData.Add(JObject.Parse(dr.GetString(0)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(kpi.MetaQuery))
|
||||
{
|
||||
//GET META DATA ROWS
|
||||
command.CommandText = kpi.MetaQuery;
|
||||
#if (DEBUG && AYSHOWQUERYINFO)
|
||||
stopWatch.Start();
|
||||
#endif
|
||||
using (var dr = await command.ExecuteReaderAsync())
|
||||
{
|
||||
#if (DEBUG && AYSHOWQUERYINFO)
|
||||
stopWatch.Stop();
|
||||
log.LogInformation($"(debug) KPIFetcher:GetResponse META query took {stopWatch.ElapsedMilliseconds}ms to execute: {qTotalRecordsQuery}");
|
||||
#endif
|
||||
while (dr.Read())
|
||||
{
|
||||
//only one column and it's the zeroth json string column
|
||||
if (!dr.IsDBNull(0))
|
||||
jMeta.Add(JObject.Parse(dr.GetString(0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Npgsql.PostgresException e)
|
||||
{
|
||||
//log out the exception and the query
|
||||
log.LogError("KPIFetcher:GetResponseAsync query failed. Data Query was:");
|
||||
log.LogError(kpi.DataQuery);
|
||||
log.LogError("Meta Query was:");
|
||||
log.LogError(kpi.MetaQuery);
|
||||
log.LogError(e, "DB Exception");
|
||||
throw new System.Exception("KPIFetcher:GetResponseAsync - Query failed see log");
|
||||
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
//ensure any other type of exception gets surfaced properly
|
||||
//log out the exception and the query
|
||||
log.LogError("KPIFetcher:GetResponseAsync unexpected failure. Data Query was:");
|
||||
log.LogError(kpi.DataQuery);
|
||||
log.LogError("Meta Query was:");
|
||||
log.LogError(kpi.MetaQuery);
|
||||
log.LogError(e, "Exception");
|
||||
throw new System.Exception("KPIFetcher:GetResponseAsync - unexpected failure see log");
|
||||
}
|
||||
|
||||
|
||||
return JObject.FromObject(new
|
||||
{
|
||||
meta = jMeta,
|
||||
data = jData
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}//eoc
|
||||
}//eons
|
||||
30
server/kpi/KPIRequestOptions.cs
Normal file
30
server/kpi/KPIRequestOptions.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
|
||||
namespace Sockeye.KPI
|
||||
{
|
||||
|
||||
//string kpiName, string criteria, DateTimeOffset clientTimeStamp
|
||||
|
||||
|
||||
public sealed class KPIRequestOptions
|
||||
{
|
||||
|
||||
[FromBody]
|
||||
public string KPIName { get; set; }
|
||||
|
||||
[FromBody]
|
||||
public JObject Criteria { get; set; }
|
||||
|
||||
[FromBody]
|
||||
public DateTimeOffset ClientTimeStamp { get; set; }
|
||||
|
||||
public KPIRequestOptions()
|
||||
{
|
||||
KPIName=string.Empty;
|
||||
Criteria=null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user