This commit is contained in:
2020-06-12 23:41:42 +00:00
parent 8be276b5b6
commit 7b452670f0
7 changed files with 184 additions and 74 deletions

View File

@@ -38,10 +38,10 @@ namespace rockfishCore.Controllers
#if (DEBUG)
private const string LICENSE_SERVER_URL = "http://localhost:3001/";
private const string SUPPORT_EMAIL = "cardjohn@ayanova.com";
public const string SUPPORT_EMAIL = "cardjohn@ayanova.com";
#else
private const string LICENSE_SERVER_URL = "https://rockfish.ayanova.com/";
private const string SUPPORT_EMAIL="support@ayanova.com";
public const string SUPPORT_EMAIL="support@ayanova.com";
#endif
[HttpPost]
@@ -66,7 +66,7 @@ namespace rockfishCore.Controllers
System.Diagnostics.Debug.WriteLine("RvRController:Post - TODO: Test MustBeOlderThan date code");
//if there is an active trial for this db then can't do this they must request we re-release it or completely zap the database instead
var MustBeOlderThan = DateUtil.DateToEpoch(DateTime.Now.AddDays(-45));
var MustBeOlderThan = DateUtil.DateToEpoch(DateTime.Now.AddDays((RavenKeyFactory.TRIAL_PERIOD_DAYS * -1)));
if (await ct.TrialRequest.Where(z => z.DbId == r.DbId && z.DtProcessed != null && z.DtProcessed > MustBeOlderThan).AnyAsync())
{
return BadRequest("E1000 - Can't trial; there is already an active trial license issued for this database Id");
@@ -114,7 +114,7 @@ namespace rockfishCore.Controllers
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@ayanova.com", "AyaNova trial request requiring action", body, false);
RfMail.SendMessage("support@ayanova.com", SUPPORT_EMAIL, "AyaNova trial request requiring action", body, false);
return new ContentResult
{

View File

@@ -5,7 +5,7 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using rockfishCore.Util;
namespace rockfishCore.Controllers
{
@@ -65,44 +65,74 @@ namespace rockfishCore.Controllers
return Ok(rec);
}
// PUT: api/TrialRequest/5
[HttpPut("{id}")]
public async Task<IActionResult> PutTrialRequest([FromRoute] long id, [FromBody] TrialRequest TrialRequest)
//Approve
[HttpPost("approve/{id}")]
public async Task<IActionResult> ApproveTrial([FromRoute] long id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
var trial = await ct.TrialRequest.SingleOrDefaultAsync(m => m.Id == id);
if (trial == null)
return NotFound();
//DO APPROVE
//check not already processed and ignore if so
if(trial.DtProcessed!=null){
//already processed, nothing to do here
return BadRequest("Already processed");
}
if (id != TrialRequest.Id)
{
return BadRequest();
}
//generate license key and insert in record
trial.Key = RavenKeyFactory.GetRavenTrialKey(trial.DbId, trial.CompanyName);
trial.Status = TrialRequest.TrialRequestStatus.Approved;
trial.DtProcessed = DateUtil.NowAsEpoch();
await ct.SaveChangesAsync();
ct.Entry(TrialRequest).State = EntityState.Modified;
//send approved email to user
var body = $"Your trial license request has been approved.\r\nThe license will fetch and install automatically shortly or you can fetch it now in the License form menu.";
//send confirmation email
RfMail.SendMessage("support@ayanova.com", trial.Email, "AyaNova trial request approved", body, false);
try
{
await ct.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!await TrialRequestExistsAsync(id))
{
return NotFound();
}
else
{
throw;
}
}
return Ok(trial);
return NoContent();
}
//Reject
[HttpPost("reject/{id}")]
public async Task<IActionResult> RejectTrial([FromRoute] long id, [FromQuery] string rejectReason)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
var trial = await ct.TrialRequest.SingleOrDefaultAsync(m => m.Id == id);
if (trial == null)
return NotFound();
//DO REJECT
//check not already processed and ignore if so
if(trial.DtProcessed!=null){
//already processed, nothing to do here
return BadRequest("Already processed");
}
//generate license key and insert in record
trial.RejectReason=rejectReason;
trial.Status = TrialRequest.TrialRequestStatus.Rejected;
trial.DtProcessed = DateUtil.NowAsEpoch();
await ct.SaveChangesAsync();
//send approved email to user
string reason=string.Empty;
if(!string.IsNullOrWhiteSpace(rejectReason)){
reason=$"The request was rejected due to:\r\n{rejectReason}";
}
var body = $"Your trial license request was not approved.\r\n{reason}";
//send confirmation email
RfMail.SendMessage("support@ayanova.com", trial.Email, "AyaNova trial request approved", body, false);
return Ok(trial);
}
private async Task<bool> TrialRequestExistsAsync(long id)
@@ -110,7 +140,7 @@ namespace rockfishCore.Controllers
return await ct.TrialRequest.AnyAsync(e => e.Id == id);
}
//------------------------------------------------------
}//eoc

View File

@@ -5,8 +5,6 @@ using System.IO;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.OpenSsl;
using rockfishCore.Models;
using rockfishCore.Util;
@@ -30,6 +28,8 @@ namespace rockfishCore.Util
//This feature name means it's a trial key
private const string TRIAL_FEATURE_NAME = "TrialMode";
public const int TRIAL_PERIOD_DAYS = 45;
//This feature name means it's a SAAS or rental mode key for month to month hosted service
private const string RENTAL_FEATURE_NAME = "ServiceMode";
@@ -202,6 +202,38 @@ namespace rockfishCore.Util
#endregion
public static string GetRavenTrialKey(Guid dbid, string CompanyName)
{
//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 = CompanyName;
k.DbId = dbid;
//trial period time limit
k.MaintenanceExpiration = k.LicenseExpiration = DateTime.UtcNow.AddDays(TRIAL_PERIOD_DAYS);
//flag as trial key not regular key
k.Features.Add(new LicenseFeature() { Feature = TRIAL_FEATURE_NAME, Count = 0 });
//add every possible feature
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);
}
#region RAVEN test code for development
//Trial key magic number for development and testing, all other guids will be fully licensed

View File

@@ -11,7 +11,7 @@
*/
/*global $, io, app */
app.api = (function() {
app.api = (function () {
"use strict";
var initModule,
getAuthHeaderObject,
@@ -32,7 +32,7 @@ app.api = (function() {
//////////////////////////////////////////////////////////////////////////////////////
// NOT AUTHORIZED ERROR HANDLER
$(document).ajaxError(function(event, jqxhr, settings, thrownError) {
$(document).ajaxError(function (event, jqxhr, settings, thrownError) {
//unauthorized? Trigger logout which will trigger login after clearing creds
if (jqxhr.status == 401) {
window.location.replace("#!/logout");
@@ -46,7 +46,7 @@ app.api = (function() {
// Return the auth token header
//
//
getAuthHeaderObject = function() {
getAuthHeaderObject = function () {
return {
Authorization: "Bearer " + app.shell.stateMap.user.token
};
@@ -59,7 +59,7 @@ app.api = (function() {
//Create
//Route app.post('/api/:obj_type/create', function (req, res) {
//
create = function(apiRoute, objData, callback) {
create = function (apiRoute, objData, callback) {
$.ajax({
method: "post",
dataType: "json",
@@ -67,10 +67,10 @@ app.api = (function() {
headers: getAuthHeaderObject(),
contentType: "application/json; charset=utf-8",
data: JSON.stringify(objData),
success: function(data, textStatus) {
success: function (data, textStatus) {
callback(data);
},
error: function(jqXHR, textStatus, errorThrown) {
error: function (jqXHR, textStatus, errorThrown) {
callback({
error: 1,
msg: textStatus + "\n" + errorThrown,
@@ -83,17 +83,17 @@ app.api = (function() {
/////////////////
//Get - get anything, the caller provides the route, this should replace most legacy get
//
get = function(apiRoute, callback) {
get = function (apiRoute, callback) {
$.ajax({
method: "GET",
dataType: "json",
url: app.shell.stateMap.apiUrl + apiRoute,
headers: getAuthHeaderObject(),
success: function(data, textStatus) {
success: function (data, textStatus) {
callback(data);
},
error: function(jqXHR, textStatus, errorThrown) {
error: function (jqXHR, textStatus, errorThrown) {
callback({
error: 1,
msg: textStatus + "\n" + errorThrown,
@@ -108,7 +108,7 @@ app.api = (function() {
//Update
//route: app.post('/api/:obj_type/update/:id', function (req, res) {
//
update = function(objType, objData, callback) {
update = function (objType, objData, callback) {
var theId;
if (!objData.id) {
return callback({
@@ -125,14 +125,14 @@ app.api = (function() {
headers: getAuthHeaderObject(),
contentType: "application/json; charset=utf-8",
data: JSON.stringify(objData),
success: function(data, textStatus) {
success: function (data, textStatus) {
if (data == null) {
data = { ok: 1 };
}
callback(data);
},
error: function(jqXHR, textStatus, errorThrown) {
error: function (jqXHR, textStatus, errorThrown) {
callback({
error: 1,
msg: textStatus + "\n" + errorThrown,
@@ -144,16 +144,16 @@ app.api = (function() {
///////////////////////////////////////////////////////////
//remove Item
remove = function(apiRoute, callback) {
remove = function (apiRoute, callback) {
$.ajax({
method: "DELETE",
dataType: "json",
url: app.shell.stateMap.apiUrl + apiRoute,
headers: getAuthHeaderObject(),
success: function(data, textStatus) {
success: function (data, textStatus) {
callback(data);
},
error: function(jqXHR, textStatus, errorThrown) {
error: function (jqXHR, textStatus, errorThrown) {
callback({
error: 1,
msg: textStatus + "\n" + errorThrown,
@@ -167,7 +167,7 @@ app.api = (function() {
// uploadFile
// (ajax route to upload a file)
//
uploadFile = function(apiRoute, objData, callback) {
uploadFile = function (apiRoute, objData, callback) {
$.ajax({
method: "post",
dataType: "json",
@@ -176,10 +176,10 @@ app.api = (function() {
contentType: false,
processData: false,
data: objData,
success: function(data, textStatus) {
success: function (data, textStatus) {
callback(data);
},
error: function(jqXHR, textStatus, errorThrown) {
error: function (jqXHR, textStatus, errorThrown) {
callback({
error: 1,
msg: textStatus + "\n" + errorThrown,
@@ -192,7 +192,7 @@ app.api = (function() {
//////////////////////////////////////////////////////////////
//putAction - ad-hoc put method used to trigger actions etc
//
putAction = function(apiRoute, callback) {
putAction = function (apiRoute, callback) {
$.ajax({
method: "put",
dataType: "json",
@@ -200,14 +200,14 @@ app.api = (function() {
headers: getAuthHeaderObject(),
contentType: "application/json; charset=utf-8",
//data: JSON.stringify(objData),
success: function(data, textStatus) {
success: function (data, textStatus) {
if (data == null) {
data = { ok: 1 };
}
callback(data);
},
error: function(jqXHR, textStatus, errorThrown) {
error: function (jqXHR, textStatus, errorThrown) {
callback({
error: 1,
msg: textStatus + "\n" + errorThrown,
@@ -216,6 +216,34 @@ app.api = (function() {
}
});
};
//////////////////////////////////////////////////////////////
//postAction - ad-hoc post method used to trigger actions etc
// (becuase it shouldn't have been put in the first place above)
postAction = function (apiRoute, callback) {
$.ajax({
method: "post",
dataType: "json",
url: app.shell.stateMap.apiUrl + apiRoute,
headers: getAuthHeaderObject(),
contentType: "application/json; charset=utf-8",
success: function (data, textStatus) {
if (data == null) {
data = { ok: 1 };
}
callback(data);
},
error: function (jqXHR, textStatus, errorThrown) {
callback({
error: 1,
msg: textStatus + "\n" + errorThrown,
error_detail: {}
});
}
});
};
//////////////////////////////////////////////////////////////////////////////////////
// LICENSE KEY RELATED API METHODS
@@ -223,7 +251,7 @@ app.api = (function() {
//CreateLicense
//Route app.post('/api/license/create', function (req, res) {
//
createLicense = function(objData, callback) {
createLicense = function (objData, callback) {
$.ajax({
method: "post",
dataType: "text",
@@ -231,10 +259,10 @@ app.api = (function() {
headers: getAuthHeaderObject(),
contentType: "application/json; charset=utf-8",
data: JSON.stringify(objData),
success: function(data, textStatus) {
success: function (data, textStatus) {
callback(data);
},
error: function(jqXHR, textStatus, errorThrown) {
error: function (jqXHR, textStatus, errorThrown) {
callback({
error: 1,
msg: textStatus + "\n" + errorThrown,
@@ -249,16 +277,16 @@ app.api = (function() {
//Fetch license requests
//route: app.get('/api/license/requests', function (req, res) {
//
getLicenseRequests = function(callback) {
getLicenseRequests = function (callback) {
$.ajax({
method: "GET",
dataType: "json",
url: app.shell.stateMap.apiUrl + "license/requests",
headers: getAuthHeaderObject(),
success: function(data, textStatus) {
success: function (data, textStatus) {
callback(data);
},
error: function(jqXHR, textStatus, errorThrown) {
error: function (jqXHR, textStatus, errorThrown) {
callback({
error: 1,
msg: textStatus + "\n" + errorThrown,
@@ -273,16 +301,16 @@ app.api = (function() {
//Fetch generated response to license request
//route: app.get('/api/license/generateFromRequest/:uid', function (req, res) {
//
generateFromRequest = function(uid, callback) {
generateFromRequest = function (uid, callback) {
$.ajax({
method: "GET",
dataType: "json",
url: app.shell.stateMap.apiUrl + "license/generateFromRequest/" + uid,
headers: getAuthHeaderObject(),
success: function(data, textStatus) {
success: function (data, textStatus) {
callback(data);
},
error: function(jqXHR, textStatus, errorThrown) {
error: function (jqXHR, textStatus, errorThrown) {
callback({
error: 1,
msg: textStatus + "\n" + errorThrown,
@@ -296,7 +324,7 @@ app.api = (function() {
//Email license request response
//app.post('/api/license/email_response', function (req, res) {
//
licenseEmailResponse = function(objData, callback) {
licenseEmailResponse = function (objData, callback) {
$.ajax({
method: "post",
dataType: "text",
@@ -304,10 +332,10 @@ app.api = (function() {
headers: getAuthHeaderObject(),
contentType: "application/json; charset=utf-8",
data: JSON.stringify(objData),
success: function(data, textStatus) {
success: function (data, textStatus) {
callback(data);
},
error: function(jqXHR, textStatus, errorThrown) {
error: function (jqXHR, textStatus, errorThrown) {
callback({
error: 1,
msg: textStatus + "\n" + errorThrown,
@@ -317,7 +345,7 @@ app.api = (function() {
});
};
initModule = function() {};
initModule = function () {};
return {
initModule: initModule,
@@ -329,6 +357,7 @@ app.api = (function() {
update: update,
uploadFile: uploadFile,
putAction: putAction,
postAction: postAction,
createLicense: createLicense,
getLicenseRequests: getLicenseRequests,
generateFromRequest: generateFromRequest,

View File

@@ -12,16 +12,34 @@ app.trialEdit = (function () {
//---------------- BEGIN MODULE SCOPE VARIABLES --------------
var
stateMap = {},
onSave, onDelete,
onApprove, onReject, onDelete,
configModule, initModule;
//----------------- END MODULE SCOPE VARIABLES ---------------
//------------------- BEGIN EVENT HANDLERS -------------------
//ONSAVE
//ONAPPROVE
//
onSave = function (event) {
onApprove = function (event) {
event.preventDefault();
$.gevent.publish('app-clear-error');
var isFetched=$('#fetched').prop('checked')
app.api.postAction('trial/fetched/' + stateMap.id + "/" + isFetched, function (res) {
if (res.error) {
$.gevent.publish('app-show-error', res.msg);
}
});
return false; //prevent default?
};
//ONREJECT
//
onReject = function (event) {
event.preventDefault();
$.gevent.publish('app-clear-error');
@@ -37,6 +55,7 @@ app.trialEdit = (function () {
return false; //prevent default?
};
//ONDELETE
//
onDelete = function (event) {

View File

@@ -48,7 +48,7 @@
</div>
<div class="form-group">
<label for="rejectReason">Reject reason</label>
<label for="rejectReason">Reject reason *emailed to user</label>
<input class="form-control" type="text" id="rejectReason" name="rejectReason" value="" >
</div>

File diff suppressed because one or more lines are too long