Final (?) de-widgetification

This commit is contained in:
2021-09-07 14:33:48 +00:00
parent 898daac02c
commit 316c8aa5bd
27 changed files with 45 additions and 1560 deletions

2
.vscode/launch.json vendored
View File

@@ -53,7 +53,7 @@
"AYANOVA_FOLDER_USER_FILES": "c:\\temp\\RavenTestData\\userfiles", "AYANOVA_FOLDER_USER_FILES": "c:\\temp\\RavenTestData\\userfiles",
"AYANOVA_FOLDER_BACKUP_FILES": "c:\\temp\\RavenTestData\\backupfiles", "AYANOVA_FOLDER_BACKUP_FILES": "c:\\temp\\RavenTestData\\backupfiles",
"AYANOVA_FOLDER_TEMPORARY_SERVER_FILES": "c:\\temp\\RavenTestData\\tempfiles", "AYANOVA_FOLDER_TEMPORARY_SERVER_FILES": "c:\\temp\\RavenTestData\\tempfiles",
"AYANOVA_SERVER_TEST_MODE": "false", "AYANOVA_SERVER_TEST_MODE": "true",
"AYANOVA_SERVER_TEST_MODE_SEEDLEVEL": "small", "AYANOVA_SERVER_TEST_MODE_SEEDLEVEL": "small",
"AYANOVA_SERVER_TEST_MODE_TZ_OFFSET": "-7", "AYANOVA_SERVER_TEST_MODE_TZ_OFFSET": "-7",
"AYANOVA_BACKUP_PG_DUMP_PATH": "C:\\data\\code\\postgres_13\\bin\\" "AYANOVA_BACKUP_PG_DUMP_PATH": "C:\\data\\code\\postgres_13\\bin\\"

View File

@@ -1,254 +0,0 @@
# WIDGET FORM HELP FILE Placeholder
[Incomplete - under construction]
#STANDARDS FOR AYANOVA DOCS
All one or two # headings are all capse, three or more #'s are regular sentence case.
## Body copy
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras arcu libero,
mollis sed massa vel, *ornare viverra ex*. Mauris a ullamcorper lacus. Nullam
urna elit, malesuada eget finibus ut, ullamcorper ac tortor. Vestibulum sodales
pulvinar nisl, pharetra aliquet est. Quisque volutpat erat ac nisi accumsan
tempor.
**Sed suscipit**, orci non pretium pretium, quam mi gravida metus, vel
venenatis justo est condimentum diam. Maecenas non ornare justo. Nam a ipsum
eros. [Nulla aliquam](/) orci sit amet nisl posuere malesuada. Proin aliquet
nulla velit, quis ultricies orci feugiat et. `Ut tincidunt sollicitudin`
tincidunt. Aenean ullamcorper sit amet nulla at interdum.
## Headings
### The 3rd level
#### The 4th level
##### The 5th level
###### The 6th level
## Headings <small>with secondary text</small>
### The 3rd level <small>with secondary text</small>
#### The 4th level <small>with secondary text</small>
##### The 5th level <small>with secondary text</small>
###### The 6th level <small>with secondary text</small>
## Blockquotes
> Morbi eget dapibus felis. Vivamus venenatis porttitor tortor sit amet rutrum.
Pellentesque aliquet quam enim, eu volutpat urna rutrum a. Nam vehicula nunc
mauris, a ultricies libero efficitur sed. *Class aptent* taciti sociosqu ad
litora torquent per conubia nostra, per inceptos himenaeos. Sed molestie
imperdiet consectetur.
### Blockquote nesting
> **Sed aliquet**, neque at rutrum mollis, neque nisi tincidunt nibh, vitae
faucibus lacus nunc at lacus. Nunc scelerisque, quam id cursus sodales, lorem
[libero fermentum](/) urna, ut efficitur elit ligula et nunc.
> > Mauris dictum mi lacus, sit amet pellentesque urna vehicula fringilla.
Ut sit amet placerat ante. Proin sed elementum nulla. Nunc vitae sem odio.
Suspendisse ac eros arcu. Vivamus orci erat, volutpat a tempor et, rutrum.
eu odio.
> > > `Suspendisse rutrum facilisis risus`, eu posuere neque commodo a.
Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed nec leo
bibendum, sodales mauris ut, tincidunt massa.
### Other content blocks
> Vestibulum vitae orci quis ante viverra ultricies ut eget turpis. Sed eu
lectus dapibus, eleifend nulla varius, lobortis turpis. In ac hendrerit nisl,
sit amet laoreet nibh.
``` js hl_lines="8"
var _extends = function(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
target[key] = source[key];
}
}
return target;
};
```
> > Praesent at `:::js return target`, sodales nibh vel, tempor felis. Fusce
vel lacinia lacus. Suspendisse rhoncus nunc non nisi iaculis ultrices.
Donec consectetur mauris non neque imperdiet, eget volutpat libero.
## Lists
### Unordered lists
* Sed sagittis eleifend rutrum. Donec vitae suscipit est. Nullam tempus tellus
non sem sollicitudin, quis rutrum leo facilisis. Nulla tempor lobortis orci,
at elementum urna sodales vitae. In in vehicula nulla, quis ornare libero.
* Duis mollis est eget nibh volutpat, fermentum aliquet dui mollis.
* Nam vulputate tincidunt fringilla.
* Nullam dignissim ultrices urna non auctor.
* Aliquam metus eros, pretium sed nulla venenatis, faucibus auctor ex. Proin ut
eros sed sapien ullamcorper consequat. Nunc ligula ante, fringilla at aliquam
ac, aliquet sed mauris.
* Nulla et rhoncus turpis. Mauris ultricies elementum leo. Duis efficitur
accumsan nibh eu mattis. Vivamus tempus velit eros, porttitor placerat nibh
lacinia sed. Aenean in finibus diam.
### Ordered lists
1. Integer vehicula feugiat magna, a mollis tellus. Nam mollis ex ante, quis
elementum eros tempor rutrum. Aenean efficitur lobortis lacinia. Nulla
consectetur feugiat sodales.
2. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur
ridiculus mus. Aliquam ornare feugiat quam et egestas. Nunc id erat et quam
pellentesque lacinia eu vel odio.
1. Vivamus venenatis porttitor tortor sit amet rutrum. Pellentesque aliquet
quam enim, eu volutpat urna rutrum a. Nam vehicula nunc mauris, a
ultricies libero efficitur sed.
1. Mauris dictum mi lacus
2. Ut sit amet placerat ante
3. Suspendisse ac eros arcu
2. Morbi eget dapibus felis. Vivamus venenatis porttitor tortor sit amet
rutrum. Pellentesque aliquet quam enim, eu volutpat urna rutrum a. Sed
aliquet, neque at rutrum mollis, neque nisi tincidunt nibh.
3. Pellentesque eget `:::js var _extends` ornare tellus, ut gravida mi.
``` js hl_lines="1"
var _extends = function(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
target[key] = source[key];
}
}
return target;
};
```
3. Vivamus id mi enim. Integer id turpis sapien. Ut condimentum lobortis
sagittis. Aliquam purus tellus, faucibus eget urna at, iaculis venenatis
nulla. Vivamus a pharetra leo.
### Definition lists
Lorem ipsum dolor sit amet
: Sed sagittis eleifend rutrum. Donec vitae suscipit est. Nullam tempus
tellus non sem sollicitudin, quis rutrum leo facilisis. Nulla tempor
lobortis orci, at elementum urna sodales vitae. In in vehicula nulla.
Duis mollis est eget nibh volutpat, fermentum aliquet dui mollis.
Nam vulputate tincidunt fringilla.
Nullam dignissim ultrices urna non auctor.
Cras arcu libero
: Aliquam metus eros, pretium sed nulla venenatis, faucibus auctor ex. Proin
ut eros sed sapien ullamcorper consequat. Nunc ligula ante, fringilla at
aliquam ac, aliquet sed mauris.
## Code blocks
### Inline
Morbi eget `dapibus felis`. Vivamus *`venenatis porttitor`* tortor sit amet
rutrum. Class aptent taciti sociosqu ad litora torquent per conubia nostra,
per inceptos himenaeos. [`Pellentesque aliquet quam enim`](/), eu volutpat urna
rutrum a.
Nam vehicula nunc `:::js return target` mauris, a ultricies libero efficitur
sed. Sed molestie imperdiet consectetur. Vivamus a pharetra leo. Pellentesque
eget ornare tellus, ut gravida mi. Fusce vel lacinia lacus.
### Listing
#!js hl_lines="8"
var _extends = function(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
target[key] = source[key];
}
}
return target;
};
## Horizontal rules
Aenean in finibus diam. Duis mollis est eget nibh volutpat, fermentum aliquet
dui mollis. Nam vulputate tincidunt fringilla. Nullam dignissim ultrices urna
non auctor.
***
Integer vehicula feugiat magna, a mollis tellus. Nam mollis ex ante, quis
elementum eros tempor rutrum. Aenean efficitur lobortis lacinia. Nulla
consectetur feugiat sodales.
## Data tables
| Sollicitudo / Pellentesi | consectetur | adipiscing | elit | arcu | sed |
| ------------------------ | ----------- | ---------- | ------- | ---- | --- |
| Vivamus a pharetra | yes | yes | yes | yes | yes |
| Ornare viverra ex | yes | yes | yes | yes | yes |
| Mauris a ullamcorper | yes | yes | partial | yes | yes |
| Nullam urna elit | yes | yes | yes | yes | yes |
| Malesuada eget finibus | yes | yes | yes | yes | yes |
| Ullamcorper | yes | yes | yes | yes | yes |
| Vestibulum sodales | yes | - | yes | - | yes |
| Pulvinar nisl | yes | yes | yes | - | - |
| Pharetra aliquet est | yes | yes | yes | yes | yes |
| Sed suscipit | yes | yes | yes | yes | yes |
| Orci non pretium | yes | partial | - | - | - |
Sed sagittis eleifend rutrum. Donec vitae suscipit est. Nullam tempus tellus
non sem sollicitudin, quis rutrum leo facilisis. Nulla tempor lobortis orci,
at elementum urna sodales vitae. In in vehicula nulla, quis ornare libero.
| Left | Center | Right |
| :--------- | :------: | ------: |
| Lorem | *dolor* | `amet` |
| [ipsum](/) | **sit** | |
Vestibulum vitae orci quis ante viverra ultricies ut eget turpis. Sed eu
lectus dapibus, eleifend nulla varius, lobortis turpis. In ac hendrerit nisl,
sit amet laoreet nibh.
<table>
<colgroup>
<col width="30%">
<col width="70%">
</colgroup>
<thead>
<tr class="header">
<th>Table</th>
<th>with colgroups (Pandoc)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Lorem</td>
<td>ipsum dolor sit amet.</td>
</tr>
<tr>
<td>Sed sagittis</td>
<td>eleifend rutrum. Donec vitae suscipit est.</td>
</tr>
</tbody>
</table>

View File

@@ -23,7 +23,7 @@ namespace AyaNova.Api.Controllers
public class SearchController : ControllerBase public class SearchController : ControllerBase
{ {
private readonly AyContext ct; private readonly AyContext ct;
private readonly ILogger<WidgetController> log; private readonly ILogger<SearchController> log;
private readonly ApiServerState serverState; private readonly ApiServerState serverState;
/// <summary> /// <summary>
@@ -32,7 +32,7 @@ namespace AyaNova.Api.Controllers
/// <param name="dbcontext"></param> /// <param name="dbcontext"></param>
/// <param name="logger"></param> /// <param name="logger"></param>
/// <param name="apiServerState"></param> /// <param name="apiServerState"></param>
public SearchController(AyContext dbcontext, ILogger<WidgetController> logger, ApiServerState apiServerState) public SearchController(AyContext dbcontext, ILogger<SearchController> logger, ApiServerState apiServerState)
{ {
ct = dbcontext; ct = dbcontext;
log = logger; log = logger;

View File

@@ -22,7 +22,7 @@ namespace AyaNova.Api.Controllers
public class TrialController : ControllerBase public class TrialController : ControllerBase
{ {
private readonly AyContext ct; private readonly AyContext ct;
private readonly ILogger<WidgetController> log; private readonly ILogger<TrialController> log;
private readonly ApiServerState serverState; private readonly ApiServerState serverState;
/// <summary> /// <summary>
@@ -31,7 +31,7 @@ namespace AyaNova.Api.Controllers
/// <param name="dbcontext"></param> /// <param name="dbcontext"></param>
/// <param name="logger"></param> /// <param name="logger"></param>
/// <param name="apiServerState"></param> /// <param name="apiServerState"></param>
public TrialController(AyContext dbcontext, ILogger<WidgetController> logger, ApiServerState apiServerState) public TrialController(AyContext dbcontext, ILogger<TrialController> logger, ApiServerState apiServerState)
{ {
ct = dbcontext; ct = dbcontext;
log = logger; log = logger;

View File

@@ -1,221 +0,0 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Logging;
using AyaNova.Models;
using AyaNova.Api.ControllerHelpers;
using AyaNova.Biz;
namespace AyaNova.Api.Controllers
{
//DOCUMENTATING THE API
//https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/xmldoc/recommended-tags-for-documentation-comments
//https://github.com/domaindrivendev/Swashbuckle.AspNetCore#include-descriptions-from-xml-comments
/// <summary>
/// Sample controller class used during development for testing purposes
/// </summary>
[ApiController]
[ApiVersion("8.0")]
[Route("api/v{version:apiVersion}/widget")]
[Produces("application/json")]
[Authorize]
public class WidgetController : ControllerBase
{
private readonly AyContext ct;
private readonly ILogger<WidgetController> log;
private readonly ApiServerState serverState;
/// <summary>
/// ctor
/// </summary>
/// <param name="dbcontext"></param>
/// <param name="logger"></param>
/// <param name="apiServerState"></param>
public WidgetController(AyContext dbcontext, ILogger<WidgetController> logger, ApiServerState apiServerState)
{
ct = dbcontext;
log = logger;
serverState = apiServerState;
}
/// <summary>
/// Create Widget
/// </summary>
/// <param name="newObject"></param>
/// <param name="apiVersion">From route path</param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> PostWidget([FromBody] Widget newObject, ApiVersion apiVersion)
{
if (!serverState.IsOpen)
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
WidgetBiz biz = WidgetBiz.GetBiz(ct, HttpContext);
if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType))
return StatusCode(403, new ApiNotAuthorizedResponse());
if (!ModelState.IsValid)
return BadRequest(new ApiErrorResponse(ModelState));
Widget o = await biz.CreateAsync(newObject);
if (o == null)
return BadRequest(new ApiErrorResponse(biz.Errors));
else
return CreatedAtAction(nameof(WidgetController.GetWidget), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o));
}
// /// <summary>
// /// Duplicate Widget
// /// (Wiki and Attachments are not duplicated)
// /// </summary>
// /// <param name="id">Source object id</param>
// /// <param name="apiVersion">From route path</param>
// /// <returns>Widget</returns>
// [HttpPost("duplicate/{id}")]
// public async Task<IActionResult> DuplicateWidget([FromRoute] long id, ApiVersion apiVersion)
// {
// if (!serverState.IsOpen)
// return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
// WidgetBiz biz = WidgetBiz.GetBiz(ct, HttpContext);
// if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType))
// return StatusCode(403, new ApiNotAuthorizedResponse());
// if (!ModelState.IsValid)
// return BadRequest(new ApiErrorResponse(ModelState));
// Widget o = await biz.DuplicateAsync(id);
// if (o == null)
// return BadRequest(new ApiErrorResponse(biz.Errors));
// else
// return CreatedAtAction(nameof(WidgetController.GetWidget), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o));
// }
/// <summary>
/// Get Widget
/// </summary>
/// <param name="id"></param>
/// <returns>Widget</returns>
[HttpGet("{id}")]
public async Task<IActionResult> GetWidget([FromRoute] long id)
{
if (!serverState.IsOpen)
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
WidgetBiz biz = WidgetBiz.GetBiz(ct, HttpContext);
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(id);
if (o == null) return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
return Ok(ApiOkResponse.Response(o));
}
/// <summary>
/// Update Widget
/// </summary>
/// <param name="updatedObject"></param>
/// <returns></returns>
[HttpPut]
public async Task<IActionResult> PutWidget([FromBody] Widget updatedObject)
{
if (!serverState.IsOpen)
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
if (!ModelState.IsValid)
return BadRequest(new ApiErrorResponse(ModelState));
WidgetBiz biz = WidgetBiz.GetBiz(ct, HttpContext);
if (!Authorized.HasModifyRole(HttpContext.Items, biz.BizType))
return StatusCode(403, new ApiNotAuthorizedResponse());
var o = await biz.PutAsync(updatedObject);
if (o == null)
{
if (biz.Errors.Exists(z => z.Code == ApiErrorCode.CONCURRENCY_CONFLICT))
return StatusCode(409, new ApiErrorResponse(biz.Errors));
else
return BadRequest(new ApiErrorResponse(biz.Errors));
}
return Ok(ApiOkResponse.Response(new { Concurrency = o.Concurrency }));
}
/// <summary>
/// Delete Widget
/// </summary>
/// <param name="id"></param>
/// <returns>NoContent</returns>
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteWidget([FromRoute] long id)
{
if (!serverState.IsOpen)
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
if (!ModelState.IsValid)
return BadRequest(new ApiErrorResponse(ModelState));
WidgetBiz biz = WidgetBiz.GetBiz(ct, HttpContext);
if (!Authorized.HasDeleteRole(HttpContext.Items, biz.BizType))
return StatusCode(403, new ApiNotAuthorizedResponse());
if (!await biz.DeleteAsync(id))
return BadRequest(new ApiErrorResponse(biz.Errors));
return NoContent();
}
/// <summary>
/// ReStart serial number
///
/// </summary>
/// <param name="newSerial">Next starting value for auto generated serial numbers</param>
/// <param name="apiVersion">From route path</param>
/// <returns>Widget</returns>
[HttpPost("restart-serial/{newSerial}")]
public async Task<IActionResult> ReStartSerial([FromRoute] long newSerial, ApiVersion apiVersion)
{
if (!serverState.IsOpen)
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
WidgetBiz biz = WidgetBiz.GetBiz(ct, HttpContext);
if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType))
return StatusCode(403, new ApiNotAuthorizedResponse());
if (!ModelState.IsValid)
return BadRequest(new ApiErrorResponse(ModelState));
bool result=await biz.RestartSerial(newSerial);
if (!result)
return BadRequest(new ApiErrorResponse(biz.Errors));
else
return NoContent();
}
///////////////////////////////////////////////
//TEST ROUTES
//
/// <summary>
/// Get route that triggers exception for testing
/// </summary>
/// <returns>Nothing, triggers exception</returns>
[HttpGet("exception")]
public ActionResult GetException()
{
//log.LogInformation("Widget::getexception-> Test exception and log from controller test");
if (!serverState.IsOpen)
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
throw new System.NotSupportedException("Test exception from widget controller");
}
/// <summary>
/// Get route that triggers an alternate type of exception for testing
/// </summary>
/// <returns>Nothing, triggers exception</returns>
[HttpGet("altexception")]
public ActionResult GetAltException()
{
if (!serverState.IsOpen)
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
throw new System.ArgumentException("Test exception (ALT) from widget controller");
}
//------------
}//eoc
}//eons

View File

@@ -1,129 +0,0 @@
using System.Collections.Generic;
using AyaNova.Biz;
namespace AyaNova.DataList
{
internal class TestWidgetDataList : DataListProcessingBase
{
public TestWidgetDataList()
{
DefaultListAType = AyaType.Widget;
SQLFrom = "from awidget left join auser on (awidget.userid=auser.id)";
var RoleSet = BizRoles.GetRoleSet(DefaultListAType);
AllowedRoles = RoleSet.ReadFullRecord | RoleSet.Change;
DefaultColumns = new List<string>() { "widgetname", "widgetserial", "widgetdollaramount", "widgetusertype", "widgetstartdate", "widgetactive", "username" };
DefaultSortBy = new Dictionary<string, string>() { { "widgetname", "+" } };
FieldDefinitions = new List<DataListFieldDefinition>();
FieldDefinitions.Add(new DataListFieldDefinition
{
TKey = "WidgetName",
FieldKey = "widgetname",
AType = (int)AyaType.Widget,
UiFieldDataType = (int)UiFieldDataType.Text,
SqlIdColumnName = "awidget.id",
SqlValueColumnName = "awidget.name",
IsRowId = true
});
FieldDefinitions.Add(new DataListFieldDefinition
{
TKey = "WidgetSerial",
FieldKey = "widgetserial",
UiFieldDataType = (int)UiFieldDataType.Integer,
SqlValueColumnName = "awidget.serial"
});
FieldDefinitions.Add(new DataListFieldDefinition
{
TKey = "WidgetDollarAmount",
FieldKey = "widgetdollaramount",
UiFieldDataType = (int)UiFieldDataType.Currency,
SqlValueColumnName = "awidget.dollaramount"
});
FieldDefinitions.Add(new DataListFieldDefinition
{
TKey = "WidgetCount",
FieldKey = "widgetcount",
UiFieldDataType = (int)UiFieldDataType.Integer,
SqlValueColumnName = "awidget.count"
});
FieldDefinitions.Add(new DataListFieldDefinition
{
TKey = "UserType",
FieldKey = "widgetusertype",
UiFieldDataType = (int)UiFieldDataType.Enum,
EnumType = AyaNova.Util.StringUtil.TrimTypeName(typeof(UserType).ToString()),
SqlValueColumnName = "awidget.usertype"
});
FieldDefinitions.Add(new DataListFieldDefinition
{
TKey = "WidgetStartDate",
FieldKey = "widgetstartdate",
UiFieldDataType = (int)UiFieldDataType.DateTime,
SqlValueColumnName = "awidget.startdate"
});
FieldDefinitions.Add(new DataListFieldDefinition
{
TKey = "WidgetEndDate",
FieldKey = "widgetenddate",
UiFieldDataType = (int)UiFieldDataType.DateTime,
SqlValueColumnName = "awidget.enddate"
});
FieldDefinitions.Add(new DataListFieldDefinition
{
TKey = "WidgetNotes",
FieldKey = "widgetnotes",
UiFieldDataType = (int)UiFieldDataType.Text,
SqlValueColumnName = "awidget.notes"
});
FieldDefinitions.Add(new DataListFieldDefinition
{
FieldKey = "username",
TKey = "User",
UiFieldDataType = (int)UiFieldDataType.Text,
AType = (int)AyaType.User,
SqlIdColumnName = "auser.id",
SqlValueColumnName = "auser.name"
});
FieldDefinitions.Add(new DataListFieldDefinition
{
TKey = "Active",
FieldKey = "widgetactive",
UiFieldDataType = (int)UiFieldDataType.Bool,
SqlValueColumnName = "awidget.active"
});
FieldDefinitions.Add(new DataListFieldDefinition
{
TKey = "Tags",
FieldKey = "widgettags",
UiFieldDataType = (int)UiFieldDataType.Tags,
SqlValueColumnName = "awidget.tags"
});
FieldDefinitions.Add(new DataListFieldDefinition { TKey = "WidgetCustom1", FieldKey = "widgetcustom1", IsCustomField = true, IsFilterable = false, IsSortable = false, SqlValueColumnName = "awidget.customfields" });
FieldDefinitions.Add(new DataListFieldDefinition { TKey = "WidgetCustom2", FieldKey = "widgetcustom2", IsCustomField = true, IsFilterable = false, IsSortable = false, SqlValueColumnName = "awidget.customfields" });
FieldDefinitions.Add(new DataListFieldDefinition { TKey = "WidgetCustom3", FieldKey = "widgetcustom3", IsCustomField = true, IsFilterable = false, IsSortable = false, SqlValueColumnName = "awidget.customfields" });
FieldDefinitions.Add(new DataListFieldDefinition { TKey = "WidgetCustom4", FieldKey = "widgetcustom4", IsCustomField = true, IsFilterable = false, IsSortable = false, SqlValueColumnName = "awidget.customfields" });
FieldDefinitions.Add(new DataListFieldDefinition { TKey = "WidgetCustom5", FieldKey = "widgetcustom5", IsCustomField = true, IsFilterable = false, IsSortable = false, SqlValueColumnName = "awidget.customfields" });
FieldDefinitions.Add(new DataListFieldDefinition { TKey = "WidgetCustom6", FieldKey = "widgetcustom6", IsCustomField = true, IsFilterable = false, IsSortable = false, SqlValueColumnName = "awidget.customfields" });
FieldDefinitions.Add(new DataListFieldDefinition { TKey = "WidgetCustom7", FieldKey = "widgetcustom7", IsCustomField = true, IsFilterable = false, IsSortable = false, SqlValueColumnName = "awidget.customfields" });
FieldDefinitions.Add(new DataListFieldDefinition { TKey = "WidgetCustom8", FieldKey = "widgetcustom8", IsCustomField = true, IsFilterable = false, IsSortable = false, SqlValueColumnName = "awidget.customfields" });
FieldDefinitions.Add(new DataListFieldDefinition { TKey = "WidgetCustom9", FieldKey = "widgetcustom9", IsCustomField = true, IsFilterable = false, IsSortable = false, SqlValueColumnName = "awidget.customfields" });
FieldDefinitions.Add(new DataListFieldDefinition { TKey = "WidgetCustom10", FieldKey = "widgetcustom10", IsCustomField = true, IsFilterable = false, IsSortable = false, SqlValueColumnName = "awidget.customfields" });
FieldDefinitions.Add(new DataListFieldDefinition { TKey = "WidgetCustom11", FieldKey = "widgetcustom11", IsCustomField = true, IsFilterable = false, IsSortable = false, SqlValueColumnName = "awidget.customfields" });
FieldDefinitions.Add(new DataListFieldDefinition { TKey = "WidgetCustom12", FieldKey = "widgetcustom12", IsCustomField = true, IsFilterable = false, IsSortable = false, SqlValueColumnName = "awidget.customfields" });
FieldDefinitions.Add(new DataListFieldDefinition { TKey = "WidgetCustom13", FieldKey = "widgetcustom13", IsCustomField = true, IsFilterable = false, IsSortable = false, SqlValueColumnName = "awidget.customfields" });
FieldDefinitions.Add(new DataListFieldDefinition { TKey = "WidgetCustom14", FieldKey = "widgetcustom14", IsCustomField = true, IsFilterable = false, IsSortable = false, SqlValueColumnName = "awidget.customfields" });
FieldDefinitions.Add(new DataListFieldDefinition { TKey = "WidgetCustom15", FieldKey = "widgetcustom15", IsCustomField = true, IsFilterable = false, IsSortable = false, SqlValueColumnName = "awidget.customfields" });
FieldDefinitions.Add(new DataListFieldDefinition { TKey = "WidgetCustom16", FieldKey = "widgetcustom16", IsCustomField = true, IsFilterable = false, IsSortable = false, SqlValueColumnName = "awidget.customfields" });
}
}//eoc
}//eons

View File

@@ -9,14 +9,7 @@ namespace AyaNova.PickList
internal static class PickListSqlBuilder internal static class PickListSqlBuilder
{ {
/*Example
select awidget.id as plId, awidget.active as plActive, awidget.name || ' ' || awidget.serial || ' ' || auser.name as plname, awidget.tags
from awidget left join auser on (awidget.userid=auser.id)
where array_to_string(awidget.tags,',') like '%zone-8%'
and awidget.active = true
and ((awidget.name like '%we%') or (cast (awidget.serial as text) like '%we%') or (auser.name like '%we%'))
order by awidget.name,awidget.serial,auser.name limit 100
*/
//Maximum number of results to return at any given time //Maximum number of results to return at any given time
//did a little research and may adjust this but it can be fairly girthy in this day and age //did a little research and may adjust this but it can be fairly girthy in this day and age
@@ -149,7 +142,7 @@ namespace AyaNova.PickList
lOrderBy.Add(valueColumnName); lOrderBy.Add(valueColumnName);
//THIS is the best filter method for a like comparison to each individual tag: //THIS is the best filter method for a like comparison to each individual tag:
//(array_to_string(awidget.tags,',') like '%zo%') //(array_to_string(acustomer.tags,',') like '%zo%')
//Note that a tag specific query takes precendence over this which exists //Note that a tag specific query takes precendence over this which exists
//in cases where there are tags in the template and the user has not specified a tag specific query //in cases where there are tags in the template and the user has not specified a tag specific query
//so this will handle it as a like query against all tags as a composite string of text just like //so this will handle it as a like query against all tags as a composite string of text just like
@@ -191,7 +184,7 @@ namespace AyaNova.PickList
lOrderBy.Add(valueColumnName); lOrderBy.Add(valueColumnName);
//Where fragment is different for non text fields: it needs to be cast to text to like query on it //Where fragment is different for non text fields: it needs to be cast to text to like query on it
//(cast (awidget.serial as text) like '%some%') //(cast (aworkorder.serial as text) like '%some%')
if (HasAutoCompleteQuery) if (HasAutoCompleteQuery)
if (ServerGlobalBizSettings.Cache.SearchCaseSensitiveOnly) if (ServerGlobalBizSettings.Cache.SearchCaseSensitiveOnly)
sWhere = $"(cast ({valueColumnName} as text) like '%{autoCompleteQuery}%')"; sWhere = $"(cast ({valueColumnName} as text) like '%{autoCompleteQuery}%')";
@@ -221,9 +214,9 @@ namespace AyaNova.PickList
sb.Append(", "); sb.Append(", ");
//nope, this will return null if any of the values are null, very bad for this use, instead //nope, this will return null if any of the values are null, very bad for this use, instead
//select name || ' ' || serial || ' ' || array_to_string(tags,',') as display from awidget //select name || ' ' || serial || ' ' || array_to_string(tags,',') as display from acustomer
//this, on the other hand will work even if all of them are null //this, on the other hand will work even if all of them are null
//concat_ws(' ', awidget.name, awidget.serial, auser.name) //concat_ws(' ', acustomer.name, acustomer.serial, auser.name)
sb.Append("concat_ws(' ', "); sb.Append("concat_ws(' ', ");
foreach (string s in lSelect) foreach (string s in lSelect)
@@ -315,8 +308,8 @@ namespace AyaNova.PickList
return sb.ToString(); return sb.ToString();
} }
//"select awidget.id as plId || ' 'awidget.active as plActive || ' 'awidget.name || ' 'awidget.serial || ' 'auser.name as plname from awidget left join auser on (awidget.userid=auser.id) //"select acustomer.id as plId || ' 'acustomer.active as plActive || ' 'acustomer.name || ' 'acustomer.serial || ' 'auser.name as plname from acustomer left join auser on (acustomer.userid=auser.id)
//where awidget.active = true and ((awidget.name like '%on%') or (cast (awidget.serial as text) like '%on%') or (auser.name like '%on%')) order by awidget.name,awidget.serial,auser.name limit 100" //where acustomer.active = true and ((acustomer.name like '%on%') or (cast (acustomer.serial as text) like '%on%') or (auser.name like '%on%')) order by acustomer.name,acustomer.serial,auser.name limit 100"
}//eoc }//eoc

View File

@@ -1,83 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using AyaNova.Biz;
namespace AyaNova.PickList
{
internal class WidgetPickList : AyaPickList
{
public WidgetPickList()
{
DefaultListAType = AyaType.Widget;
SQLFrom = "from awidget left join auser on (awidget.userid=auser.id)";
AllowedRoles = BizRoles.GetRoleSet(DefaultListAType).Select;
//Default template
dynamic dTemplate = new JArray();
dynamic cm = new JObject();
cm.fld = "widgetname";
dTemplate.Add(cm);
cm = new JObject();
cm.fld = "widgetserial";
dTemplate.Add(cm);
cm = new JObject();
cm.fld = "username";
dTemplate.Add(cm);
cm = new JObject();
cm.fld = "widgettags";
dTemplate.Add(cm);
base.DefaultTemplate = dTemplate.ToString(Newtonsoft.Json.Formatting.None);
//NOTE: Due to the join, all the sql id and name fields that can conflict with the joined (in this case User) table need to be specified completely
ColumnDefinitions = new List<AyaPickListFieldDefinition>();
ColumnDefinitions.Add(new AyaPickListFieldDefinition
{
TKey = "Active",
FieldKey = "widgetactive",
ColumnDataType = UiFieldDataType.Bool,
SqlValueColumnName = "awidget.active",
IsActiveColumn = true
});
ColumnDefinitions.Add(new AyaPickListFieldDefinition
{
TKey = "WidgetName",
FieldKey = "widgetname",
//AType = AyaType.Widget,
ColumnDataType = UiFieldDataType.Text,
SqlIdColumnName = "awidget.id",
SqlValueColumnName = "awidget.name",
IsRowId = true
});
ColumnDefinitions.Add(new AyaPickListFieldDefinition
{
TKey = "WidgetSerial",
FieldKey = "widgetserial",
ColumnDataType = UiFieldDataType.Integer,
SqlValueColumnName = "awidget.serial"
});
ColumnDefinitions.Add(new AyaPickListFieldDefinition
{
FieldKey = "username",
TKey = "User",
ColumnDataType = UiFieldDataType.Text,
SqlIdColumnName = "auser.id",
SqlValueColumnName = "auser.name"
});
ColumnDefinitions.Add(new AyaPickListFieldDefinition
{
TKey = "Tags",
FieldKey = "widgettags",
ColumnDataType = UiFieldDataType.Tags,
SqlValueColumnName = "awidget.tags"
});
}
}//eoc
}//eons

View File

@@ -23,8 +23,7 @@ namespace AyaNova.Biz
NoType = 0, NoType = 0,
Global = 1, Global = 1,
[CoreBizObject,ReportableBizObject] UNUSED_2 = 2,
Widget = 2,
[CoreBizObject,ReportableBizObject] [CoreBizObject,ReportableBizObject]
User = 3, User = 3,
ServerState = 4, ServerState = 4,

View File

@@ -32,8 +32,6 @@ namespace AyaNova.Biz
return await ct.FormCustom.AnyAsync(z => z.Id == id); return await ct.FormCustom.AnyAsync(z => z.Id == id);
case AyaType.User: case AyaType.User:
return await ct.User.AnyAsync(z => z.Id == id); return await ct.User.AnyAsync(z => z.Id == id);
case AyaType.Widget:
return await ct.Widget.AnyAsync(z => z.Id == id);
case AyaType.Customer: case AyaType.Customer:
return await ct.Customer.AnyAsync(z => z.Id == id); return await ct.Customer.AnyAsync(z => z.Id == id);
case AyaType.CustomerNote: case AyaType.CustomerNote:

View File

@@ -34,8 +34,6 @@ namespace AyaNova.Biz
return new DataListSavedFilterBiz(ct, userId, translationId, roles); return new DataListSavedFilterBiz(ct, userId, translationId, roles);
case AyaType.FormCustom: case AyaType.FormCustom:
return new FormCustomBiz(ct, userId, translationId, roles); return new FormCustomBiz(ct, userId, translationId, roles);
case AyaType.Widget:
return new WidgetBiz(ct, userId, translationId, roles);
case AyaType.FileAttachment: case AyaType.FileAttachment:
return new AttachmentBiz(ct, userId, roles); return new AttachmentBiz(ct, userId, roles);
case AyaType.Customer: case AyaType.Customer:

File diff suppressed because one or more lines are too long

View File

@@ -60,40 +60,6 @@ namespace AyaNova.Biz
/* ***************************** WARNING: Be careful here, if a standard field is hideable and also it's DB SCHEMA is set to NON NULLABLE then the CLIENT end needs to set a default /* ***************************** WARNING: Be careful here, if a standard field is hideable and also it's DB SCHEMA is set to NON NULLABLE then the CLIENT end needs to set a default
***************************** Otherwise the hidden field can't be set and the object can't be saved EVER ***************************** Otherwise the hidden field can't be set and the object can't be saved EVER
*/ */
#region WIDGET_KEY
{
List<FormField> l = new List<FormField>();
l.Add(new FormField { TKey = "WidgetSerial", FieldKey = "Serial" });
l.Add(new FormField { TKey = "WidgetCount", FieldKey = "Count" });
l.Add(new FormField { TKey = "WidgetDollarAmount", FieldKey = "DollarAmount" });
l.Add(new FormField { TKey = "WidgetStartDate", FieldKey = "StartDate" });
l.Add(new FormField { TKey = "WidgetEndDate", FieldKey = "EndDate" });
l.Add(new FormField { TKey = "User", FieldKey = "UserId" });
l.Add(new FormField { TKey = "UserType", FieldKey = "UserType" });
l.Add(new FormField { TKey = "WidgetNotes", FieldKey = "Notes" });
l.Add(new FormField { TKey = "Tags", FieldKey = "Tags" });
l.Add(new FormField { TKey = "Wiki", FieldKey = "Wiki" });
l.Add(new FormField { TKey = "Attachments", FieldKey = "Attachments" });
l.Add(new FormField { TKey = "WidgetCustom1", FieldKey = "WidgetCustom1", IsCustomField = true });
l.Add(new FormField { TKey = "WidgetCustom2", FieldKey = "WidgetCustom2", IsCustomField = true });
l.Add(new FormField { TKey = "WidgetCustom3", FieldKey = "WidgetCustom3", IsCustomField = true });
l.Add(new FormField { TKey = "WidgetCustom4", FieldKey = "WidgetCustom4", IsCustomField = true });
l.Add(new FormField { TKey = "WidgetCustom5", FieldKey = "WidgetCustom5", IsCustomField = true });
l.Add(new FormField { TKey = "WidgetCustom6", FieldKey = "WidgetCustom6", IsCustomField = true });
l.Add(new FormField { TKey = "WidgetCustom7", FieldKey = "WidgetCustom7", IsCustomField = true });
l.Add(new FormField { TKey = "WidgetCustom8", FieldKey = "WidgetCustom8", IsCustomField = true });
l.Add(new FormField { TKey = "WidgetCustom9", FieldKey = "WidgetCustom9", IsCustomField = true });
l.Add(new FormField { TKey = "WidgetCustom10", FieldKey = "WidgetCustom10", IsCustomField = true });
l.Add(new FormField { TKey = "WidgetCustom11", FieldKey = "WidgetCustom11", IsCustomField = true });
l.Add(new FormField { TKey = "WidgetCustom12", FieldKey = "WidgetCustom12", IsCustomField = true });
l.Add(new FormField { TKey = "WidgetCustom13", FieldKey = "WidgetCustom13", IsCustomField = true });
l.Add(new FormField { TKey = "WidgetCustom14", FieldKey = "WidgetCustom14", IsCustomField = true });
l.Add(new FormField { TKey = "WidgetCustom15", FieldKey = "WidgetCustom15", IsCustomField = true });
l.Add(new FormField { TKey = "WidgetCustom16", FieldKey = "WidgetCustom16", IsCustomField = true });
_formFields.Add(AyaType.Widget.ToString(), l);
}
#endregion widget
#region USER_KEY #region USER_KEY
{ {

View File

@@ -931,7 +931,7 @@ namespace AyaNova.Biz
if (jobData.ContainsKey("idList")) if (jobData.ContainsKey("idList"))
idList = ((JArray)jobData["idList"]).ToObject<List<long>>(); idList = ((JArray)jobData["idList"]).ToObject<List<long>>();
else else
idList = await ct.Widget.Select(z => z.Id).ToListAsync(); idList = await ct.PM.Select(z => z.Id).ToListAsync();
bool SaveIt = false; bool SaveIt = false;
foreach (long id in idList) foreach (long id in idList)
{ {

View File

@@ -912,7 +912,7 @@ namespace AyaNova.Biz
if (jobData.ContainsKey("idList")) if (jobData.ContainsKey("idList"))
idList = ((JArray)jobData["idList"]).ToObject<List<long>>(); idList = ((JArray)jobData["idList"]).ToObject<List<long>>();
else else
idList = await ct.Widget.Select(z => z.Id).ToListAsync(); idList = await ct.Quote.Select(z => z.Id).ToListAsync();
bool SaveIt = false; bool SaveIt = false;
foreach (long id in idList) foreach (long id in idList)
{ {

View File

@@ -1,552 +0,0 @@
using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System.Linq;
using EnumsNET;
using AyaNova.Util;
using AyaNova.Api.ControllerHelpers;
using AyaNova.Models;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace AyaNova.Biz
{
internal class WidgetBiz : BizObject, IJobObject, ISearchAbleObject, IReportAbleObject, IExportAbleObject, IImportAbleObject, INotifiableObject
{
internal WidgetBiz(AyContext dbcontext, long currentUserId, long userTranslationId, AuthorizationRoles UserRoles)
{
ct = dbcontext;
UserId = currentUserId;
UserTranslationId = userTranslationId;
CurrentUserRoles = UserRoles;
BizType = AyaType.Widget;
}
internal static WidgetBiz GetBiz(AyContext ct, Microsoft.AspNetCore.Http.HttpContext httpContext = null)
{
if (httpContext != null)
return new WidgetBiz(ct, UserIdFromContext.Id(httpContext.Items), UserTranslationIdFromContext.Id(httpContext.Items), UserRolesFromContext.Roles(httpContext.Items));
else
return new WidgetBiz(ct, 1, ServerBootConfig.AYANOVA_DEFAULT_TRANSLATION_ID, AuthorizationRoles.BizAdmin);
}
////////////////////////////////////////////////////////////////////////////////////////////////
//EXISTS
internal async Task<bool> ExistsAsync(long id)
{
return await ct.Widget.AnyAsync(z => z.Id == id);
}
////////////////////////////////////////////////////////////////////////////////////////////////
//CREATE
//
internal async Task<Widget> CreateAsync(Widget newObject)
{
await ValidateAsync(newObject);
if (HasErrors)
return null;
else
{
newObject.Tags = TagBiz.NormalizeTags(newObject.Tags);
newObject.CustomFields = JsonUtil.CompactJson(newObject.CustomFields);
await ct.Widget.AddAsync(newObject);
await ct.SaveChangesAsync();
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct);
await SearchIndexAsync(newObject, true);
await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, newObject.Tags, null);
await HandlePotentialNotificationEvent(AyaEvent.Created, newObject);
return newObject;
}
}
// ////////////////////////////////////////////////////////////////////////////////////////////////
// //DUPLICATE
// //
// internal async Task<Widget> DuplicateAsync(long id)
// {
// var dbObject = await GetAsync(id, false);
// if (dbObject == null)
// {
// AddError(ApiErrorCode.NOT_FOUND, "id");
// return null;
// }
// var newObject = new Widget();
// CopyObject.Copy(dbObject, newObject, "Wiki,Serial");
// string newUniqueName = string.Empty;
// bool NotUnique = true;
// long l = 1;
// do
// {
// newUniqueName = Util.StringUtil.UniqueNameBuilder(dbObject.Name, l++, 255);
// NotUnique = await ct.Widget.AnyAsync(z => z.Name == newUniqueName);
// } while (NotUnique);
// newObject.Name = newUniqueName;
// newObject.Id = 0;
// newObject.Concurrency = 0;
// await ct.Widget.AddAsync(newObject);
// await ct.SaveChangesAsync();
// await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct);
// await SearchIndexAsync(newObject, true);
// await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, newObject.Tags, null);
// await HandlePotentialNotificationEvent(AyaEvent.Created, newObject);
// return newObject;
// }
////////////////////////////////////////////////////////////////////////////////////////////////
// GET
//
internal async Task<Widget> GetAsync(long id, bool logTheGetEvent = true)
{
var ret = await ct.Widget.AsNoTracking().SingleOrDefaultAsync(z => z.Id == id);
if (logTheGetEvent && ret != null)
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, id, BizType, AyaEvent.Retrieved), ct);
return ret;
}
/*
OLD PUT CODE
////////////////////////////////////////////////////////////////////////////////////////////////
//UPDATE
//
internal async Task<Widget> PutAsync(Widget putObject)
{
Widget dbObject = await ct.Widget.SingleOrDefaultAsync(z => z.Id == putObject.Id);
if (dbObject == null)
{
AddError(ApiErrorCode.NOT_FOUND, "id");
return null;
}
Widget SnapshotOfOriginalDBObj = new Widget();
CopyObject.Copy(dbObject, SnapshotOfOriginalDBObj);
CopyObject.Copy(putObject, dbObject, "Id");//can update serial
dbObject.Tags = TagBiz.NormalizeTags(dbObject.Tags);
dbObject.CustomFields = JsonUtil.CompactJson(dbObject.CustomFields);
ct.Entry(dbObject).OriginalValues["Concurrency"] = putObject.Concurrency;
await ValidateAsync(dbObject);
if (HasErrors) return null;
try
{
await ct.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!await ExistsAsync(putObject.Id))
AddError(ApiErrorCode.NOT_FOUND);
else
AddError(ApiErrorCode.CONCURRENCY_CONFLICT);
return null;
}
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, BizType, AyaEvent.Modified), ct);
await SearchIndexAsync(dbObject, false);
await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, dbObject.Tags, SnapshotOfOriginalDBObj.Tags);
await NotifyEventProcessor.HandlePotentialNotificationEvent(AyaEvent.Modified, dbObject, SnapshotOfOriginalDBObj);
return dbObject;
}
*/
////////////////////////////////////////////////////////////////////////////////////////////////
//UPDATE
//
internal async Task<Widget> PutAsync(Widget putObject)
{
var dbObject = await GetAsync(putObject.Id, false);
if (dbObject == null)
{
AddError(ApiErrorCode.NOT_FOUND, "id");
return null;
}
if (dbObject.Concurrency != putObject.Concurrency)
{
AddError(ApiErrorCode.CONCURRENCY_CONFLICT);
return null;
}
putObject.Tags = TagBiz.NormalizeTags(putObject.Tags);
putObject.CustomFields = JsonUtil.CompactJson(putObject.CustomFields);
await ValidateAsync(putObject);
if (HasErrors) return null;
ct.Replace(dbObject, putObject);
try
{
await ct.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!await ExistsAsync(putObject.Id))
AddError(ApiErrorCode.NOT_FOUND);
else
AddError(ApiErrorCode.CONCURRENCY_CONFLICT);
return null;
}
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, BizType, AyaEvent.Modified), ct);
await SearchIndexAsync(putObject, false);
await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, putObject.Tags, dbObject.Tags);
await HandlePotentialNotificationEvent(AyaEvent.Modified, putObject, dbObject);
return putObject;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//DELETE
//
internal async Task<bool> DeleteAsync(long id)
{
using (var transaction = await ct.Database.BeginTransactionAsync())
{
var dbObject = await GetAsync(id, false);
if (dbObject == null)
{
AddError(ApiErrorCode.NOT_FOUND);
return false;
}
ValidateCanDelete(dbObject);
if (HasErrors)
return false;
if (HasErrors)
return false;
ct.Widget.Remove(dbObject);
await ct.SaveChangesAsync();
//Log event
await EventLogProcessor.DeleteObjectLogAsync(UserId, BizType, dbObject.Id, dbObject.Name, ct);
await Search.ProcessDeletedObjectKeywordsAsync(dbObject.Id, BizType, ct);
await TagBiz.ProcessDeleteTagsInRepositoryAsync(ct, dbObject.Tags);
await FileUtil.DeleteAttachmentsForObjectAsync(BizType, dbObject.Id, ct);
//all good do the commit
await transaction.CommitAsync();
await HandlePotentialNotificationEvent(AyaEvent.Deleted, dbObject);
return true;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
//RESTART SERIAL
//
internal async Task<bool> RestartSerial(long newSerial)
{
using (var command = ct.Database.GetDbConnection().CreateCommand())
{
command.CommandText = $"alter table awidget alter column serial restart with {newSerial}";
await ct.Database.OpenConnectionAsync();
await command.ExecuteNonQueryAsync();
await ct.Database.CloseConnectionAsync();
}
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, 0, BizType, AyaEvent.ResetSerial, newSerial.ToString()), ct);
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//SEARCH
//
private async Task SearchIndexAsync(Widget obj, bool isNew)
{
var SearchParams = new Search.SearchIndexProcessObjectParameters(UserTranslationId, obj.Id, BizType);
DigestSearchText(obj, SearchParams);
if (isNew)
await Search.ProcessNewObjectKeywordsAsync(SearchParams);
else
await Search.ProcessUpdatedObjectKeywordsAsync(SearchParams);
}
public async Task<Search.SearchIndexProcessObjectParameters> GetSearchResultSummary(long id, AyaType specificType)
{
var obj = await GetAsync(id, false);
var SearchParams = new Search.SearchIndexProcessObjectParameters();
DigestSearchText(obj, SearchParams);
return SearchParams;
}
public void DigestSearchText(Widget obj, Search.SearchIndexProcessObjectParameters searchParams)
{
if (obj != null)
searchParams.AddText(obj.Notes)
.AddText(obj.Name)
.AddText(obj.Wiki)
.AddText(obj.Tags)
.AddText(obj.Serial)
.AddText(obj.DollarAmount)
.AddText(obj.Count)
.AddCustomFields(obj.CustomFields);
}
////////////////////////////////////////////////////////////////////////////////////////////////
//VALIDATION
//
private async Task ValidateAsync(Widget proposedObj)
{
//skip validation if seeding
if(ServerBootConfig.SEEDING) return;
//NOTE: In DB schema only name and serial are not nullable
//run validation and biz rules
//Name required
if (string.IsNullOrWhiteSpace(proposedObj.Name))
AddError(ApiErrorCode.VALIDATION_REQUIRED, "Name");
//If name is otherwise OK, check that name is unique
if (!PropertyHasErrors("Name"))
{
//Use Any command is efficient way to check existance, it doesn't return the record, just a true or false
if (await ct.Widget.AnyAsync(z => z.Name == proposedObj.Name && z.Id != proposedObj.Id))
{
AddError(ApiErrorCode.VALIDATION_NOT_UNIQUE, "Name");
}
}
//Start date AND end date must both be null or both contain values
if (proposedObj.StartDate == null && proposedObj.EndDate != null)
AddError(ApiErrorCode.VALIDATION_REQUIRED, "StartDate");
if (proposedObj.StartDate != null && proposedObj.EndDate == null)
AddError(ApiErrorCode.VALIDATION_REQUIRED, "EndDate");
//Start date before end date
if (proposedObj.StartDate != null && proposedObj.EndDate != null)
if (proposedObj.StartDate > proposedObj.EndDate)
AddError(ApiErrorCode.VALIDATION_STARTDATE_AFTER_ENDDATE, "StartDate");
//Enum is valid value
if (!proposedObj.UserType.IsValid())
{
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "UserType");
}
//Any form customizations to validate?
var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(z => z.FormKey == AyaType.Widget.ToString());
if (FormCustomization != null)
{
//Yeppers, do the validation, there are two, the custom fields and the regular fields that might be set to required
//validate users choices for required non custom fields
RequiredFieldsValidator.Validate(this, FormCustomization, proposedObj);
//validate custom fields
CustomFieldsValidator.Validate(this, FormCustomization, proposedObj.CustomFields);
}
}
private void ValidateCanDelete(Widget inObj)
{
//whatever needs to be check to delete this object
}
//Fulfil report request for data
public async Task<JArray> GetReportData(DataListSelectedRequest dataListSelectedRequest)
{
//NOTE: Report widget is a superset of biz object widget
//Biz objects will add and needed linked records here as extra fields with the data included
//for example instead of a userid only there will be username added to the record
//so the report designer can just select it as a field, no need to query seperately for it etc
//REMEMBER: there is a name display format system and it should honour that so that the report
//displays a user the same as it would display in the UI in an input form, no surprises
var idList = dataListSelectedRequest.SelectedRowIds;
JArray ReportData = new JArray();
while (idList.Any())
{
var batch = idList.Take(IReportAbleObject.REPORT_DATA_BATCH_SIZE);
idList = idList.Skip(IReportAbleObject.REPORT_DATA_BATCH_SIZE).ToArray();
//query for this batch, comes back in db natural order unfortunately
var batchResults = await ct.Widget.AsNoTracking().Where(z => batch.Contains(z.Id)).ToArrayAsync();
//order the results back into original
var orderedList = from id in batch join z in batchResults on id equals z.Id select z;
//cache frequent viz data
//usertypes
var UserTypesEnumList = await AyaNova.Api.Controllers.EnumListController.GetEnumList(
StringUtil.TrimTypeName(typeof(UserType).ToString()),
UserTranslationId,
CurrentUserRoles);
foreach (Widget w in orderedList)
{
await PopulateVizFields(w, UserTypesEnumList);
var jo = JObject.FromObject(w);
if (!JsonUtil.JTokenIsNullOrEmpty(jo["CustomFields"]))
jo["CustomFields"] = JObject.Parse((string)jo["CustomFields"]);
ReportData.Add(jo);
}
}
return ReportData;
}
//populate viz fields from provided object
private async Task PopulateVizFields(Widget o, List<NameIdItem> userTypesEnumList)
{
if (o.UserId != null)
o.UserViz = await ct.User.AsNoTracking().Where(x => x.Id == o.UserId).Select(x => x.Name).FirstOrDefaultAsync();
o.UserTypeViz = userTypesEnumList.Where(x => x.Id == (long)o.UserType).Select(x => x.Name).First();
}
////////////////////////////////////////////////////////////////////////////////////////////////
// IMPORT EXPORT
//
public async Task<JArray> GetExportData(DataListSelectedRequest dataListSelectedRequest)
{
//for now just re-use the report data code
//this may turn out to be the pattern for most biz object types but keeping it seperate allows for custom usage from time to time
return await GetReportData(dataListSelectedRequest);
}
public async Task<List<string>> ImportData(JArray ja)
{
List<string> ImportResult = new List<string>();
string ImportTag = $"imported-{FileUtil.GetSafeDateFileName()}";
var jsset = JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = new AyaNova.Util.JsonUtil.ShouldSerializeContractResolver(new string[] { "Concurrency", "Id", "CustomFields" }) });
foreach (JObject j in ja)
{
var w = j.ToObject<Widget>(jsset);
if (j["CustomFields"] != null)
w.CustomFields = j["CustomFields"].ToString();
w.Tags.Add(ImportTag);//so user can find them all and revert later if necessary
var res = await CreateAsync(w);
if (res == null)
{
ImportResult.Add($"* {w.Name} - {this.GetErrorsAsString()}");
this.ClearErrors();
}
else
{
ImportResult.Add($"{w.Name} - ok");
}
}
return ImportResult;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//JOB / OPERATIONS
//
public async Task HandleJobAsync(OpsJob job)
{
//Hand off the particular job to the corresponding processing code
//NOTE: If this code throws an exception the caller (JobsBiz::ProcessJobsAsync) will automatically set the job to failed and log the exeption so
//basically any error condition during job processing should throw up an exception if it can't be handled
switch (job.JobType)
{
case JobType.BatchCoreObjectOperation:
await ProcessBatchJobAsync(job);
break;
default:
throw new System.ArgumentOutOfRangeException($"WidgetBiz.HandleJob-> Invalid job type{job.JobType.ToString()}");
}
}
private async Task ProcessBatchJobAsync(OpsJob job)
{
await JobsBiz.UpdateJobStatusAsync(job.GId, JobStatus.Running);
await JobsBiz.LogJobAsync(job.GId, $"LT:StartJob {job.SubType}");
List<long> idList = new List<long>();
long FailedObjectCount = 0;
JObject jobData = JObject.Parse(job.JobInfo);
if (jobData.ContainsKey("idList"))
idList = ((JArray)jobData["idList"]).ToObject<List<long>>();
else
idList = await ct.Widget.AsNoTracking().Select(z => z.Id).ToListAsync();
bool SaveIt = false;
foreach (long id in idList)
{
try
{
SaveIt = false;
ClearErrors();
Widget o = null;
//save a fetch if it's a delete
if (job.SubType != JobSubType.Delete)
o = await GetAsync(id, false);
switch (job.SubType)
{
case JobSubType.TagAddAny:
case JobSubType.TagAdd:
case JobSubType.TagRemoveAny:
case JobSubType.TagRemove:
case JobSubType.TagReplaceAny:
case JobSubType.TagReplace:
SaveIt = TagBiz.ProcessBatchTagOperation(o.Tags, (string)jobData["tag"], jobData.ContainsKey("toTag") ? (string)jobData["toTag"] : null, job.SubType);
break;
case JobSubType.Delete:
if (!await DeleteAsync(id))
{
await JobsBiz.LogJobAsync(job.GId, $"LT:Errors {GetErrorsAsString()} id {id}");
FailedObjectCount++;
}
break;
default:
throw new System.ArgumentOutOfRangeException($"ProcessBatchJobAsync -> Invalid job Subtype{job.SubType}");
}
if (SaveIt)
{
o = await PutAsync(o);
if (o == null)
{
await JobsBiz.LogJobAsync(job.GId, $"LT:Errors {GetErrorsAsString()} id {id}");
FailedObjectCount++;
}
}
}
catch (Exception ex)
{
await JobsBiz.LogJobAsync(job.GId, $"LT:Errors id({id})");
await JobsBiz.LogJobAsync(job.GId, ExceptionUtil.ExtractAllExceptionMessages(ex));
}
}
await JobsBiz.LogJobAsync(job.GId, $"LT:BatchJob {job.SubType} {idList.Count}{(FailedObjectCount > 0 ? " - LT:Failed " + FailedObjectCount : "")}");
await JobsBiz.UpdateJobStatusAsync(job.GId, JobStatus.Completed);
}
////////////////////////////////////////////////////////////////////////////////////////////////
// NOTIFICATION PROCESSING
//
public async Task HandlePotentialNotificationEvent(AyaEvent ayaEvent, ICoreBizObjectModel proposedObj, ICoreBizObjectModel currentObj = null)
{
ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger<WidgetBiz>();
if(ServerBootConfig.SEEDING || ServerBootConfig.MIGRATING) return;
log.LogDebug($"HandlePotentialNotificationEvent processing: [AyaType:{this.BizType}, AyaEvent:{ayaEvent}]");
bool isNew = currentObj == null;
//STANDARD EVENTS FOR ALL OBJECTS
await NotifyEventHelper.ProcessStandardObjectEvents(ayaEvent, proposedObj, ct);
//SPECIFIC EVENTS FOR THIS OBJECT
}//end of process notifications
/////////////////////////////////////////////////////////////////////
}//eoc
}//eons

View File

@@ -1029,7 +1029,7 @@ namespace AyaNova.Biz
if (jobData.ContainsKey("idList")) if (jobData.ContainsKey("idList"))
idList = ((JArray)jobData["idList"]).ToObject<List<long>>(); idList = ((JArray)jobData["idList"]).ToObject<List<long>>();
else else
idList = await ct.Widget.Select(z => z.Id).ToListAsync(); idList = await ct.WorkOrder.Select(z => z.Id).ToListAsync();
bool SaveIt = false; bool SaveIt = false;
foreach (long id in idList) foreach (long id in idList)
{ {

View File

@@ -10,7 +10,6 @@ namespace AyaNova.Models
public virtual DbSet<MetricDD> MetricDD { get; set; } public virtual DbSet<MetricDD> MetricDD { get; set; }
public virtual DbSet<User> User { get; set; } public virtual DbSet<User> User { get; set; }
public virtual DbSet<UserOptions> UserOptions { get; set; } public virtual DbSet<UserOptions> UserOptions { get; set; }
public virtual DbSet<Widget> Widget { get; set; }
public virtual DbSet<GlobalBizSettings> GlobalBizSettings { get; set; } public virtual DbSet<GlobalBizSettings> GlobalBizSettings { get; set; }
public virtual DbSet<GlobalOpsBackupSettings> GlobalOpsBackupSettings { get; set; } public virtual DbSet<GlobalOpsBackupSettings> GlobalOpsBackupSettings { get; set; }
public virtual DbSet<GlobalOpsNotificationSettings> GlobalOpsNotificationSettings { get; set; } public virtual DbSet<GlobalOpsNotificationSettings> GlobalOpsNotificationSettings { get; set; }
@@ -186,7 +185,6 @@ namespace AyaNova.Models
//SERIALIZED OBJECTS //SERIALIZED OBJECTS
// //
modelBuilder.Entity<PurchaseOrder>().Property(z => z.Serial).UseIdentityByDefaultColumn(); modelBuilder.Entity<PurchaseOrder>().Property(z => z.Serial).UseIdentityByDefaultColumn();
modelBuilder.Entity<Widget>().Property(z => z.Serial).UseIdentityByDefaultColumn();
modelBuilder.Entity<WorkOrder>().Property(z => z.Serial).UseIdentityByDefaultColumn(); modelBuilder.Entity<WorkOrder>().Property(z => z.Serial).UseIdentityByDefaultColumn();
modelBuilder.Entity<Quote>().Property(z => z.Serial).UseIdentityByDefaultColumn(); modelBuilder.Entity<Quote>().Property(z => z.Serial).UseIdentityByDefaultColumn();
modelBuilder.Entity<PM>().Property(z => z.Serial).UseIdentityByDefaultColumn(); modelBuilder.Entity<PM>().Property(z => z.Serial).UseIdentityByDefaultColumn();

View File

@@ -116,8 +116,7 @@ namespace AyaNova.Models
[JsonIgnore] [JsonIgnore]
public Vendor Vendor { get; set; } public Vendor Vendor { get; set; }
[JsonIgnore]//hide from being returned (as null anyway) with User object in routes
public Widget Widget { get; set; }
public User() public User()
{ {

View File

@@ -1,52 +0,0 @@
using System;
using System.Collections.Generic;
using AyaNova.Biz;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Newtonsoft.Json;
namespace AyaNova.Models
{
//NOTE: Any non required field (nullable in DB) sb nullable here, i.e. decimal? not decimal, otherwise the server will call it an invalid record if the field isn't sent from client
//NOTE: In Widget DB schema only name and serial are not nullable
public class Widget : ICoreBizObjectModel
{
public long Id { get; set; }
public uint Concurrency { get; set; }
[Required]
public string Name { get; set; }
public long Serial { get; set; }
public decimal? DollarAmount { get; set; }
public bool? Active { get; set; }
public UserType UserType { get; set; }
[NotMapped]
public string UserTypeViz { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public string Notes { get; set; }
public int? Count { get; set; }
public string Wiki { get; set; }
public string CustomFields { get; set; }
public List<string> Tags { get; set; }
//relations
//https://docs.microsoft.com/en-us/ef/core/modeling/relationships#other-relationship-patterns
[JsonIgnore]//hide from being returned (as null anyway) with User object in routes
public User User { get; set; }
public long? UserId { get; set; }
[NotMapped]
public string UserViz { get; set; }
public Widget()
{
Tags = new List<string>();
}
[NotMapped, JsonIgnore]
public AyaType AyaType { get => AyaType.Widget; }
}
}

View File

@@ -1663,31 +1663,6 @@
"SupportedUntil": "Support- und Aktualisierungsdatum", "SupportedUntil": "Support- und Aktualisierungsdatum",
"LicensedOptions": "Lizenzoptionen", "LicensedOptions": "Lizenzoptionen",
"Log": "Protokoll", "Log": "Protokoll",
"Widget": "Widget",
"WidgetList": "Widgets",
"WidgetName": "Name",
"WidgetSerial": "Seriennummer",
"WidgetDollarAmount": "Betrag",
"WidgetCount": "Anzahl",
"WidgetStartDate": "Startdatum",
"WidgetEndDate": "Enddatum",
"WidgetNotes": "Notizen",
"WidgetCustom1": "Angepasstes Feld 1",
"WidgetCustom2": "Angepasstes Feld 2",
"WidgetCustom3": "Angepasstes Feld 3",
"WidgetCustom4": "Angepasstes Feld 4",
"WidgetCustom5": "Angepasstes Feld 5",
"WidgetCustom6": "Angepasstes Feld 6",
"WidgetCustom7": "Angepasstes Feld 7",
"WidgetCustom8": "Angepasstes Feld 8",
"WidgetCustom9": "Angepasstes Feld 9",
"WidgetCustom10": "Angepasstes Feld 10",
"WidgetCustom11": "Angepasstes Feld 11",
"WidgetCustom12": "Angepasstes Feld 12",
"WidgetCustom13": "Angepasstes Feld 13",
"WidgetCustom14": "Angepasstes Feld 14",
"WidgetCustom15": "Angepasstes Feld 15",
"WidgetCustom16": "Angepasstes Feld 16",
"RowsPerPage": "Zeilen pro Seite", "RowsPerPage": "Zeilen pro Seite",
"PageOfPageText": "{0}-{1} von {2}", "PageOfPageText": "{0}-{1} von {2}",
"Loading": "Wird geladen...", "Loading": "Wird geladen...",

View File

@@ -1663,31 +1663,6 @@
"SupportedUntil": "Support and updates expiration date", "SupportedUntil": "Support and updates expiration date",
"LicensedOptions": "Licensed options", "LicensedOptions": "Licensed options",
"Log": "Log", "Log": "Log",
"Widget": "Widget",
"WidgetList": "Widgets",
"WidgetName": "Name",
"WidgetSerial": "Serial #",
"WidgetDollarAmount": "Price",
"WidgetCount": "Count",
"WidgetStartDate": "Start",
"WidgetEndDate": "End",
"WidgetNotes": "Notes",
"WidgetCustom1": "Custom1",
"WidgetCustom2": "Custom2",
"WidgetCustom3": "Custom3",
"WidgetCustom4": "Custom4",
"WidgetCustom5": "Custom5",
"WidgetCustom6": "Custom6",
"WidgetCustom7": "Custom7",
"WidgetCustom8": "Custom8",
"WidgetCustom9": "Custom9",
"WidgetCustom10": "Custom10",
"WidgetCustom11": "Custom11",
"WidgetCustom12": "Custom12",
"WidgetCustom13": "Custom13",
"WidgetCustom14": "Custom14",
"WidgetCustom15": "Custom15",
"WidgetCustom16": "Custom16",
"RowsPerPage": "Rows per page", "RowsPerPage": "Rows per page",
"PageOfPageText": "{0}-{1} of {2}", "PageOfPageText": "{0}-{1} of {2}",
"Loading": "Loading...", "Loading": "Loading...",

View File

@@ -1663,31 +1663,6 @@
"SupportedUntil": "Soporte y actualizaciones fecha de caducidad", "SupportedUntil": "Soporte y actualizaciones fecha de caducidad",
"LicensedOptions": "Opciones de licencia", "LicensedOptions": "Opciones de licencia",
"Log": "Registro", "Log": "Registro",
"Widget": "Widget",
"WidgetList": "Widgets",
"WidgetName": "Nombre",
"WidgetSerial": "Número de serie",
"WidgetDollarAmount": "Importe",
"WidgetCount": "Recuento",
"WidgetStartDate": "Fecha de comienzo",
"WidgetEndDate": "Fecha de fin",
"WidgetNotes": "Notas",
"WidgetCustom1": "Campo personalizado 1",
"WidgetCustom2": "Campo personalizado 2",
"WidgetCustom3": "Campo personalizado 3",
"WidgetCustom4": "Campo personalizado 4",
"WidgetCustom5": "Campo personalizado 5",
"WidgetCustom6": "Campo personalizado 6",
"WidgetCustom7": "Campo personalizado 7",
"WidgetCustom8": "Campo personalizado 8",
"WidgetCustom9": "Campo personalizado 9",
"WidgetCustom10": "Campo personalizado 10",
"WidgetCustom11": "Campo personalizado 11",
"WidgetCustom12": "Campo personalizado 12",
"WidgetCustom13": "Campo personalizado 13",
"WidgetCustom14": "Campo personalizado 14",
"WidgetCustom15": "Campo personalizado 15",
"WidgetCustom16": "Campo personalizado 16",
"RowsPerPage": "Filas por página", "RowsPerPage": "Filas por página",
"PageOfPageText": "{0}-{1} de {2}", "PageOfPageText": "{0}-{1} de {2}",
"Loading": "Cargando...", "Loading": "Cargando...",

View File

@@ -1663,31 +1663,6 @@
"SupportedUntil": "Support et mises à jour date d'expiration", "SupportedUntil": "Support et mises à jour date d'expiration",
"LicensedOptions": "Options de licence", "LicensedOptions": "Options de licence",
"Log": "Enregistrement", "Log": "Enregistrement",
"Widget": "Widget",
"WidgetList": "Widgets",
"WidgetName": "Nom",
"WidgetSerial": "Numéro de série",
"WidgetDollarAmount": "Montant",
"WidgetCount": "Nombre",
"WidgetStartDate": "Date de début",
"WidgetEndDate": "Date de fin",
"WidgetNotes": "Remarques",
"WidgetCustom1": "Champ personnalisé 1",
"WidgetCustom2": "Champ personnalisé 2",
"WidgetCustom3": "Champ personnalisé 3",
"WidgetCustom4": "Champ personnalisé 4",
"WidgetCustom5": "Champ personnalisé 5",
"WidgetCustom6": "Champ personnalisé 6",
"WidgetCustom7": "Champ personnalisé 7",
"WidgetCustom8": "Champ personnalisé 8",
"WidgetCustom9": "Champ personnalisé 9",
"WidgetCustom10": "Champ personnalisé 10",
"WidgetCustom11": "Champ personnalisé 11",
"WidgetCustom12": "Champ personnalisé 12",
"WidgetCustom13": "Champ personnalisé 13",
"WidgetCustom14": "Champ personnalisé 14",
"WidgetCustom15": "Champ personnalisé 15",
"WidgetCustom16": "Champ personnalisé 16",
"RowsPerPage": "Lignes par page", "RowsPerPage": "Lignes par page",
"PageOfPageText": "{0}-{1} sur {2}", "PageOfPageText": "{0}-{1} sur {2}",
"Loading": "Chargement...", "Loading": "Chargement...",

View File

@@ -22,16 +22,16 @@ namespace AyaNova.Util
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImportingAsync WHEN NEW TABLES ADDED!!!! //!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImportingAsync WHEN NEW TABLES ADDED!!!!
private const int DESIRED_SCHEMA_LEVEL = 1; private const int DESIRED_SCHEMA_LEVEL = 1;
internal const long EXPECTED_COLUMN_COUNT = 1276; internal const long EXPECTED_COLUMN_COUNT = 1262;
internal const long EXPECTED_INDEX_COUNT = 146; internal const long EXPECTED_INDEX_COUNT = 144;
internal const long EXPECTED_CHECK_CONSTRAINTS = 517; internal const long EXPECTED_CHECK_CONSTRAINTS = 513;
internal const long EXPECTED_FOREIGN_KEY_CONSTRAINTS = 192; internal const long EXPECTED_FOREIGN_KEY_CONSTRAINTS = 192;
internal const long EXPECTED_VIEWS = 9; internal const long EXPECTED_VIEWS = 9;
internal const long EXPECTED_ROUTINES = 2; internal const long EXPECTED_ROUTINES = 2;
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImportingAsync WHEN NEW TABLES ADDED!!!! //!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImportingAsync WHEN NEW TABLES ADDED!!!!
///////////////////////////////////////////////////////////////// C1276:I146:CC517:FC192:V9:R2 ///////////////////////////////////////////////////////////////// C1262:I144:CC513:FC192:V9:R2
@@ -369,7 +369,7 @@ BEGIN
case ayatype case ayatype
when 0 then return 'LT:NoType'; when 0 then return 'LT:NoType';
when 1 then return 'LT:Global'; when 1 then return 'LT:Global';
when 2 then aytable = 'awidget'; when 2 then return 'LT:UNUSED';
when 3 then aytable = 'auser'; when 3 then aytable = 'auser';
when 4 then return 'LT:ServerState'; when 4 then return 'LT:ServerState';
when 5 then return 'LT:License'; when 5 then return 'LT:License';
@@ -494,15 +494,9 @@ $BODY$ LANGUAGE PLPGSQL STABLE");
//Add user table //Add user table
await ExecQueryAsync("CREATE TABLE alicense (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, dbid TEXT, key TEXT NOT NULL)"); await ExecQueryAsync("CREATE TABLE alicense (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, dbid TEXT, key TEXT NOT NULL)");
//Add widget table
//id, TEXT, longtext, boolean, currency,
await ExecQueryAsync("CREATE TABLE awidget (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name TEXT NOT NULL UNIQUE, serial BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL,"
+ "startdate TIMESTAMP, enddate TIMESTAMP, dollaramount DECIMAL(38,18), active BOOL NOT NULL, usertype int4, count INTEGER,"
+ "notes TEXT, userid BIGINT, wiki TEXT, customfields TEXT, tags VARCHAR(255) ARRAY)");
await ExecQueryAsync("CREATE TABLE afileattachment (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, " await ExecQueryAsync("CREATE TABLE afileattachment (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, "
+ "attachtoobjectid BIGINT NOT NULL, attachtoatype INTEGER NOT NULL, " + "attachtoobjectid BIGINT NOT NULL, attachtoatype INTEGER NOT NULL, "
+ "storedfilename TEXT NOT NULL, displayfilename TEXT NOT NULL, contenttype TEXT, lastmodified TIMESTAMP NOT NULL, notes TEXT, exists BOOL NOT NULL, size BIGINT NOT NULL)"); + "storedfilename TEXT NOT NULL, displayfilename TEXT NOT NULL, contenttype TEXT, lastmodified TIMESTAMP NOT NULL, notes TEXT, exists BOOL NOT NULL, size BIGINT NOT NULL)");
//index required for ops that need to check if file already in db (delete, count refs etc) //index required for ops that need to check if file already in db (delete, count refs etc)
//LOOKAT: isn't this useless without the ID as well or is that not fetched? //LOOKAT: isn't this useless without the ID as well or is that not fetched?

View File

@@ -403,7 +403,6 @@ namespace AyaNova.Util
//--- //---
await EraseTableAsync("afileattachment", conn); await EraseTableAsync("afileattachment", conn);
await EraseTableAsync("awidget", conn);
await EraseTableAsync("aevent", conn); await EraseTableAsync("aevent", conn);
await EraseTableAsync("adatalistsavedfilter", conn); await EraseTableAsync("adatalistsavedfilter", conn);
await EraseTableAsync("adatalistcolumnview", conn); await EraseTableAsync("adatalistcolumnview", conn);

View File

@@ -114,49 +114,49 @@ namespace AyaNova.Util
apiServerState.SetOpsOnly("Seeding database with sample data"); apiServerState.SetOpsOnly("Seeding database with sample data");
// //WIDGET sample form customization // //CUSTOMER sample form customization
// { // {
// var fc = new FormCustom() // var fc = new FormCustom()
// { // {
// FormKey = AyaType.Widget.ToString(), // FormKey = AyaType.Customer.ToString(),
// Template = @"[ // Template = @"[
// { // {
// ""fld"": ""Notes"", // ""fld"": ""Notes"",
// ""required"": true // ""required"": true
// }, // },
// { // {
// ""fld"": ""WidgetCustom1"", // ""fld"": ""CustomerCustom1"",
// ""required"": false, // ""required"": false,
// ""type"": 1 // ""type"": 1
// }, // },
// { // {
// ""fld"": ""WidgetCustom2"", // ""fld"": ""CustomerCustom2"",
// ""required"": true, // ""required"": true,
// ""type"": 4 // ""type"": 4
// }, // },
// { // {
// ""fld"": ""WidgetCustom3"", // ""fld"": ""CustomerCustom3"",
// ""required"": false, // ""required"": false,
// ""type"": 5 // ""type"": 5
// }, // },
// { // {
// ""fld"": ""WidgetCustom4"", // ""fld"": ""CustomerCustom4"",
// ""required"": false, // ""required"": false,
// ""type"": 6 // ""type"": 6
// }, // },
// { // {
// ""fld"": ""WidgetCustom5"", // ""fld"": ""CustomerCustom5"",
// ""required"": false, // ""required"": false,
// ""type"": 8 // ""type"": 8
// }, // },
// { // {
// ""fld"": ""WidgetCustom6"", // ""fld"": ""CustomerCustom6"",
// ""required"": false, // ""required"": false,
// ""type"": 2 // ""type"": 2
// }, // },
// { // {
// ""fld"": ""WidgetCustom7"", // ""fld"": ""CustomerCustom7"",
// ""required"": false, // ""required"": false,
// ""type"": 3 // ""type"": 3
// } // }
@@ -175,9 +175,9 @@ namespace AyaNova.Util
// { // {
// Name = "Name starts with generic", // Name = "Name starts with generic",
// UserId = 1, // UserId = 1,
// ListKey = "TestWidgetDataList", // ListKey = "TestCustomerDataList",
// Public = true, // Public = true,
// ListView = @"[{""fld"": ""widgetname"",""filter"": {""any"":false,""items"": [{""op"": ""%-"",""value"": ""Generic""}]}}]" // ListView = @"[{""fld"": ""customername"",""filter"": {""any"":false,""items"": [{""op"": ""%-"",""value"": ""Generic""}]}}]"
// }; // };
// //Create and save to db // //Create and save to db
@@ -188,9 +188,9 @@ namespace AyaNova.Util
// { // {
// Name = "Awesome (lots of fields)", // Name = "Awesome (lots of fields)",
// UserId = 1, // UserId = 1,
// ListKey = "TestWidgetDataList", // ListKey = "TestCustomerDataList",
// Public = true, // Public = true,
// ListView = @"[{""fld"": ""widgetname"",""filter"": {""any"":false,""items"": [{""op"": ""%-"",""value"": ""Awesome""}]}},{""fld"":""widgetserial""},{""fld"":""widgetdollaramount""},{""fld"":""widgetusertype""},{""fld"":""widgetstartdate""},{""fld"":""widgetactive""},{""fld"":""username""},{""fld"":""widgettags""},{""fld"":""widgetcustom1""},{""fld"":""widgetcustom2""}]" // ListView = @"[{""fld"": ""customername"",""filter"": {""any"":false,""items"": [{""op"": ""%-"",""value"": ""Awesome""}]}},{""fld"":""customerserial""},{""fld"":""customerdollaramount""},{""fld"":""customerusertype""},{""fld"":""customerstartdate""},{""fld"":""customeractive""},{""fld"":""username""},{""fld"":""customertags""},{""fld"":""customercustom1""},{""fld"":""customercustom2""}]"
// }; // };
// //Create and save to db // //Create and save to db
@@ -228,7 +228,6 @@ namespace AyaNova.Util
await SeedUserAsync(log, 1, AuthorizationRoles.BizAdmin | AuthorizationRoles.Service | AuthorizationRoles.Inventory | AuthorizationRoles.OpsAdmin, UserType.Service); await SeedUserAsync(log, 1, AuthorizationRoles.BizAdmin | AuthorizationRoles.Service | AuthorizationRoles.Inventory | AuthorizationRoles.OpsAdmin, UserType.Service);
//Generate one office person / secretary //Generate one office person / secretary
await SeedUserAsync(log, 1, AuthorizationRoles.Service | AuthorizationRoles.Inventory | AuthorizationRoles.Accounting, UserType.NotService); await SeedUserAsync(log, 1, AuthorizationRoles.Service | AuthorizationRoles.Inventory | AuthorizationRoles.Accounting, UserType.NotService);
// await SeedWidgetAsync(log, 3);//keeping this here for now but must remove later
await SeedVendorAsync(log, 10); await SeedVendorAsync(log, 10);
await SeedUnitModelAsync(log, 10); await SeedUnitModelAsync(log, 10);
await SeedCustomerAsync(log, 25); await SeedCustomerAsync(log, 25);
@@ -287,7 +286,6 @@ namespace AyaNova.Util
//1 accountant / bookkeeper //1 accountant / bookkeeper
await SeedUserAsync(log, 1, AuthorizationRoles.Accounting | AuthorizationRoles.BizAdminRestricted, UserType.NotService); await SeedUserAsync(log, 1, AuthorizationRoles.Accounting | AuthorizationRoles.BizAdminRestricted, UserType.NotService);
//await SeedWidgetAsync(log, 100);
await SeedVendorAsync(log, 50); await SeedVendorAsync(log, 50);
await SeedUnitModelAsync(log, 20); await SeedUnitModelAsync(log, 20);
await SeedCustomerAsync(log, 500); await SeedCustomerAsync(log, 500);
@@ -356,7 +354,6 @@ namespace AyaNova.Util
//5 accountant / bookkeeper //5 accountant / bookkeeper
await SeedUserAsync(log, 5, AuthorizationRoles.Accounting | AuthorizationRoles.BizAdminRestricted, UserType.NotService); await SeedUserAsync(log, 5, AuthorizationRoles.Accounting | AuthorizationRoles.BizAdminRestricted, UserType.NotService);
//await SeedWidgetAsync(log, 100);
await SeedVendorAsync(log, 100); await SeedVendorAsync(log, 100);
await SeedUnitModelAsync(log, 40); await SeedUnitModelAsync(log, 40);
await SeedCustomerAsync(log, 1000); await SeedCustomerAsync(log, 1000);
@@ -426,7 +423,6 @@ namespace AyaNova.Util
//accountant / bookkeeper //accountant / bookkeeper
await SeedUserAsync(log, 20, AuthorizationRoles.Accounting | AuthorizationRoles.BizAdminRestricted, UserType.NotService); await SeedUserAsync(log, 20, AuthorizationRoles.Accounting | AuthorizationRoles.BizAdminRestricted, UserType.NotService);
//await SeedWidgetAsync(log, 100);
await SeedVendorAsync(log, 500); await SeedVendorAsync(log, 500);
await SeedUnitModelAsync(log, 200); await SeedUnitModelAsync(log, 200);
await SeedCustomerAsync(log, 10000); await SeedCustomerAsync(log, 10000);
@@ -1772,61 +1768,6 @@ namespace AyaNova.Util
} }
#region WIDGET
// //////////////////////////////////////////////////////
// //Seed widget for testing
// //
// public async Task SeedWidgetAsync(ILogger log, int count)
// {
// //this is 4 times slower than doing it inside the loop below
// //seems counterintuitive but maybe it's to do with the db context not being refreshed?
// //RANDOM ROLES
// Array values = Enum.GetValues(typeof(UserType));
// Random random = new Random();
// DateTime seedStartWindow = DateTime.Now.AddYears(-1).AddMonths(-6);
// DateTime seedEndWindow = DateTime.Now.AddYears(1).AddMonths(6);
// for (int x = 0; x < count; x++)
// {
// Widget o = new Widget();
// o.Name = Uniquify(Fake.Commerce.ProductName());
// o.Active = true;
// DateTime dtSeed = Fake.Date.Between(seedStartWindow, seedEndWindow).ToUniversalTime();
// o.StartDate = dtSeed;
// o.EndDate = dtSeed.AddMinutes(60).ToUniversalTime();
// o.DollarAmount = Convert.ToDecimal(Fake.Commerce.Price());
// //Random but valid enum
// UserType randomUserType = (UserType)values.GetValue(random.Next(values.Length));
// o.UserType = randomUserType;
// o.Notes = Fake.Lorem.Sentence(null, 5);
// o.Tags = RandomTags();
// o.UserId = Fake.Random.Int(1, TotalSeededUsers);
// //RANDOM CUSTOM FIELD DATA
// var c1 = DateUtil.UniversalISO8661Format(Fake.Date.Between(DateTime.Now.AddYears(-1), DateTime.Now.AddYears(1)));
// var c2 = Fake.Lorem.Sentence(null, 5);
// var c3 = Fake.Random.Int(1, 99999999);
// var c4 = Fake.Random.Bool().ToString().ToLowerInvariant();
// var c5 = Fake.Random.Decimal();
// o.CustomFields = $@"{{c1:""{c1}"",c2:""{c2}"",c3:{c3},c4:{c4},c5:{c5}}}";
// //This seems wrong to do in a loop but is 4 times faster this way ?!?
// using (AyContext ct = ServiceProviderProvider.DBContext)
// {
// WidgetBiz biz = WidgetBiz.GetBiz(ct);
// var NewObject = await biz.CreateAsync(o);
// if (NewObject == null)
// {
// log.LogError($"Seeder::SeedWidget error creating {o.Name}\r\n" + biz.GetErrorsAsString());
// throw new System.Exception("Seeder::SeedWidget error creating widget\r\n" + biz.GetErrorsAsString());
// }
// }
// }
// }
#endregion
public HashSet<string> HashCompanyNames = new HashSet<string>(); public HashSet<string> HashCompanyNames = new HashSet<string>();