From fb586e0f5b84c8c070e9ae6c204e437e3362e7c1 Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Wed, 17 Jun 2020 17:59:34 +0000 Subject: [PATCH] --- Controllers/RvlController.cs | 171 ++++++++++++++++ util/RavenKeyFactory.cs | 140 +++++++------- wwwroot/js/app.api.js | 27 +++ wwwroot/js/app.ravlicense.js | 156 +++++++++++++++ .../js/templates/app.ravlicense.handlebars | 183 ++++++++++++++++++ 5 files changed, 603 insertions(+), 74 deletions(-) create mode 100644 Controllers/RvlController.cs create mode 100644 wwwroot/js/app.ravlicense.js create mode 100644 wwwroot/js/templates/app.ravlicense.handlebars diff --git a/Controllers/RvlController.cs b/Controllers/RvlController.cs new file mode 100644 index 0000000..2b79924 --- /dev/null +++ b/Controllers/RvlController.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using Microsoft.EntityFrameworkCore; +using rockfishCore.Models; +using rockfishCore.Util; +using System.ComponentModel.DataAnnotations; + +namespace rockfishCore.Controllers +{ + [Produces("text/plain")] + [Route("rvl")] + public class RvlController : Controller //RAVEN license controller + { + private readonly rockfishContext ct; + + + public RvlController(rockfishContext context) + { + ct = context; + } + + public class dtoRavLicense + { + [Required] + public string RegisteredTo { get; set; } + [Required] + public Guid DbId { get; set; } + [Required] + public long LicenseExpiration { get; set; } + [Required] + public long MaintenanceExpiration { get; set; } + [Required] + public List Features { get; set; } + [Required] + public long SiteId { get; set; } + } + public class dtoLicenseFeature + { + dtoLicenseFeature() + { + Count = 0; + } + //name of feature / product + public string Feature { get; set; } + //Optional count for items that require it + public long Count { get; set; } + } + + +#if (DEBUG) + private const string LICENSE_SERVER_URL = "http://localhost:3001/"; + public const string SUPPORT_EMAIL = "cardjohn@ayanova.com"; +#else + private const string LICENSE_SERVER_URL = "https://rockfish.ayanova.com/"; + public const string SUPPORT_EMAIL="support@ayanova.com"; +#endif + + [HttpPost] + public async Task Post([FromBody] dtoRavLicense l) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + + //Get customer from site id + var CustomerId = await ct.Site.AsNoTracking().Where(z => z.Id == l.SiteId).Select(z => z.CustomerId).FirstOrDefaultAsync(); + + if (CustomerId == 0) + { + return BadRequest($"Customer could not be found for site id {l.SiteId}"); + } + + var Customer = await ct.Customer.AsNoTracking().Where(z => z.Id == CustomerId).FirstOrDefaultAsync(); + if (Customer == null) + { + return BadRequest($"Customer could not be found for customer id {CustomerId}"); + } + + if (string.IsNullOrWhiteSpace(Customer.AdminEmail)) + { + return BadRequest($"Customer does not have an Admin / License email address, no where to send key"); + } + + if (!Customer.Active) + { + return BadRequest($"Customer {Customer.Name} is not Active, set to active and try again"); + } + + if (Customer.DoNotContact) + { + return BadRequest($"Customer {Customer.Name} is set to DO NOT CONTACT, unable to process and send key"); + } + + + var newLicense = new RavenKeyFactory.AyaNovaLicenseKey(); + + newLicense.RegisteredTo = l.RegisteredTo; + newLicense.DbId = l.DbId; + newLicense.LicenseExpiration = DateUtil.EpochToDate(l.LicenseExpiration); + newLicense.MaintenanceExpiration = DateUtil.EpochToDate(l.MaintenanceExpiration); + foreach (dtoLicenseFeature f in l.Features) + { + newLicense.Features.Add(new RavenKeyFactory.LicenseFeature() { Feature = f.Feature, Count = f.Count }); + } + + //Everything seems to be in order generate the license, save it and send it + + + + + var NewRequest = new TrialRequest(); + NewRequest.Email = r.Email; + NewRequest.DbId = r.DbId; + NewRequest.CompanyName = r.Company; + NewRequest.ContactName = r.Contact; + await ct.TrialRequest.AddAsync(NewRequest); + await ct.SaveChangesAsync(); + NewRequest.EmailConfirmCode = NewRequest.Id.ToString() + FetchKeyCode.generate(); + await ct.SaveChangesAsync(); + var verifyUrl = LICENSE_SERVER_URL + $"rvr/verify/{NewRequest.EmailConfirmCode}"; + var body = $"Please verify your email address by clicking the link below or copy and pasting into a browser\r\n{verifyUrl}\r\n(If you did not request this you can ignore this message)"; + //send confirmation email + RfMail.SendMessage("support@ayanova.com", NewRequest.Email, "AyaNova trial request email verification", body, false); + //return Ok(new { Accepted = true }); + return Accepted(); + + } + + [HttpGet("verify/{code}")] + public async Task GetVerify([FromRoute] string code) + { + //is there a valid trial request + var req = await ct.TrialRequest.Where(z => z.EmailConfirmCode == code && z.DtFetched == null && z.Status == TrialRequest.TrialRequestStatus.NotSet).FirstOrDefaultAsync(); + if (req == null) + { + return new ContentResult + { + ContentType = "text/html", + StatusCode = 200, + Content = "

Request not found

There was no evaluation request associated with this verification code.

" + }; + } + + req.EmailValidated = true; + await ct.SaveChangesAsync(); + + //notify *us* + //http://localhost:3001/default.htm#!/trials/[id] + var rfUrl = LICENSE_SERVER_URL + $"default.htm#!/trialEdit/{req.Id}"; + var body = $"Email address {req.Email} was just verified for {req.ContactName} at {req.CompanyName}.\r\nTrial key is ready to be processed now:\r\n{rfUrl}"; + //send confirmation email + RfMail.SendMessage("support@ayanova.com", SUPPORT_EMAIL, "AyaNova trial request requiring action", body, false); + + return new ContentResult + { + ContentType = "text/html", + StatusCode = 200, + Content = "

Email validated!

Your request is being processed and you will receive an email with instructions for starting your AyaNova evaluation.

" + }; + } + + + }//eoc +}//eons \ No newline at end of file diff --git a/util/RavenKeyFactory.cs b/util/RavenKeyFactory.cs index e97a534..b03041f 100644 --- a/util/RavenKeyFactory.cs +++ b/util/RavenKeyFactory.cs @@ -36,7 +36,7 @@ namespace rockfishCore.Util #region license classes //DTO object returned on license query - internal class LicenseFeature + public class LicenseFeature { //name of feature / product public string Feature { get; set; } @@ -53,7 +53,14 @@ namespace rockfishCore.Util { Features = new List(); RegisteredTo = UNLICENSED_TOKEN; - Id = RegisteredTo; + //Id = RegisteredTo; + LicenseFormat = "8"; + + var vv = Math.Truncate((DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds); + string sId = vv.ToString(); + if (sId.Contains(",")) + sId = sId.Split('.')[0]; + Id = $"00-{sId}"; } public bool IsEmpty @@ -169,7 +176,7 @@ namespace rockfishCore.Util // private static string SAMPLE_KEY = @"[KEY // { // ""Key"": { - // ""LicenseFormat"": ""2018"", + // ""LicenseFormat"": ""8"", // ""Id"": ""34-1516288681"", <----Customer id followed by key serial id // ""RegisteredTo"": ""Super TestCo"", // ""DBID"": ""df558559-7f8a-4c7b-955c-959ebcdf71f3"", @@ -210,13 +217,13 @@ namespace rockfishCore.Util //Build a sample test key, sign it and return it AyaNovaLicenseKey k = new AyaNovaLicenseKey(); - k.LicenseFormat = "2018"; + k.LicenseFormat = "8"; - var vv = Math.Truncate((DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds); - string sId = vv.ToString(); - if (sId.Contains(",")) - sId = sId.Split('.')[0]; - k.Id = $"00-{sId}"; + // var vv = Math.Truncate((DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds); + // string sId = vv.ToString(); + // if (sId.Contains(",")) + // sId = sId.Split('.')[0]; + // k.Id = $"00-{sId}"; k.RegisteredTo = CompanyName; k.DbId = dbid; @@ -232,66 +239,26 @@ namespace rockfishCore.Util k.Features.Add(new LicenseFeature() { Feature = ACCOUNTING_FEATURE_NAME, Count = 0 }); k.Features.Add(new LicenseFeature() { Feature = SERVICE_TECHS_FEATURE_NAME, Count = 1000 }); - return genKey(k); + return GenerateRavenKey(k); } - #region RAVEN test code for development - //Trial key magic number for development and testing, all other guids will be fully licensed - private static Guid TEST_TRIAL_KEY_DBID = new Guid("{A6D18A8A-5613-4979-99DA-80D07641A2FE}"); - - - - public static string GetRavenTestKey(Guid dbid) - { - - //Build a sample test key, sign it and return it - AyaNovaLicenseKey k = new AyaNovaLicenseKey(); - k.LicenseFormat = "2018"; - - var vv = Math.Truncate((DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds); - string sId = vv.ToString(); - if (sId.Contains(",")) - sId = sId.Split('.')[0]; - k.Id = $"00-{sId}"; - k.RegisteredTo = "Best Besterson Inc."; - k.DbId = dbid; - - //add accounting and user features either way - k.Features.Add(new LicenseFeature() { Feature = ACCOUNTING_FEATURE_NAME, Count = 0 }); - k.Features.Add(new LicenseFeature() { Feature = SERVICE_TECHS_FEATURE_NAME, Count = 1000 }); - - - //fake trial key or fake licensed key - if (dbid == TEST_TRIAL_KEY_DBID) - { - k.MaintenanceExpiration = k.LicenseExpiration = DateTime.UtcNow.AddMonths(1); - k.Features.Add(new LicenseFeature() { Feature = TRIAL_FEATURE_NAME, Count = 0 }); - } - else - { - k.MaintenanceExpiration = DateTime.UtcNow.AddYears(1); - k.LicenseExpiration = DateUtil.EmptyDateValue;//1/1/5555 as per spec - } - - return genKey(k); - } - - #endregion /// - /// New RAVEN key generator, so far just for testing purposes + /// RAVEN key generator /// /// - private static string genKey(AyaNovaLicenseKey k) + internal static string GenerateRavenKey(AyaNovaLicenseKey k) { if (string.IsNullOrWhiteSpace(k.RegisteredTo)) throw new ArgumentException("RegisteredTo is required", "RegisteredTo"); + if (k.DbId == Guid.Empty) + throw new ArgumentException("DBId is required", "RegisteredTo"); try { @@ -438,28 +405,53 @@ oArP0E2Vbow3JMxq/oeXmHbrLMLQfYyXwFmciLFigOtkd45bfHdrbA== - // private static void AddLicensePlugin(Newtonsoft.Json.JsonWriter w, string pluginName, DateTime pluginExpires) - // { - - // //this dictionary is used by the additional message code to - // //make the human readable portion of the license - // _plugins.Add(pluginName, pluginExpires); - - // //this is adding it to the actual key - // w.WriteStartObject(); - // w.WritePropertyName("Item"); - // w.WriteValue(pluginName); - - // w.WritePropertyName("SubscriptionExpires"); - // w.WriteValue(pluginExpires); - - // w.WriteEndObject(); - // //---------------- - // } - //eoc } //eons -} \ No newline at end of file +} + +// #region RAVEN test code for development + +// //Trial key magic number for development and testing, all other guids will be fully licensed +// private static Guid TEST_TRIAL_KEY_DBID = new Guid("{A6D18A8A-5613-4979-99DA-80D07641A2FE}"); + + + +// public static string GetRavenTestKey(Guid dbid) +// { + +// //Build a sample test key, sign it and return it +// AyaNovaLicenseKey k = new AyaNovaLicenseKey(); +// k.LicenseFormat = "8"; + +// var vv = Math.Truncate((DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds); +// string sId = vv.ToString(); +// if (sId.Contains(",")) +// sId = sId.Split('.')[0]; +// k.Id = $"00-{sId}"; +// k.RegisteredTo = "Best Besterson Inc."; +// k.DbId = dbid; + +// //add accounting and user features either way +// k.Features.Add(new LicenseFeature() { Feature = ACCOUNTING_FEATURE_NAME, Count = 0 }); +// k.Features.Add(new LicenseFeature() { Feature = SERVICE_TECHS_FEATURE_NAME, Count = 1000 }); + + +// //fake trial key or fake licensed key +// if (dbid == TEST_TRIAL_KEY_DBID) +// { +// k.MaintenanceExpiration = k.LicenseExpiration = DateTime.UtcNow.AddMonths(1); +// k.Features.Add(new LicenseFeature() { Feature = TRIAL_FEATURE_NAME, Count = 0 }); +// } +// else +// { +// k.MaintenanceExpiration = DateTime.UtcNow.AddYears(1); +// k.LicenseExpiration = DateUtil.EmptyDateValue;//1/1/5555 as per spec +// } + +// return genKey(k); +// } + +// #endregion \ No newline at end of file diff --git a/wwwroot/js/app.api.js b/wwwroot/js/app.api.js index 1a8e82b..83d128b 100644 --- a/wwwroot/js/app.api.js +++ b/wwwroot/js/app.api.js @@ -273,6 +273,33 @@ app.api = (function () { }); }; + +/////////////////////////////////////////////////////////// + //CreateRavLicense + //Route app.post('/api/license/create', function (req, res) { + // + createRavLicense = function (objData, callback) { + $.ajax({ + method: "post", + dataType: "text", + url: app.shell.stateMap.apiUrl + "license/generate", + headers: getAuthHeaderObject(), + contentType: "application/json; charset=utf-8", + data: JSON.stringify(objData), + success: function (data, textStatus) { + callback(data); + }, + error: function (jqXHR, textStatus, errorThrown) { + callback({ + error: 1, + msg: textStatus + "\n" + errorThrown, + error_detail: {} + }); + } + }); + }; + + /////////////////////////////////////////////////////////// //GetLicenseRequests //Fetch license requests diff --git a/wwwroot/js/app.ravlicense.js b/wwwroot/js/app.ravlicense.js new file mode 100644 index 0000000..2019aff --- /dev/null +++ b/wwwroot/js/app.ravlicense.js @@ -0,0 +1,156 @@ +/* + * app.license.js + * License key generator + */ + +/*jslint browser : true, continue : true, + devel : true, indent : 2, maxerr : 50, + newcap : true, nomen : true, plusplus : true, + regexp : true, sloppy : true, vars : false, + white : true +*/ + +/*global $, app */ + +app.ravlicense = (function () { + 'use strict'; + //---------------- BEGIN MODULE SCOPE VARIABLES -------------- + var + + stateMap = {}, + configModule, initModule, onGenerate, onSelectAllAddOns; + //----------------- END MODULE SCOPE VARIABLES --------------- + + //------------------- BEGIN UTILITY METHODS ------------------ + //-------------------- END UTILITY METHODS ------------------- + + + //------------------- BEGIN EVENT HANDLERS ------------------- + onGenerate = function (event) { + + event.preventDefault(); + $.gevent.publish('app-clear-error'); + //get form data + var formData = $("form").serializeArray({ + checkboxesAsBools: true + }); + + var submitData = app.utilB.objectifyFormDataArray(formData); + + app.api.createRavLicense(submitData, function (res) { + if (res.error) { + $.gevent.publish('app-show-error', res.msg); + } else { + $('#key').val(res); + return false; + } + }); + + return false; //prevent default + }; + + + onSelectAllAddOns = function (event) { + event.preventDefault(); + $('#wbi').prop('checked', true); + $('#mbi').prop('checked', true); + $('#ri').prop('checked', true); + $('#qbi').prop('checked', true); + $('#qboi').prop('checked', true); + $('#pti').prop('checked', true); + $('#quickNotification').prop('checked', true); + $('#exportToXls').prop('checked', true); + $('#outlookSchedule').prop('checked', true); + $('#oli').prop('checked', true); + $('#importExportCSVDuplicate').prop('checked', true); + + + + return false; //prevent default + }; + + // onTemplates = function(event) { + // event.preventDefault(); + // alert("STUB: templates"); + + + // return false; //prevent default + // }; + + + //-------------------- END EVENT HANDLERS -------------------- + + //------------------- BEGIN PUBLIC METHODS ------------------- + //CONFIGMODULE + // + configModule = function (context) { + stateMap.context = context.context; + if (stateMap.context.params.id) { + stateMap.id = stateMap.context.params.id; + } + }; + + //INITMODULE + // + initModule = function ($container) { + if (typeof $container === 'undefined') { + $container = $('#app-shell-main-content'); + } + $container.html(Handlebars.templates['app.license']({})); + + + //case 3233 customer list + //Fill customer list combo + var customerList = {}; + + + //get customers + app.api.get('customer/list', function (res) { + if (res.error) { + $.gevent.publish('app-show-error', res.msg); + } else { + + var html = ''; + + for (var i = 0, len = res.length; i < len; ++i) { + html += (''); + customerList[res[i]['id']] = res[i]['name']; + } + $('#customerId').append(html); + } + }); + + + //Context menu + app.nav.contextClear(); + + ////app.nav.setContextTitle("License"); + + //make context menu + + + //Context menu + app.nav.contextClear(); + app.nav.contextAddButton('btn-generate', 'Make', 'key', onGenerate); + app.nav.contextAddButton('btn-select-all-addons', 'All', 'check-all', onSelectAllAddOns); + // app.nav.contextAddLink("licenseRequests/", "Requests", "voice"); + app.nav.contextAddLink("licenseTemplates/", "", "layers"); + //case 3233 + app.nav.contextAddLink("licenses/", "List", ""); + + + //set all date inputs to today plus one year + var oneYearFromNow = moment().add(1, 'years').toISOString().substring(0, 10); + var oneMonthFromNow = moment().add(1, 'months').toISOString().substring(0, 10); + $('input[type="date"]').val(oneYearFromNow); + $('#lockoutDate').val(oneMonthFromNow); + + }; + + // return public methods + return { + configModule: configModule, + initModule: initModule + }; + //------------------- END PUBLIC METHODS --------------------- +}()); \ No newline at end of file diff --git a/wwwroot/js/templates/app.ravlicense.handlebars b/wwwroot/js/templates/app.ravlicense.handlebars new file mode 100644 index 0000000..598ecbb --- /dev/null +++ b/wwwroot/js/templates/app.ravlicense.handlebars @@ -0,0 +1,183 @@ +
+
+
+ + +
+
+ +
+ +
+ +
+
+ +
+
+
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+ +
+
+ + +
+
+ + + +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+ +
+
+ +