diff --git a/restore-db-script.txt b/restore-db-script.txt index 4492406..0415c88 100644 --- a/restore-db-script.txt +++ b/restore-db-script.txt @@ -5,4 +5,17 @@ Powershell command to restore a backup of the sockeye db locally here for develo NOTE: you may need to drop and create db outside of sockeye first if schema was changed locally from the backups copy schema, in practice should always start with a fresh db restored *then* make schema changes while coding to save a hassle. -there's an info case for this if get stuck on it. \ No newline at end of file +there's an info case for this if get stuck on it. + +-- DROP DATABASE IF EXISTS sockeye; + +CREATE DATABASE sockeye + WITH + TEMPLATE = template0 + OWNER = postgres + ENCODING = 'UTF8' + LC_COLLATE = 'English_United States.1252' + LC_CTYPE = 'English_United States.1252' + TABLESPACE = pg_default + CONNECTION LIMIT = -1 + IS_TEMPLATE = False; \ No newline at end of file diff --git a/server/Controllers/SubscriptionController.cs b/server/Controllers/SubscriptionController.cs new file mode 100644 index 0000000..bc32899 --- /dev/null +++ b/server/Controllers/SubscriptionController.cs @@ -0,0 +1,140 @@ +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 Microsoft.EntityFrameworkCore; +using System.Linq; +using Sockeye.Models; +using Sockeye.Api.ControllerHelpers; +using Sockeye.Biz; + + +namespace Sockeye.Api.Controllers +{ + [ApiController] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/subscription")] + [Produces("application/json")] + [Authorize] + public class SubscriptionController : ControllerBase + { + private readonly AyContext ct; + private readonly ILogger log; + private readonly ApiServerState serverState; + + /// + /// ctor + /// + /// + /// + /// + public SubscriptionController(AyContext dbcontext, ILogger logger, ApiServerState apiServerState) + { + ct = dbcontext; + log = logger; + serverState = apiServerState; + } + + /// + /// Create Subscription + /// + /// + /// From route path + /// + [HttpPost] + public async Task PostSubscription([FromBody] Subscription newObject, ApiVersion apiVersion) + { + if (!serverState.IsOpen) + return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); + SubscriptionBiz biz = SubscriptionBiz.GetBiz(ct, HttpContext); + if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType)) + return StatusCode(403, new ApiNotAuthorizedResponse()); + if (!ModelState.IsValid) + return BadRequest(new ApiErrorResponse(ModelState)); + Subscription o = await biz.CreateAsync(newObject); + if (o == null) + return BadRequest(new ApiErrorResponse(biz.Errors)); + else + return CreatedAtAction(nameof(SubscriptionController.GetSubscription), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); + } + + + /// + /// Get Subscription + /// + /// + /// Subscription + [HttpGet("{id}")] + public async Task GetSubscription([FromRoute] long id) + { + if (!serverState.IsOpen) + return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); + SubscriptionBiz biz = SubscriptionBiz.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)); + } + + /// + /// Update Subscription + /// + /// + /// + [HttpPut] + public async Task PutSubscription([FromBody] Subscription updatedObject) + { + if (!serverState.IsOpen) + return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); + if (!ModelState.IsValid) + return BadRequest(new ApiErrorResponse(ModelState)); + SubscriptionBiz biz = SubscriptionBiz.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 })); ; + } + + /// + /// Delete Subscription + /// + /// + /// NoContent + [HttpDelete("{id}")] + public async Task DeleteSubscription([FromRoute] long id) + { + if (!serverState.IsOpen) + return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); + if (!ModelState.IsValid) + return BadRequest(new ApiErrorResponse(ModelState)); + SubscriptionBiz biz = SubscriptionBiz.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(); + } + + + + + + + //------------ + + + }//eoc + +}//eons \ No newline at end of file diff --git a/server/DataList/SubscriptionsDataList.cs b/server/DataList/SubscriptionsDataList.cs index b6aa7d9..df2b885 100644 --- a/server/DataList/SubscriptionsDataList.cs +++ b/server/DataList/SubscriptionsDataList.cs @@ -14,18 +14,18 @@ namespace Sockeye.DataList var RoleSet = BizRoles.GetRoleSet(DefaultListAType); AllowedRoles = RoleSet.ReadFullRecord | RoleSet.Change; - DefaultColumns = new List() { "name", "Customer", "active" }; + DefaultColumns = new List() { "SubSite", "Customer", "active" }; DefaultSortBy = new Dictionary() { { "Customer", "-" } }; FieldDefinitions = new List(); FieldDefinitions.Add(new DataListFieldDefinition { - TKey = "Name", - FieldKey = "name", + TKey = "SubSite", + FieldKey = "SubSite", SockType = (int)SockType.Subscription, UiFieldDataType = (int)UiFieldDataType.Text, SqlIdColumnName = "asubscription.id", - SqlValueColumnName = "asubscription.name", + SqlValueColumnName = "asubscription.subsite", IsRowId = true }); diff --git a/server/biz/SubscriptionBiz.cs b/server/biz/SubscriptionBiz.cs index 4849170..2ffffa6 100644 --- a/server/biz/SubscriptionBiz.cs +++ b/server/biz/SubscriptionBiz.cs @@ -43,7 +43,7 @@ namespace Sockeye.Biz // internal async Task CreateAsync(Subscription newObject) { - + await ValidateAsync(newObject, null); if (HasErrors) return null; @@ -201,10 +201,21 @@ namespace Sockeye.Biz private async Task ValidateAsync(Subscription proposedObj, Subscription currentObj) { - await Task.CompletedTask; - // bool isNew = currentObj == null; + bool isNew = currentObj == null; - + //Name required + if (string.IsNullOrWhiteSpace(proposedObj.Subsite)) + AddError(ApiErrorCode.VALIDATION_REQUIRED, "SubSite"); + + + //MISC / NOTSET product group are not valid for keys + if (proposedObj.PGroup == ProductGroup.Misc || proposedObj.PGroup == ProductGroup.NotSet) + { + AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "pGroup"); + return; + } + + await Task.CompletedTask; } diff --git a/server/models/Subscription.cs b/server/models/Subscription.cs index f465045..98c7dd6 100644 --- a/server/models/Subscription.cs +++ b/server/models/Subscription.cs @@ -14,7 +14,8 @@ namespace Sockeye.Models public long Id { get; set; } public uint Concurrency { get; set; } - public string Subsite { get; set; } //always null unless customer has multiple sites with same pgroup type subscription + [Required] + public string Subsite { get; set; } = "main"; public bool Active { get; set; } [Required] public ProductGroup PGroup { get; set; } diff --git a/server/util/AySchema.cs b/server/util/AySchema.cs index 7777bc1..271878f 100644 --- a/server/util/AySchema.cs +++ b/server/util/AySchema.cs @@ -23,7 +23,7 @@ namespace Sockeye.Util private const int DESIRED_SCHEMA_LEVEL = 19; internal const long EXPECTED_COLUMN_COUNT = 543; - internal const long EXPECTED_INDEX_COUNT = 78; + internal const long EXPECTED_INDEX_COUNT = 77; internal const long EXPECTED_CHECK_CONSTRAINTS = 260; internal const long EXPECTED_FOREIGN_KEY_CONSTRAINTS = 40; internal const long EXPECTED_VIEWS = 0; @@ -31,7 +31,7 @@ namespace Sockeye.Util //!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImportingAsync WHEN NEW TABLES ADDED!!!! - ///////////////////////////////////////// (C543:I78:CC260:FC40:V0:R2) + ///////////////////////////////////////// C543:I77:CC260:FC40:V0:R2 /* MAXIMUM POSTGRES OBJECT NAME LENGTH: 63 CHARACTERS @@ -1500,7 +1500,7 @@ $BODY$ LANGUAGE PLPGSQL STABLE"); LogUpdateMessage(log); //SUBSCRIPTION - await ExecQueryAsync("CREATE TABLE asubscription (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, subsite TEXT, active BOOL NOT NULL, notes TEXT, " + await ExecQueryAsync("CREATE TABLE asubscription (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, subsite TEXT NOT NULL, active BOOL NOT NULL, notes TEXT, " + "customerid BIGINT REFERENCES acustomer(id) ON DELETE CASCADE, pgroup INTEGER NOT NULL DEFAULT 4, tags VARCHAR(255) ARRAY )"); //SUBSCRIPTIONITEM