diff --git a/docs/8.0/ayanova/docs/ops-install-linux-desktop.md b/docs/8.0/ayanova/docs/ops-install-linux-desktop.md
index 56be4b45..d4e9ea47 100644
--- a/docs/8.0/ayanova/docs/ops-install-linux-desktop.md
+++ b/docs/8.0/ayanova/docs/ops-install-linux-desktop.md
@@ -90,7 +90,7 @@ sudo mkdir /usr/bin/ayanova
[https://www.ayanova.com/download/ayanova-linux-x64-desktop.zip](https://www.ayanova.com/download/ayanova-linux-x64-desktop.zip)
-Download the the AyaNova server binary files folder created in the previous step or copy it there from the terminal:
+Download the AyaNova server binary files to the folder created in the previous step or copy it there from the terminal:
```bash
sudo cp ayanova-linux-x64-desktop.zip /usr/bin/ayanova/
diff --git a/server/AyaNova/Controllers/AuthController.cs b/server/AyaNova/Controllers/AuthController.cs
index 2cc872de..b9b5da43 100644
--- a/server/AyaNova/Controllers/AuthController.cs
+++ b/server/AyaNova/Controllers/AuthController.cs
@@ -71,6 +71,12 @@ namespace AyaNova.Api.Controllers
//NOTE: lockout or other login impacting state is processed later in ReturnUserCredsOnSuccessfulAuthentication() because many of those states need to have exceptions once the user is known
//or return alternate result of auth etc
+ if (Core.License.LicenseConsentRequired)
+ {
+ await Task.Delay(AyaNova.Util.ServerBootConfig.FAILED_AUTH_DELAY);
+ return StatusCode(401, new ApiErrorResponse(ApiErrorCode.AUTHENTICATION_FAILED, "generalerror", "License agreement consent required"));
+ }
+
if (string.IsNullOrWhiteSpace(creds.Login) || string.IsNullOrWhiteSpace(creds.Password))
{
//Make a failed pw wait
diff --git a/server/AyaNova/Controllers/LicenseController.cs b/server/AyaNova/Controllers/LicenseController.cs
index bcb71b2a..c4f8824b 100644
--- a/server/AyaNova/Controllers/LicenseController.cs
+++ b/server/AyaNova/Controllers/LicenseController.cs
@@ -274,8 +274,31 @@ namespace AyaNova.Api.Controllers
}
+ ///
+ ///
+ ///
+ ///
+ /// HTTP 204 No Content result code on success or fail code with explanation
+ [AllowAnonymous]
+ [HttpPost("lc")]
+ [ApiExplorerSettings(IgnoreApi = true)]
+ public async Task lc([FromBody] string acceptCode)
+ {
+ //END USER LICENSE AGREEMENT ROUTE ONLY CALLED FROM WEBAPP AND HIDDEN FROM VIEW AS A ROUTE
+ //SuperUser only and must have accept code
+ if (string.IsNullOrWhiteSpace(acceptCode) || acceptCode.ToLowerInvariant() != "iaccepttheagreement")
+ return StatusCode(403, new ApiNotAuthorizedResponse());
+
+ await Core.License.FlagEULA(ct, log);
+
+ //Log
+ await EventLogProcessor.LogEventToDatabaseAsync(new Event(1, 0, AyaType.Global, AyaEvent.Modified, "End user license agreement consent obtained"), ct);
+
+ return NoContent();
+ }
+
//------------------------------------------------------
diff --git a/server/AyaNova/Controllers/NotifyController.cs b/server/AyaNova/Controllers/NotifyController.cs
index 6d425e89..f4bed2be 100644
--- a/server/AyaNova/Controllers/NotifyController.cs
+++ b/server/AyaNova/Controllers/NotifyController.cs
@@ -54,9 +54,10 @@ namespace AyaNova.Api.Controllers
var logo = await ct.Logo.AsNoTracking().SingleOrDefaultAsync();
if (logo == null)
{
- return Ok(ApiOkResponse.Response(new { eval = showSampleLogins, ll = false, ml = false, sl = false }));
+ return Ok(ApiOkResponse.Response(new { eval = showSampleLogins, ll = false, ml = false, sl = false, lcr = AyaNova.Core.License.LicenseConsentRequired }));
}
- return Ok(ApiOkResponse.Response(new { eval = showSampleLogins, ll = logo.Large != null ? true : false, ml = logo.Medium != null ? true : false, sl = logo.Small != null ? true : false }));
+ return Ok(ApiOkResponse.Response(
+ new { eval = showSampleLogins, ll = logo.Large != null ? true : false, ml = logo.Medium != null ? true : false, sl = logo.Small != null ? true : false, lcr = AyaNova.Core.License.LicenseConsentRequired }));
}
@@ -69,7 +70,7 @@ namespace AyaNova.Api.Controllers
public async Task GetNewCount()
{
var UserId = UserIdFromContext.Id(HttpContext.Items);
- if (serverState.IsClosed && UserId!=1)//bypass for superuser to fix fundamental problems
+ if (serverState.IsClosed && UserId != 1)//bypass for superuser to fix fundamental problems
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
return Ok(ApiOkResponse.Response(await ct.InAppNotification.CountAsync(z => z.UserId == UserId && z.Fetched == false)));
diff --git a/server/AyaNova/generator/CoreJobLicense.cs b/server/AyaNova/generator/CoreJobLicense.cs
index efb27879..ee1d05d2 100644
--- a/server/AyaNova/generator/CoreJobLicense.cs
+++ b/server/AyaNova/generator/CoreJobLicense.cs
@@ -1,10 +1,7 @@
using System;
-using System.Linq;
using System.Threading.Tasks;
-using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using AyaNova.Models;
-using AyaNova.Core;
using AyaNova.Util;
namespace AyaNova.Biz
diff --git a/server/AyaNova/models/License.cs b/server/AyaNova/models/License.cs
index ebf695a7..7eff4816 100644
--- a/server/AyaNova/models/License.cs
+++ b/server/AyaNova/models/License.cs
@@ -7,6 +7,8 @@ namespace AyaNova.Models
{
public long Id { get; set; }
public string Key { get; set; }
- public string DbId { get; set; }
+ public string DbId { get; set; }
+ public bool LicenseAgree { get; set; }//flag indicating end user license agreement consent
+
}
}
diff --git a/server/AyaNova/util/AySchema.cs b/server/AyaNova/util/AySchema.cs
index d65c78ba..4ff39411 100644
--- a/server/AyaNova/util/AySchema.cs
+++ b/server/AyaNova/util/AySchema.cs
@@ -22,16 +22,16 @@ namespace AyaNova.Util
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImportingAsync WHEN NEW TABLES ADDED!!!!
private const int DESIRED_SCHEMA_LEVEL = 1;
- internal const long EXPECTED_COLUMN_COUNT = 1324;
+ internal const long EXPECTED_COLUMN_COUNT = 1325;
internal const long EXPECTED_INDEX_COUNT = 153;
- internal const long EXPECTED_CHECK_CONSTRAINTS = 519;
+ internal const long EXPECTED_CHECK_CONSTRAINTS = 520;
internal const long EXPECTED_FOREIGN_KEY_CONSTRAINTS = 198;
internal const long EXPECTED_VIEWS = 11;
internal const long EXPECTED_ROUTINES = 2;
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImportingAsync WHEN NEW TABLES ADDED!!!!
- ///////////////////////////////////////// C1324:I153:CC519:FC198:V11:R2
+ ///////////////////////////////////////// C1325:I153:CC520:FC198:V11:R2
@@ -624,7 +624,7 @@ $BODY$ LANGUAGE PLPGSQL STABLE");
await AyaNova.Biz.PrimeData.PrimeSuperUserAccount(ct);
//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, licenseagree BOOL NOT NULL, dbid TEXT, key TEXT NOT NULL)");
await ExecQueryAsync("CREATE TABLE afileattachment (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, "
+ "attachtoobjectid BIGINT NOT NULL, attachtoatype INTEGER NOT NULL, "
diff --git a/server/AyaNova/util/License.cs b/server/AyaNova/util/License.cs
index 3e669105..3bb533ce 100644
--- a/server/AyaNova/util/License.cs
+++ b/server/AyaNova/util/License.cs
@@ -73,6 +73,7 @@ namespace AyaNova.Core
//The license dbid, separate from the server dbid
private static string LicenseDbId { get; set; }
+
#region license classes
//DTO object returned on license query
@@ -184,6 +185,8 @@ namespace AyaNova.Core
}
}
+
+
//Has any kind of valid license that is active
//used for auth route checking to allow for fixing this issue
public bool KeyDoesNotNeedAttention
@@ -257,6 +260,7 @@ namespace AyaNova.Core
public List Features { get; set; }
+
}
#endregion
@@ -302,6 +306,9 @@ namespace AyaNova.Core
//The database id value stored in the schema table
internal static string ServerDbId { get; private set; }
+ internal static bool LicenseConsentRequired { get; private set; }
+
+
///
/// Fetch a summary of the license key for displaying to the end user
///
@@ -443,10 +450,32 @@ namespace AyaNova.Core
}
}
-
-
#endregion
+ #region EULA consent
+ ///
+ /// Set consent flag for license agreement
+ ///
+ internal static async Task FlagEULA(AyContext ct, ILogger log)
+ {
+ try
+ {
+ var CurrentInDbKeyRecord = await ct.License.OrderBy(z => z.Id).FirstOrDefaultAsync();
+ if (CurrentInDbKeyRecord == null)
+ throw new ApplicationException("E1020 - Can't update EULA agreement, no key record found");
+ //Update current license
+ CurrentInDbKeyRecord.LicenseAgree = true;
+ await ct.SaveChangesAsync();
+ }
+ catch (Exception ex)
+ {
+ var msg = "E1020 - Error during EULA agreement flagging";
+ log.LogError(ex, msg);
+ throw new ApplicationException(msg, ex);
+ }
+ LicenseConsentRequired = false;
+ }
+ #endregion
#region Trial license request handling
///
@@ -484,7 +513,7 @@ namespace AyaNova.Core
#endregion trial license request handling
- #region License fetching and handling
+ #region License fetching and handling
public class dtoFetchRequest
{
@@ -657,6 +686,7 @@ namespace AyaNova.Core
ldb = new Models.License();
ldb.DbId = ServerDbId;
ldb.Key = "none";
+ ldb.LicenseAgree = false;
ct.License.Add(ldb);
await ct.SaveChangesAsync();
}
@@ -666,6 +696,7 @@ namespace AyaNova.Core
if (string.IsNullOrWhiteSpace(ldb.DbId))
{
ldb.DbId = ServerDbId;
+ ldb.LicenseAgree = false;
//Convert the no tracking record fetched above to tracking
//this is required because a prior call to initialize before dumping the db would mean the license is still in memory in the context
ct.Entry(ldb).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
@@ -675,10 +706,13 @@ namespace AyaNova.Core
//Get it early and set it here so that it can be displayed early to the user even if not licensed
LicenseDbId = ldb.DbId;
+ //someone must agree to the license on first login from the client, this stores that
+ LicenseConsentRequired = !ldb.LicenseAgree;
+
if (ldb.Key == "none")
{
var msg = "E1020 - License key not found in database, running in unlicensed mode";
- apiServerState.SetSystemLock(msg);
+ apiServerState.SetSystemLock(msg);
log.LogWarning(msg);
return;
}
@@ -790,6 +824,8 @@ namespace AyaNova.Core
}
+
+
#endregion
#region PARSE and Validate key