This commit is contained in:
@@ -1,181 +0,0 @@
|
|||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.Routing;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
using AyaNova.Models;
|
|
||||||
using AyaNova.Api.ControllerHelpers;
|
|
||||||
using AyaNova.Biz;
|
|
||||||
using AyaNova.DataList;
|
|
||||||
|
|
||||||
|
|
||||||
namespace AyaNova.Api.Controllers
|
|
||||||
{
|
|
||||||
|
|
||||||
[ApiController]
|
|
||||||
[ApiVersion("8.0")]
|
|
||||||
[Route("api/v{version:apiVersion}/[controller]")]
|
|
||||||
[Produces("application/json")]
|
|
||||||
[Authorize]
|
|
||||||
public class DataListTemplateController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly AyContext ct;
|
|
||||||
private readonly ILogger<DataListTemplateController> log;
|
|
||||||
private readonly ApiServerState serverState;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// ctor
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dbcontext"></param>
|
|
||||||
/// <param name="logger"></param>
|
|
||||||
/// <param name="apiServerState"></param>
|
|
||||||
public DataListTemplateController(AyContext dbcontext, ILogger<DataListTemplateController> logger, ApiServerState apiServerState)
|
|
||||||
{
|
|
||||||
ct = dbcontext;
|
|
||||||
log = logger;
|
|
||||||
serverState = apiServerState;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get full DataListTemplate object
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="DataListKey"></param>
|
|
||||||
/// <returns>A single DataListTemplate</returns>
|
|
||||||
[HttpGet("{DataListKey}")]
|
|
||||||
public async Task<IActionResult> GetDataListTemplate([FromRoute] string DataListKey)
|
|
||||||
{
|
|
||||||
if (serverState.IsClosed)
|
|
||||||
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
|
|
||||||
|
|
||||||
//Attempt to get the data list by key to see if key is valid and for the default template and valid field names
|
|
||||||
var DataList = DataListFactory.GetAyaDataList(DataListKey);
|
|
||||||
if (DataList == null)
|
|
||||||
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
|
||||||
|
|
||||||
//Instantiate the business object handler
|
|
||||||
DataListTemplateBiz biz = DataListTemplateBiz.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(DataListKey, true, DataList);
|
|
||||||
if (o == null)
|
|
||||||
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
|
||||||
|
|
||||||
return Ok(ApiOkResponse.Response(o, !Authorized.HasModifyRole(HttpContext.Items, biz.BizType)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List of all DataList keys available
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>List of strings</returns>
|
|
||||||
[HttpGet("ListKeys")]
|
|
||||||
public ActionResult GetDataListKeys()
|
|
||||||
{
|
|
||||||
if (!serverState.IsOpen)
|
|
||||||
{
|
|
||||||
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(ApiOkResponse.Response(DataListFactory.GetListOfAllDataListKeyNames(), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Put (update) DataListTemplate
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="DataListKey"></param>
|
|
||||||
/// <param name="inObj"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPut("{DataListKey}")]
|
|
||||||
public async Task<IActionResult> PutDataListTemplate([FromRoute] string DataListKey, [FromBody] DataListTemplate inObj)
|
|
||||||
{
|
|
||||||
if (!serverState.IsOpen)
|
|
||||||
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(new ApiErrorResponse(ModelState));
|
|
||||||
|
|
||||||
//Attempt to get the data list by key to see if key is valid and for the default template and valid field names
|
|
||||||
var DataList = DataListFactory.GetAyaDataList(DataListKey);
|
|
||||||
if (DataList == null)
|
|
||||||
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
|
||||||
|
|
||||||
//Instantiate the business object handler
|
|
||||||
DataListTemplateBiz biz = DataListTemplateBiz.GetBiz(ct, HttpContext);
|
|
||||||
|
|
||||||
var o = await biz.GetAsync(DataListKey, false, DataList);
|
|
||||||
if (o == null)
|
|
||||||
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
|
||||||
|
|
||||||
if (!Authorized.HasModifyRole(HttpContext.Items, biz.BizType))
|
|
||||||
return StatusCode(403, new ApiNotAuthorizedResponse());
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!await biz.PutAsync(o, inObj, DataList))
|
|
||||||
return BadRequest(new ApiErrorResponse(biz.Errors));
|
|
||||||
}
|
|
||||||
catch (DbUpdateConcurrencyException)
|
|
||||||
{
|
|
||||||
// if (!await biz.ExistsAsync(id))
|
|
||||||
// return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
|
||||||
// else
|
|
||||||
//these always exist so can only be concurrency conflict
|
|
||||||
return StatusCode(409, new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT));
|
|
||||||
}
|
|
||||||
return Ok(ApiOkResponse.Response(new { ConcurrencyToken = o.ConcurrencyToken }, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Delete DataListTemplate
|
|
||||||
/// (Reset DataListTemplate to default)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="DataListKey"></param>
|
|
||||||
/// <returns>Ok</returns>
|
|
||||||
[HttpDelete("{DataListKey}")]
|
|
||||||
public async Task<IActionResult> DeleteDataListTemplate([FromRoute] string DataListKey)
|
|
||||||
{
|
|
||||||
if (!serverState.IsOpen)
|
|
||||||
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(new ApiErrorResponse(ModelState));
|
|
||||||
|
|
||||||
//Attempt to get the data list by key to see if key is valid
|
|
||||||
var DataList = DataListFactory.GetAyaDataList(DataListKey);
|
|
||||||
if (DataList == null)
|
|
||||||
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
|
||||||
|
|
||||||
//Instantiate the business object handler
|
|
||||||
DataListTemplateBiz biz = DataListTemplateBiz.GetBiz(ct, HttpContext);
|
|
||||||
|
|
||||||
var o = await biz.GetAsync(DataListKey, false, DataList);
|
|
||||||
if (o == null)
|
|
||||||
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
|
||||||
|
|
||||||
if (!Authorized.HasDeleteRole(HttpContext.Items, biz.BizType))
|
|
||||||
return StatusCode(403, new ApiNotAuthorizedResponse());
|
|
||||||
|
|
||||||
if (!await biz.DeleteAsync(o))
|
|
||||||
return BadRequest(new ApiErrorResponse(biz.Errors));
|
|
||||||
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------
|
|
||||||
|
|
||||||
|
|
||||||
}//eoc
|
|
||||||
}//eons
|
|
||||||
@@ -40,14 +40,6 @@ namespace AyaNova.DataList
|
|||||||
//start with default
|
//start with default
|
||||||
string JSONDataListTemplate = DataList.DefaultDataListDisplayTemplate;
|
string JSONDataListTemplate = DataList.DefaultDataListDisplayTemplate;
|
||||||
|
|
||||||
var CustomDataListTemplate = await ct.DataListTemplate.FirstOrDefaultAsync(x => x.DataListKey == listOptions.DataListKey);
|
|
||||||
//Null is expected unless user has created a custom one
|
|
||||||
if (CustomDataListTemplate != null)
|
|
||||||
{
|
|
||||||
//Make sure it's valid, if not then don't use it
|
|
||||||
if (DataList.ValidateTemplate(CustomDataListTemplate.Template))
|
|
||||||
JSONDataListTemplate = CustomDataListTemplate.Template;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -32,9 +32,8 @@ namespace AyaNova.Biz
|
|||||||
DEPRECATED_REUSELATER_15 = 15,
|
DEPRECATED_REUSELATER_15 = 15,
|
||||||
DEPRECATED_REUSELATER_16 = 16,
|
DEPRECATED_REUSELATER_16 = 16,
|
||||||
FileAttachment = 17,
|
FileAttachment = 17,
|
||||||
DataListSortFilter = 18,
|
DataListSortFilter = 18,
|
||||||
FormCustom = 19,
|
FormCustom = 19
|
||||||
DataListTemplate = 20
|
|
||||||
|
|
||||||
|
|
||||||
//NOTE: New objects added here need to also be added to the following classes:
|
//NOTE: New objects added here need to also be added to the following classes:
|
||||||
@@ -43,7 +42,7 @@ namespace AyaNova.Biz
|
|||||||
//AyaNova.Biz.BizRoles
|
//AyaNova.Biz.BizRoles
|
||||||
//AyaNova.Biz.BizObjectNameFetcherDIRECT
|
//AyaNova.Biz.BizObjectNameFetcherDIRECT
|
||||||
|
|
||||||
//and in the CLIENT in ayatype.js
|
//and in the CLIENT in ayatype.js
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,8 +38,7 @@ namespace AyaNova.Biz
|
|||||||
return await ct.FileAttachment.AnyAsync(m => m.Id == id);
|
return await ct.FileAttachment.AnyAsync(m => m.Id == id);
|
||||||
case AyaType.DataListSortFilter:
|
case AyaType.DataListSortFilter:
|
||||||
return await ct.DataListSortFilter.AnyAsync(m => m.Id == id);
|
return await ct.DataListSortFilter.AnyAsync(m => m.Id == id);
|
||||||
case AyaType.DataListTemplate:
|
|
||||||
return await ct.DataListTemplate.AnyAsync(m => m.Id == id);
|
|
||||||
case AyaType.FormCustom:
|
case AyaType.FormCustom:
|
||||||
return await ct.FormCustom.AnyAsync(m => m.Id == id);
|
return await ct.FormCustom.AnyAsync(m => m.Id == id);
|
||||||
|
|
||||||
|
|||||||
@@ -37,8 +37,7 @@ namespace AyaNova.Biz
|
|||||||
return new LocaleBiz(dbcontext, userId, ServerBootConfig.AYANOVA_DEFAULT_LANGUAGE_ID, roles);
|
return new LocaleBiz(dbcontext, userId, ServerBootConfig.AYANOVA_DEFAULT_LANGUAGE_ID, roles);
|
||||||
case AyaType.DataListSortFilter:
|
case AyaType.DataListSortFilter:
|
||||||
return new DataListSortFilterBiz(dbcontext, userId, ServerBootConfig.AYANOVA_DEFAULT_LANGUAGE_ID, roles);
|
return new DataListSortFilterBiz(dbcontext, userId, ServerBootConfig.AYANOVA_DEFAULT_LANGUAGE_ID, roles);
|
||||||
case AyaType.DataListTemplate:
|
|
||||||
return new DataListTemplateBiz(dbcontext, userId, ServerBootConfig.AYANOVA_DEFAULT_LANGUAGE_ID, roles);
|
|
||||||
case AyaType.FormCustom:
|
case AyaType.FormCustom:
|
||||||
return new FormCustomBiz(dbcontext, userId, ServerBootConfig.AYANOVA_DEFAULT_LANGUAGE_ID, roles);
|
return new FormCustomBiz(dbcontext, userId, ServerBootConfig.AYANOVA_DEFAULT_LANGUAGE_ID, roles);
|
||||||
|
|
||||||
|
|||||||
@@ -37,10 +37,7 @@ namespace AyaNova.Biz
|
|||||||
TABLE = "aformcustom";
|
TABLE = "aformcustom";
|
||||||
COLUMN = "formkey";
|
COLUMN = "formkey";
|
||||||
break;
|
break;
|
||||||
case AyaType.DataListTemplate:
|
|
||||||
TABLE = "adatalisttemplate";
|
|
||||||
COLUMN = "datalistkey";
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
throw new System.NotSupportedException($"AyaNova.BLL.BizObjectNameFetcher::Name type {aytype.ToString()} is not supported");
|
throw new System.NotSupportedException($"AyaNova.BLL.BizObjectNameFetcher::Name type {aytype.ToString()} is not supported");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,14 +139,7 @@ namespace AyaNova.Biz
|
|||||||
ReadFullRecord = AuthorizationRoles.All
|
ReadFullRecord = AuthorizationRoles.All
|
||||||
});
|
});
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//DATALISTTEMPLATE
|
|
||||||
//
|
|
||||||
roles.Add(AyaType.DataListTemplate, new BizRoleSet()
|
|
||||||
{
|
|
||||||
Change = AuthorizationRoles.BizAdminFull,
|
|
||||||
ReadFullRecord = AuthorizationRoles.All
|
|
||||||
});
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//FORMCUSTOM
|
//FORMCUSTOM
|
||||||
|
|||||||
@@ -1,124 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using AyaNova.Util;
|
|
||||||
using AyaNova.Api.ControllerHelpers;
|
|
||||||
using AyaNova.Models;
|
|
||||||
using AyaNova.DataList;
|
|
||||||
|
|
||||||
|
|
||||||
namespace AyaNova.Biz
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
internal class DataListTemplateBiz : BizObject
|
|
||||||
{
|
|
||||||
|
|
||||||
internal DataListTemplateBiz(AyContext dbcontext, long currentUserId, long userLocaleId, AuthorizationRoles UserRoles)
|
|
||||||
{
|
|
||||||
ct = dbcontext;
|
|
||||||
UserId = currentUserId;
|
|
||||||
UserLocaleId = userLocaleId;
|
|
||||||
CurrentUserRoles = UserRoles;
|
|
||||||
BizType = AyaType.DataListSortFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static DataListTemplateBiz GetBiz(AyContext ct, Microsoft.AspNetCore.Http.HttpContext httpContext)
|
|
||||||
{
|
|
||||||
return new DataListTemplateBiz(ct, UserIdFromContext.Id(httpContext.Items), UserLocaleIdFromContext.Id(httpContext.Items), UserRolesFromContext.Roles(httpContext.Items));
|
|
||||||
}
|
|
||||||
|
|
||||||
// //Version for internal use
|
|
||||||
// internal static DataListTemplateBiz GetBizInternal(AyContext ct)
|
|
||||||
// {
|
|
||||||
// return new DataListTemplateBiz(ct, 1, ServerBootConfig.AYANOVA_DEFAULT_LANGUAGE_ID, AuthorizationRoles.BizAdminFull);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// GET
|
|
||||||
internal async Task<DataListTemplate> GetAsync(string DataListKey, bool log, IAyaDataList dataList)
|
|
||||||
{
|
|
||||||
//DataListKey always exists, if not in db then in default form
|
|
||||||
var ret = await ct.DataListTemplate.SingleOrDefaultAsync(m => m.DataListKey == DataListKey);
|
|
||||||
//Not in db? then put it in the db with the default then return it
|
|
||||||
if (ret == null)
|
|
||||||
{
|
|
||||||
ret = new DataListTemplate();
|
|
||||||
ret.DataListKey = dataList.ListKey;
|
|
||||||
ret.Template = dataList.DefaultDataListDisplayTemplate;
|
|
||||||
await ct.DataListTemplate.AddAsync(ret);
|
|
||||||
await ct.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log)
|
|
||||||
{
|
|
||||||
//Log
|
|
||||||
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, ret.Id, BizType, AyaEvent.Retrieved), ct);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//UPDATE
|
|
||||||
//
|
|
||||||
|
|
||||||
//put
|
|
||||||
internal async Task<bool> PutAsync(DataListTemplate dbObj, DataListTemplate inObj, IAyaDataList dataList)
|
|
||||||
{
|
|
||||||
|
|
||||||
//Replace the db object with the PUT object
|
|
||||||
CopyObject.Copy(inObj, dbObj, "Id");
|
|
||||||
//Set "original" value of concurrency token to input token
|
|
||||||
//this will allow EF to check it out
|
|
||||||
ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = inObj.ConcurrencyToken;
|
|
||||||
|
|
||||||
if (!dataList.ValidateTemplate(dbObj.Template))
|
|
||||||
{
|
|
||||||
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Template");
|
|
||||||
}
|
|
||||||
if (HasErrors)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
await ct.SaveChangesAsync();
|
|
||||||
|
|
||||||
//Log modification and save context
|
|
||||||
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//DELETE
|
|
||||||
//
|
|
||||||
internal async Task<bool> DeleteAsync(DataListTemplate dbObj)
|
|
||||||
{
|
|
||||||
//no validation required, we have defaults so this is ok anytime
|
|
||||||
ct.DataListTemplate.Remove(dbObj);
|
|
||||||
await ct.SaveChangesAsync();
|
|
||||||
|
|
||||||
//Event log process delete
|
|
||||||
await EventLogProcessor.DeleteObjectLogAsync(UserId, BizType, dbObj.Id, dbObj.DataListKey, ct);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//VALIDATION
|
|
||||||
// nothing special required here, it's all tightly controlled and datalist has validation code built in
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
}//eoc
|
|
||||||
|
|
||||||
|
|
||||||
}//eons
|
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ namespace AyaNova.Models
|
|||||||
public virtual DbSet<DataListSortFilter> DataListSortFilter { get; set; }
|
public virtual DbSet<DataListSortFilter> DataListSortFilter { get; set; }
|
||||||
public virtual DbSet<Tag> Tag { get; set; }
|
public virtual DbSet<Tag> Tag { get; set; }
|
||||||
public virtual DbSet<FormCustom> FormCustom { get; set; }
|
public virtual DbSet<FormCustom> FormCustom { get; set; }
|
||||||
public virtual DbSet<DataListTemplate> DataListTemplate { get; set; }
|
|
||||||
|
|
||||||
//Note: had to add this constructor to work with the code in startup.cs that gets the connection string from the appsettings.json file
|
//Note: had to add this constructor to work with the code in startup.cs that gets the connection string from the appsettings.json file
|
||||||
//and commented out the above on configuring
|
//and commented out the above on configuring
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
|
|
||||||
namespace AyaNova.Models
|
|
||||||
{
|
|
||||||
|
|
||||||
public partial class DataListTemplate
|
|
||||||
{
|
|
||||||
public long Id { get; set; }
|
|
||||||
public uint ConcurrencyToken { get; set; }
|
|
||||||
[Required]
|
|
||||||
public string DataListKey { get; set; }
|
|
||||||
public string Template { get; set; }//JSON fragment template
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -268,8 +268,7 @@ namespace AyaNova.Util
|
|||||||
|
|
||||||
await ExecQueryAsync("CREATE TABLE adatalistsortfilter (id BIGSERIAL PRIMARY KEY, userId bigint not null, name varchar(255) not null, public bool not null," +
|
await ExecQueryAsync("CREATE TABLE adatalistsortfilter (id BIGSERIAL PRIMARY KEY, userId bigint not null, name varchar(255) not null, public bool not null," +
|
||||||
"listkey varchar(255) not null, filter text, sort text, UNIQUE(name))");
|
"listkey varchar(255) not null, filter text, sort text, UNIQUE(name))");
|
||||||
|
|
||||||
await ExecQueryAsync("CREATE TABLE adatalisttemplate (id BIGSERIAL PRIMARY KEY, datalistkey text not null, template text, UNIQUE(datalistkey))");
|
|
||||||
await SetSchemaLevelAsync(++currentSchema);
|
await SetSchemaLevelAsync(++currentSchema);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user