Commit d1e2352c by Mac Stephens

Add startup version check with ConnectionModule gate and Bootstrap modal reload prompt

parent fbd70441
*.exe *.exe
*.dll
*.bpl *.bpl
*.bpi *.bpi
*.dcp *.dcp
......
object DMConnection: TDMConnection
Height = 256
Width = 337
object ApiConnection: TXDataWebConnection
Left = 48
Top = 80
end
object xdwcApi: TXDataWebClient
Connection = ApiConnection
Left = 187
Top = 84
end
end
unit ConnectionModule;
interface
uses
System.SysUtils, System.Classes,
WEBLib.Modules,
XData.Web.Connection, XData.Web.Client;
type
TVersionCheckCallback = reference to procedure(success: Boolean; errorMessage: string);
TDMConnection = class(TWebDataModule)
ApiConnection: TXDataWebConnection;
xdwcApi: TXDataWebClient;
procedure ApiConnectionError(error: TXDataWebConnectionError);
procedure XDataWebClientError(error: TXDataClientError);
private
configLoaded: Boolean;
versionCheckPending: Boolean;
pendingCallback: TVersionCheckCallback;
procedure LoadConfig(loadedProc: TProc<Boolean>);
public
const clientVersion = '0.1.0';
procedure InitApp(readyProc: TProc);
procedure SetClientConfig(callback: TVersionCheckCallback);
end;
var
DMConnection: TDMConnection;
implementation
uses
JS, Web,
XData.Web.Request,
XData.Web.Response;
{$R *.dfm}
procedure TDMConnection.ApiConnectionError(error: TXDataWebConnectionError);
begin
if versionCheckPending and Assigned(pendingCallback) then
begin
versionCheckPending := False;
pendingCallback(False, 'Unable to reach server to verify version. Please reload.');
pendingCallback := nil;
end;
end;
procedure TDMConnection.XDataWebClientError(error: TXDataClientError);
begin
if versionCheckPending and Assigned(pendingCallback) then
begin
versionCheckPending := False;
pendingCallback(False, 'Unable to verify version. Please reload.');
pendingCallback := nil;
end;
end;
procedure TDMConnection.LoadConfig(loadedProc: TProc<Boolean>);
procedure onSuccess(response: IHttpResponse);
var
obj: TJSObject;
apiUrl: string;
begin
apiUrl := '';
if response.StatusCode = 200 then
begin
obj := TJSObject(TJSJSON.parse(response.ContentAsText));
apiUrl := JS.toString(obj['ApiUrl']);
end;
if apiUrl <> '' then
begin
ApiConnection.URL := apiUrl;
configLoaded := True;
loadedProc(True);
end
else
loadedProc(False);
end;
procedure onError;
begin
loadedProc(False);
end;
var
conn: TXDataWebConnection;
begin
if configLoaded then
begin
loadedProc(True);
Exit;
end;
conn := TXDataWebConnection.Create(nil);
try
conn.SendRequest(THttpRequest.Create('config/config.json'), @onSuccess, @onError);
finally
conn.Free;
end;
end;
procedure TDMConnection.InitApp(readyProc: TProc);
begin
if Assigned(readyProc) then
readyProc;
end;
procedure TDMConnection.SetClientConfig(callback: TVersionCheckCallback);
procedure configLoadedProc(success: Boolean);
begin
if not success then
begin
callback(False, 'Missing or invalid config/config.json (ApiUrl).');
Exit;
end;
pendingCallback := callback;
versionCheckPending := True;
xdwcApi.Connection := ApiConnection;
ApiConnection.Open(
procedure
begin
xdwcApi.RawInvoke('IApiService.VerifyVersion', [clientVersion],
procedure(response: TXDataClientResponse)
var
jsonResult: TJSObject;
errorMsg: string;
begin
versionCheckPending := False;
jsonResult := TJSObject(response.Result);
if Assigned(jsonResult) and jsonResult.HasOwnProperty('error') then
errorMsg := string(jsonResult['error'])
else
errorMsg := '';
if errorMsg <> '' then
pendingCallback(False, errorMsg)
else
pendingCallback(True, '');
pendingCallback := nil;
end);
end);
end;
begin
LoadConfig(@configLoadedProc);
end;
end.
...@@ -11,29 +11,79 @@ uses ...@@ -11,29 +11,79 @@ uses
View.CustomSoftware in 'View.CustomSoftware.pas' {FCustomSoftware: TWebForm} {*.html}, View.CustomSoftware in 'View.CustomSoftware.pas' {FCustomSoftware: TWebForm} {*.html},
View.AboutUs in 'View.AboutUs.pas' {FAboutUs: TWebForm} {*.html}, View.AboutUs in 'View.AboutUs.pas' {FAboutUs: TWebForm} {*.html},
View.ContactUs in 'View.ContactUs.pas' {FContactUs: TWebForm} {*.html}, View.ContactUs in 'View.ContactUs.pas' {FContactUs: TWebForm} {*.html},
Utils in 'Utils.pas'; Utils in 'Utils.pas',
ConnectionModule in 'ConnectionModule.pas' {DMConnection: TWebDataModule};
{$R *.res} {$R *.res}
procedure ShowVersionModal(const errorMessage, clientVer: string);
begin begin
Application.Initialize; asm
Application.MainFormOnTaskbar := True; var dlg = document.createElement("dialog");
dlg.classList.add("shadow", "rounded", "border", "p-4");
dlg.style.maxWidth = "520px";
dlg.style.width = "92%";
dlg.style.fontFamily = "system-ui, sans-serif";
dlg.innerHTML =
"<h5 class='fw-bold mb-3 text-danger'>EM Systems web site</h5>" +
"<p class='mb-3' style='white-space: pre-wrap;'>" + errorMessage + "</p>" +
"<div class='text-end'>" +
"<button id='refreshBtn' class='btn btn-danger'>Reload</button></div>";
document.body.appendChild(dlg);
dlg.showModal();
document.getElementById("refreshBtn").addEventListener("click", function () {
var base = location.origin + location.pathname;
location.replace(base + "?ver=" + clientVer + "&r=" + Date.now() + location.hash);
});
end;
end;
procedure StartRouting;
begin
asm asm
// Set a handler to scroll to top on every hash change
window.addEventListener('hashchange', function() { window.addEventListener('hashchange', function() {
window.scrollTo(0, 0); window.scrollTo(0, 0);
}, false); }, false);
// Ensure navigation to the home form if no hash is present
if (window.location.hash === '') { if (window.location.hash === '') {
window.location.hash = '#FHome'; window.location.hash = '#FHome';
} }
end; end;
if not Application.Route then if not Application.Route then
begin
Application.CreateForm(TFHome, FHome); Application.CreateForm(TFHome, FHome);
end; end;
procedure StartApplication;
var
clientVer: string;
begin
clientVer := TDMConnection.clientVersion;
DMConnection.InitApp(
procedure
begin
DMConnection.SetClientConfig(
procedure(success: Boolean; errorMessage: string)
begin
if success then
StartRouting
else
ShowVersionModal(errorMessage, clientVer);
end
);
end
);
end;
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TDMConnection, DMConnection);
StartApplication;
Application.Run; Application.Run;
end. end.
...@@ -9,6 +9,7 @@ procedure ShowStatusMessage(const AMessage, AClass: string; const AElementId: st ...@@ -9,6 +9,7 @@ procedure ShowStatusMessage(const AMessage, AClass: string; const AElementId: st
procedure HideStatusMessage(const AElementId: string); procedure HideStatusMessage(const AElementId: string);
procedure ShowSpinner(SpinnerID: string); procedure ShowSpinner(SpinnerID: string);
procedure HideSpinner(SpinnerID: string); procedure HideSpinner(SpinnerID: string);
procedure ShowNotificationModal(msg: string);
implementation implementation
...@@ -61,6 +62,13 @@ begin ...@@ -61,6 +62,13 @@ begin
SpinnerElement := TJSHTMLElement(document.getElementById(SpinnerID)); SpinnerElement := TJSHTMLElement(document.getElementById(SpinnerID));
if Assigned(SpinnerElement) then if Assigned(SpinnerElement) then
begin begin
// Move spinner to the <body> if it's not already there
asm
if (SpinnerElement.parentNode !== document.body) {
document.body.appendChild(SpinnerElement);
}
end;
SpinnerElement.classList.remove('d-none'); SpinnerElement.classList.remove('d-none');
SpinnerElement.classList.add('d-block'); SpinnerElement.classList.add('d-block');
end; end;
...@@ -78,4 +86,35 @@ begin ...@@ -78,4 +86,35 @@ begin
end; end;
end; end;
procedure ShowNotificationModal(msg: string);
begin
asm
var modal = document.getElementById('contact_notification_modal');
var label = document.getElementById('contact_notification_modal_body');
var closeBtn = document.getElementById('btn_modal_close');
if (label) label.innerText = msg;
// Ensure modal is a direct child of <body>
if (modal && modal.parentNode !== document.body) {
document.body.appendChild(modal);
}
// Button simply closes the modal
if (closeBtn) {
closeBtn.onclick = function () {
var existing = bootstrap.Modal.getInstance(modal);
if (existing) {
existing.hide();
}
};
}
// Show the Bootstrap modal
var bsModal = new bootstrap.Modal(modal, { keyboard: false });
bsModal.show();
end;
end;
end. end.
...@@ -209,16 +209,10 @@ object FContactUs: TFContactUs ...@@ -209,16 +209,10 @@ object FContactUs: TFContactUs
WidthPercent = 100.000000000000000000 WidthPercent = 100.000000000000000000
OnClick = btnSubmitClick OnClick = btnSubmitClick
end end
object XDataWebConnection1: TXDataWebConnection object xdwcEmail: TXDataWebClient
OnConnect = XDataWebConnection1Connect Connection = DMConnection.ApiConnection
OnError = XDataWebConnection1Error OnError = xdwcEmailError
Left = 209 Left = 412
Top = 492 Top = 512
end
object XDataWebClient1: TXDataWebClient
Connection = XDataWebConnection1
OnError = XDataWebClient1Error
Left = 368
Top = 490
end end
end end
...@@ -120,3 +120,21 @@ ...@@ -120,3 +120,21 @@
<div></div><div></div><div></div><div></div> <div></div><div></div><div></div><div></div>
</div> </div>
</div> </div>
<div class="modal fade" id="contact_notification_modal" tabindex="-1" aria-labelledby="main_lblmodal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content shadow-lg">
<div class="modal-header">
<h5 class="modal-title" id="contact_notification_modal">Info</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body fs-6 fw-bold" id="contact_notification_modal_body">
Please contact EMSystems to solve the issue.
</div>
<div class="modal-footer justify-content-center">
<button type="button" id="btn_modal_close" class="btn btn-primary">Close</button>
</div>
</div>
</div>
</div>
...@@ -6,9 +6,9 @@ uses ...@@ -6,9 +6,9 @@ uses
System.SysUtils, System.Classes, WEBLib.Graphics, WEBLib.Forms, Vcl.StdCtrls, System.SysUtils, System.Classes, WEBLib.Graphics, WEBLib.Forms, Vcl.StdCtrls,
WEBLib.StdCtrls, Vcl.Controls, WEBLib.Dialogs, Vcl.Imaging.pngimage, WEBLib.StdCtrls, Vcl.Controls, WEBLib.Dialogs, Vcl.Imaging.pngimage,
WEBLib.ExtCtrls, WEBLib.Controls, Web, JS, WEBLib.Menus, WEBLib.WebCtrls, WEBLib.ExtCtrls, WEBLib.Controls, Web, JS, WEBLib.Menus, WEBLib.WebCtrls,
XData.Web.Connection, XData.Web.Client, Data.DB, XData.Web.Connection, XData.Web.Client, Data.DB, Utils,
XData.Web.JsonDataset, XData.Web.Dataset, Vcl.Grids, XData.Web.JsonDataset, XData.Web.Dataset, Vcl.Grids,
WEBLib.DBCtrls, WEBLib.DB, WEBLib.Grids, WEBLib.CDS, WEBLib.REST, Utils, WEBLib.DBCtrls, WEBLib.DB, WEBLib.Grids, WEBLib.CDS, WEBLib.REST,
WEBLib.WebTools, System.NetEncoding, WEBLib.RegularExpressions, WEBLib.WebTools, System.NetEncoding, WEBLib.RegularExpressions,
WEBLib.Toast, XData.Web.Request, XData.Web.Response; WEBLib.Toast, XData.Web.Request, XData.Web.Response;
...@@ -26,10 +26,9 @@ type ...@@ -26,10 +26,9 @@ type
edtEmail: TWebEdit; edtEmail: TWebEdit;
edtSubject: TWebEdit; edtSubject: TWebEdit;
memoMessage: TWebMemo; memoMessage: TWebMemo;
XDataWebConnection1: TXDataWebConnection;
XDataWebClient1: TXDataWebClient;
btnSubmit: TWebButton; btnSubmit: TWebButton;
btnPublicSafety: TWebButton; btnPublicSafety: TWebButton;
xdwcEmail: TXDataWebClient;
procedure btnHomeClick(Sender: TObject); procedure btnHomeClick(Sender: TObject);
procedure btnAboutUsClick(Sender: TObject); procedure btnAboutUsClick(Sender: TObject);
...@@ -38,17 +37,15 @@ type ...@@ -38,17 +37,15 @@ type
procedure btnCustomSoftwareClick(Sender: TObject); procedure btnCustomSoftwareClick(Sender: TObject);
procedure btnPublicSafetyClick(Sender: TObject); procedure btnPublicSafetyClick(Sender: TObject);
procedure btnSubmitClick(Sender: TObject); procedure btnSubmitClick(Sender: TObject);
procedure XDataWebConnection1Connect(Sender: TObject);
procedure XDataWebClient1Error(error: TXDataClientError);
procedure XDataWebConnection1Error(error: TXDataWebConnectionError);
procedure WebFormCreate(Sender: TObject); procedure WebFormCreate(Sender: TObject);
procedure WebFormClose(Sender: TObject; var Action: TCloseAction); procedure WebFormClose(Sender: TObject; var Action: TCloseAction);
procedure xdwcEmailError(Error: TXDataClientError);
private private
{ Private declarations } { Private declarations }
function IsInputValid: Boolean; function IsInputValid: Boolean;
function IsEmailValid(AEmail: String): Boolean; function IsEmailValid(const email: String): Boolean;
[async] procedure SendEmail; [async] procedure SendEmail;
[async] procedure InitializeConnection;
public public
procedure NavScrollSizing; procedure NavScrollSizing;
end; end;
...@@ -61,43 +58,29 @@ implementation ...@@ -61,43 +58,29 @@ implementation
{$R *.dfm} {$R *.dfm}
uses uses
View.AboutUs, ConnectionModule,
View.Home, View.Home,
View.CustomSoftware, View.PublicSafety,
View.PublicSafety, View.RecordsManagement,
View.RecordsManagement; View.CustomSoftware,
View.AboutUs;
procedure TFContactUs.WebFormCreate(Sender: TObject); procedure TFContactUs.WebFormCreate(Sender: TObject);
begin begin
Application.ThemeColor := clTMSWEB; Application.ThemeColor := clTMSWEB;
NavScrollSizing; NavScrollSizing;
InitializeConnection;
end; end;
[async] procedure TFContactUs.InitializeConnection;
var
Conn: TXDataWebConnection;
Resp: IHttpResponse;
Obj: TJSObject;
begin
try
Conn := TXDataWebConnection.Create(nil);
Resp := await(Conn.SendRequestAsync(THttpRequest.Create('config/config.json')));
Obj := TJSObject(TJSJSON.parse(Resp.ContentAsText));
XDataWebConnection1.URL := string(Obj['ApiUrl']);
XDataWebClient1.Connection := XDataWebConnection1;
console.log('XData connection initialized with URL: ', XDataWebConnection1.URL); procedure TFContactUs.xdwcEmailError(Error: TXDataClientError);
except begin
on E: Exception do ShowNotificationModal('Error when attempting to send: ' + error.ErrorMessage);
begin
ShowMessage('Failed to load configuration or initialize XData: ' + E.Message);
end;
end;
end; end;
procedure TFContactUs.WebFormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
procedure TFContactUs.NavScrollSizing; procedure TFContactUs.NavScrollSizing;
begin begin
...@@ -105,7 +88,7 @@ begin ...@@ -105,7 +88,7 @@ begin
window.addEventListener('scroll', function() { window.addEventListener('scroll', function() {
var navbar = document.querySelector('.em-navbar-wrap .navbar'); var navbar = document.querySelector('.em-navbar-wrap .navbar');
var logo = document.querySelector('.em-brand img'); var logo = document.querySelector('.em-brand img');
var scrollDistance = 50; // Adjust based on your preference var scrollDistance = 50;
if (window.scrollY > scrollDistance) { if (window.scrollY > scrollDistance) {
navbar.classList.add('scrolled'); navbar.classList.add('scrolled');
...@@ -118,132 +101,99 @@ begin ...@@ -118,132 +101,99 @@ begin
end; end;
end; end;
procedure TFContactUs.btnSubmitClick(Sender: TObject); function TFContactUs.IsEmailValid(const email: string): Boolean;
begin
if IsInputValid then
begin
XDataWebConnection1.Connected := True;
end
else
ShowMessage('Please complete all fields and ensure the email address is valid.');
end;
function TFContactUs.IsEmailValid(AEmail: String): Boolean;
const const
CPattern = '^\w+([\.-]?w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$'; pattern = '^[^\s@]+@[^\s@]+\.[^\s@]+$';
begin begin
Result := TRegEx.IsMatch( AEmail, CPattern ); Result := TRegEx.IsMatch(email.Trim, pattern);
end; end;
function TFContactUs.IsInputValid: Boolean; function TFContactUs.IsInputValid: Boolean;
var var
LEmailValid: Boolean; nameOk: Boolean;
LComplete: Boolean; emailOk: Boolean;
subjectOk: Boolean;
messageOk: Boolean;
begin begin
LEmailValid := IsEmailValid( edtEmail.Text ); nameOk := edtName.Text.Trim <> '';
emailOk := IsEmailValid(edtEmail.Text);
LComplete := (edtName.Text <> '') and subjectOk := edtSubject.Text.Trim <> '';
(edtSubject.Text <> '') and messageOk := memoMessage.Text.Trim <> '';
(edtEmail.Text <> '');
Result := LEmailValid and LComplete;
Result := nameOk and emailOk and subjectOk and messageOk;
end; end;
procedure TFContactUs.btnSubmitClick(Sender: TObject);
procedure TFContactUs.XDataWebConnection1Error(error: TXDataWebConnectionError);
begin
ShowMessage('Error Connecting to XData Server');
end;
procedure TFContactUs.XDataWebConnection1Connect(Sender: TObject);
begin begin
console.log('Connected to XData server, Sending Email'); if not IsInputValid then
SendEmail(); begin
end; ShowNotificationModal('Please complete all fields and ensure the email address is valid.');
Exit;
end;
if not DMConnection.ApiConnection.Connected then
begin
DMConnection.ApiConnection.Open(
procedure
begin
SendEmail;
end);
Exit;
end;
procedure TFContactUs.XDataWebClient1Error(Error: TXDataClientError); SendEmail;
begin
console.log('Error: ', Error.ErrorMessage, ' RequestId: ', Error.RequestId, ' Code: ', Error.ErrorCode, ' Request Url: ', Error.RequestUrl);
end; end;
procedure TFContactUs.SendEmail; procedure TFContactUs.SendEmail;
var
xdcResponse: TXDataClientResponse;
begin begin
try xdwcEmail.RawInvoke('IApiService.SendEmail',
xdcResponse := await(XDataWebClient1.RawInvokeAsync('IApiService.SendEmail', [edtName.Text, edtEmail.Text, edtSubject.Text, memoMessage.Text],
[edtName.Text, edtEmail.Text, edtSubject.Text, memoMessage.Text])); procedure(response: TXDataClientResponse)
ShowMessage('Your message has been sent successfully. Please check your email for a response in the next 48 hours.'); begin
// Clears the input fields after successful email sending ShowNotificationModal('Your message has been sent successfully. Please check your email for a response in the next 48 hours.');
edtName.Text := ''; edtName.Text := '';
edtEmail.Text := ''; edtEmail.Text := '';
edtSubject.Text := ''; edtSubject.Text := '';
memoMessage.Text := ''; memoMessage.Text := '';
// Disconnects after sending the email end);
XDataWebConnection1.Connected := False;
except
on E: EXDataClientRequestException do
begin
ShowMessage('Error when attempting to send: ' + E.Message);
// Optionally disconnect even on error if you intend to reset the connection state
XDataWebConnection1.Connected := False;
end;
end;
end; end;
procedure TFContactUs.WebFormClose(Sender: TObject; var Action: TCloseAction); procedure TFContactUs.btnHomeClick(Sender: TObject);
begin begin
Action := caFree; Close;
Application.CreateForm(TFHome, FHome);
end; end;
procedure TFContactUs.btnPublicSafetyClick(Sender: TObject);
procedure TFContactUs.btnCustomSoftwareClick(Sender: TObject);
begin begin
Close; Close;
Application.CreateForm(TFCustomSoftware, FCustomSoftware); Application.CreateForm(TFPublicSafety, FPublicSafety);
end; end;
procedure TFContactUs.btnRecordsManagementClick(Sender: TObject); procedure TFContactUs.btnRecordsManagementClick(Sender: TObject);
begin begin
Close; Close;
Application.CreateForm(TFRecordsManagement, FRecordsManagement); Application.CreateForm(TFRecordsManagement, FRecordsManagement);
end; end;
procedure TFContactUs.btnCustomSoftwareClick(Sender: TObject);
procedure TFContactUs.btnPublicSafetyClick(Sender: TObject);
begin
Close;
Application.CreateForm(TFPublicSafety, FPublicSafety);
end;
procedure TFContactUs.btnContactUsClick(Sender: TObject);
begin begin
Close; Close;
Application.CreateForm(TFContactUs, FContactUs); Application.CreateForm(TFCustomSoftware, FCustomSoftware);
end; end;
procedure TFContactUs.btnAboutUsClick(Sender: TObject); procedure TFContactUs.btnAboutUsClick(Sender: TObject);
begin begin
Close; Close;
Application.CreateForm(TFAboutUs, FAboutUs); Application.CreateForm(TFAboutUs, FAboutUs);
end; end;
procedure TFContactUs.btnContactUsClick(Sender: TObject);
procedure TFContactUs.btnHomeClick(Sender: TObject);
begin begin
Close; Close;
Application.CreateForm(TFHome, FHome); Application.CreateForm(TFContactUs, FContactUs);
end; end;
initialization initialization
RegisterClass(TFContactUs); RegisterClass(TFContactUs);
......
...@@ -131,3 +131,5 @@ ...@@ -131,3 +131,5 @@
© 2011-2024 EM Systems Inc © 2011-2024 EM Systems Inc
</div> </div>
</footer> </footer>
...@@ -132,6 +132,11 @@ ...@@ -132,6 +132,11 @@
<DesignClass>TWebForm</DesignClass> <DesignClass>TWebForm</DesignClass>
</DCCReference> </DCCReference>
<DCCReference Include="Utils.pas"/> <DCCReference Include="Utils.pas"/>
<DCCReference Include="ConnectionModule.pas">
<Form>DMConnection</Form>
<FormType>dfm</FormType>
<DesignClass>TWebDataModule</DesignClass>
</DCCReference>
<None Include="css\App.css"/> <None Include="css\App.css"/>
<None Include="images\job-gcdf1cf1d3_1920-1536x925.jpg"> <None Include="images\job-gcdf1cf1d3_1920-1536x925.jpg">
<ResourceType>RCDATA</ResourceType> <ResourceType>RCDATA</ResourceType>
...@@ -224,7 +229,7 @@ ...@@ -224,7 +229,7 @@
<DeployFile LocalName="Win32\Debug\EMSystemsWebsite.exe" Configuration="Debug" Class="ProjectOutput"/> <DeployFile LocalName="Win32\Debug\EMSystemsWebsite.exe" Configuration="Debug" Class="ProjectOutput"/>
<DeployFile LocalName="Win32\Debug\EMSystemsWebsite.exe" Configuration="Debug" Class="ProjectOutput"> <DeployFile LocalName="Win32\Debug\EMSystemsWebsite.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32"> <Platform Name="Win32">
<RemoteName>EMSystemsWebsite.exe</RemoteName> <RemoteName>emSystemsWebsite.exe</RemoteName>
<Overwrite>true</Overwrite> <Overwrite>true</Overwrite>
</Platform> </Platform>
</DeployFile> </DeployFile>
......
[Settings] [Settings]
memoLogLevel=3 memoLogLevel=3
fileLogLevel=4 fileLogLevel=4
LogFileNum=10 LogFileNum=12
webClientVersion=0.1.1
[SMTP] [SMTP]
Host=mail.em-sys.net Host=mail.em-sys.net
......
[2026-01-14 15:16:07.252][1] --- Initialization Timer Triggered ---
[2026-01-14 15:16:07.254][1] Exe version: 1.0.0.0
[2026-01-14 15:16:07.260][1] --TServerConfig.Create - start
[2026-01-14 15:16:07.271][1] --TServerConfig.Create - end
[2026-01-14 15:16:07.287][1] --LoadServerConfig - start
[2026-01-14 15:16:07.289][1] -- Config file: serverconfig.json
[2026-01-14 15:16:07.300][1] -- Config file found.
[2026-01-14 15:16:07.307][1] --TServerConfig.Create - start
[2026-01-14 15:16:07.315][1] --TServerConfig.Create - end
[2026-01-14 15:16:07.324][1] -- localConfig loaded from config file
[2026-01-14 15:16:07.332][1] -- serverConfig.Free - called
[2026-01-14 15:16:07.339][1] -- serverConfig := localConfig - called
[2026-01-14 15:16:07.350][1] -------------------------------------------------------------
[2026-01-14 15:16:07.357][1] -- serverConfig.Server url: http://localhost:2002/website/
[2026-01-14 15:16:07.367][1] -- serverConfig.adminPassword: whatisthisusedfor
[2026-01-14 15:16:07.376][1] -- serverConfig.jwtTokenSecret: super_secret0123super_secret4567
[2026-01-14 15:16:07.387][1] -- serverConfig.webAppFolder: static
[2026-01-14 15:16:07.395][1] --LoadServerConfig - end
[2026-01-14 15:16:07.415][1] ******************************************************
[2026-01-14 15:16:07.423][1] emWebsite XData Server
[2026-01-14 15:16:07.432][1] Version: 1.0.0.0
[2026-01-14 15:16:07.442][1] by EM Systems, Inc.
[2026-01-14 15:16:07.452][1] ******************************************************
[2026-01-14 15:16:07.476][1] --- StartApiServer: Initializing ---
[2026-01-14 15:16:07.527][1] XData Server started at: http://localhost:2002/website/
[2026-01-14 15:16:07.529][1] --- StartApiServer: Complete ---
[2026-01-14 15:16:07.543][1] API Server started at: http://localhost:2002/website/
[2026-01-14 15:16:07.568][1] App server module listening at "http://localhost:2002/website/app", rootDir: static
[2026-01-14 15:16:07.583][1] App Server started at: http://localhost:2002/website/app
[2026-01-14 15:16:07.592][1] --- StartServer: Complete ---
[2026-01-14 16:27:34.851][1] --- Initialization Timer Triggered ---
[2026-01-14 16:27:34.860][1] Exe version: 1.0.0.0
[2026-01-14 16:27:34.869][1] --TServerConfig.Create - start
[2026-01-14 16:27:34.876][1] --TServerConfig.Create - end
[2026-01-14 16:27:34.887][1] --LoadServerConfig - start
[2026-01-14 16:27:34.899][1] -- Config file: serverconfig.json
[2026-01-14 16:27:34.906][1] -- Config file found.
[2026-01-14 16:27:34.916][1] --TServerConfig.Create - start
[2026-01-14 16:27:34.927][1] --TServerConfig.Create - end
[2026-01-14 16:27:34.936][1] -- localConfig loaded from config file
[2026-01-14 16:27:34.948][1] -- serverConfig.Free - called
[2026-01-14 16:27:34.958][1] -- serverConfig := localConfig - called
[2026-01-14 16:27:34.969][1] -------------------------------------------------------------
[2026-01-14 16:27:34.982][1] -- serverConfig.Server url: http://localhost:2002/website/
[2026-01-14 16:27:34.990][1] -- serverConfig.adminPassword: whatisthisusedfor
[2026-01-14 16:27:34.998][1] -- serverConfig.jwtTokenSecret: super_secret0123super_secret4567
[2026-01-14 16:27:35.007][1] -- serverConfig.webAppFolder: static
[2026-01-14 16:27:35.017][1] --LoadServerConfig - end
[2026-01-14 16:27:35.035][1] ******************************************************
[2026-01-14 16:27:35.044][1] emWebsite XData Server
[2026-01-14 16:27:35.056][1] Version: 1.0.0.0
[2026-01-14 16:27:35.064][1] by EM Systems, Inc.
[2026-01-14 16:27:35.077][1] ******************************************************
[2026-01-14 16:27:35.095][1] --- StartApiServer: Initializing ---
[2026-01-14 16:27:35.151][1] XData Server started at: http://localhost:2002/website/
[2026-01-14 16:27:35.151][1] --- StartApiServer: Complete ---
[2026-01-14 16:27:35.161][1] API Server started at: http://localhost:2002/website/
[2026-01-14 16:27:35.202][1] App server module listening at "http://localhost:2002/website/app", rootDir: static
[2026-01-14 16:27:35.202][1] App Server started at: http://localhost:2002/website/app
[2026-01-14 16:27:35.214][1] --- StartServer: Complete ---
[2026-01-14 16:27:48.874][2] VerifyVersion: client=0.1.0 server= mismatch=False
[2026-01-14 15:19:58.305][1] --- Initialization Timer Triggered ---
[2026-01-14 15:19:58.314][1] Exe version: 1.0.0.0
[2026-01-14 15:19:58.317][1] --TServerConfig.Create - start
[2026-01-14 15:19:58.327][1] --TServerConfig.Create - end
[2026-01-14 15:19:58.335][1] --LoadServerConfig - start
[2026-01-14 15:19:58.349][1] -- Config file: serverconfig.json
[2026-01-14 15:19:58.353][1] -- Config file found.
[2026-01-14 15:19:58.359][1] --TServerConfig.Create - start
[2026-01-14 15:19:58.375][1] --TServerConfig.Create - end
[2026-01-14 15:19:58.384][1] -- localConfig loaded from config file
[2026-01-14 15:19:58.391][1] -- serverConfig.Free - called
[2026-01-14 15:19:58.398][1] -- serverConfig := localConfig - called
[2026-01-14 15:19:58.405][1] -------------------------------------------------------------
[2026-01-14 15:19:58.412][1] -- serverConfig.Server url: http://localhost:2002/website/
[2026-01-14 15:19:58.419][1] -- serverConfig.adminPassword: whatisthisusedfor
[2026-01-14 15:19:58.427][1] -- serverConfig.jwtTokenSecret: super_secret0123super_secret4567
[2026-01-14 15:19:58.436][1] -- serverConfig.webAppFolder: static
[2026-01-14 15:19:58.447][1] --LoadServerConfig - end
[2026-01-14 15:19:58.462][1] ******************************************************
[2026-01-14 15:19:58.471][1] emWebsite XData Server
[2026-01-14 15:19:58.478][1] Version: 1.0.0.0
[2026-01-14 15:19:58.487][1] by EM Systems, Inc.
[2026-01-14 15:19:58.497][1] ******************************************************
[2026-01-14 15:19:58.516][1] --- StartApiServer: Initializing ---
[2026-01-14 15:19:58.570][1] XData Server started at: http://localhost:2002/website/
[2026-01-14 15:19:58.572][1] --- StartApiServer: Complete ---
[2026-01-14 15:19:58.582][1] API Server started at: http://localhost:2002/website/
[2026-01-14 15:19:58.611][1] App server module listening at "http://localhost:2002/website/app", rootDir: static
[2026-01-14 15:19:58.622][1] App Server started at: http://localhost:2002/website/app
[2026-01-14 15:19:58.633][1] --- StartServer: Complete ---
[2026-01-14 16:31:20.130][1] --- Initialization Timer Triggered ---
[2026-01-14 16:31:20.154][1] Exe version: 1.0.0.0
[2026-01-14 16:31:20.158][1] --TServerConfig.Create - start
[2026-01-14 16:31:20.170][1] --TServerConfig.Create - end
[2026-01-14 16:31:20.180][1] --LoadServerConfig - start
[2026-01-14 16:31:20.192][1] -- Config file: serverconfig.json
[2026-01-14 16:31:20.208][1] -- Config file found.
[2026-01-14 16:31:20.221][1] --TServerConfig.Create - start
[2026-01-14 16:31:20.232][1] --TServerConfig.Create - end
[2026-01-14 16:31:20.239][1] -- localConfig loaded from config file
[2026-01-14 16:31:20.251][1] -- serverConfig.Free - called
[2026-01-14 16:31:20.259][1] -- serverConfig := localConfig - called
[2026-01-14 16:31:20.267][1] -------------------------------------------------------------
[2026-01-14 16:31:20.282][1] -- serverConfig.Server url: http://localhost:2002/website/
[2026-01-14 16:31:20.286][1] -- serverConfig.adminPassword: whatisthisusedfor
[2026-01-14 16:31:20.296][1] -- serverConfig.jwtTokenSecret: super_secret0123super_secret4567
[2026-01-14 16:31:20.304][1] -- serverConfig.webAppFolder: static
[2026-01-14 16:31:20.315][1] --LoadServerConfig - end
[2026-01-14 16:31:20.336][1] ******************************************************
[2026-01-14 16:31:20.349][1] emWebsite XData Server
[2026-01-14 16:31:20.360][1] Version: 1.0.0.0
[2026-01-14 16:31:20.369][1] by EM Systems, Inc.
[2026-01-14 16:31:20.380][1] ******************************************************
[2026-01-14 16:31:20.399][1] --- StartApiServer: Initializing ---
[2026-01-14 16:31:20.460][1] XData Server started at: http://localhost:2002/website/
[2026-01-14 16:31:20.462][1] --- StartApiServer: Complete ---
[2026-01-14 16:31:20.472][1] API Server started at: http://localhost:2002/website/
[2026-01-14 16:31:20.506][1] App server module listening at "http://localhost:2002/website/app", rootDir: static
[2026-01-14 16:31:20.509][1] App Server started at: http://localhost:2002/website/app
[2026-01-14 16:31:20.522][1] --- StartServer: Complete ---
[2026-01-14 16:31:32.520][1] Contact form submitted. Name: Mac, Email: mac@em-sys.net, Subject: Test Subject, Message: testmessage
[2026-01-14 16:33:27.606][2] VerifyVersion: client=0.1.0 server= mismatch=False
[2026-01-14 16:43:34.930][2] VerifyVersion: client=0.1.0 server= mismatch=False
[2026-01-14 16:43:55.931][1] Contact form submitted. Name: mac, Email: mac@em-sys.net, Subject: test3, Message: test3
[2026-01-14 16:48:02.149][2] VerifyVersion: client=0.1.0 server= mismatch=False
[2026-01-14 16:48:15.513][1] Contact form submitted. Name: Mac, Email: mac@em-sys.net, Subject: test4, Message: test4
[2026-01-14 16:49:42.682][2] VerifyVersion: client=0.1.0 server=0.1.1 mismatch=True
[2026-01-14 16:49:45.939][2] VerifyVersion: client=0.1.0 server=0.1.1 mismatch=True
[2026-01-14 15:21:18.212][1] --- Initialization Timer Triggered ---
[2026-01-14 15:21:18.214][1] Exe version: 1.0.0.0
[2026-01-14 15:21:18.226][1] --TServerConfig.Create - start
[2026-01-14 15:21:18.234][1] --TServerConfig.Create - end
[2026-01-14 15:21:18.245][1] --LoadServerConfig - start
[2026-01-14 15:21:18.251][1] -- Config file: serverconfig.json
[2026-01-14 15:21:18.259][1] -- Config file found.
[2026-01-14 15:21:18.271][1] --TServerConfig.Create - start
[2026-01-14 15:21:18.277][1] --TServerConfig.Create - end
[2026-01-14 15:21:18.286][1] -- localConfig loaded from config file
[2026-01-14 15:21:18.291][1] -- serverConfig.Free - called
[2026-01-14 15:21:18.300][1] -- serverConfig := localConfig - called
[2026-01-14 15:21:18.307][1] -------------------------------------------------------------
[2026-01-14 15:21:18.316][1] -- serverConfig.Server url: http://localhost:2002/website/
[2026-01-14 15:21:18.322][1] -- serverConfig.adminPassword: whatisthisusedfor
[2026-01-14 15:21:18.331][1] -- serverConfig.jwtTokenSecret: super_secret0123super_secret4567
[2026-01-14 15:21:18.333][1] -- serverConfig.webAppFolder: static
[2026-01-14 15:21:18.342][1] --LoadServerConfig - end
[2026-01-14 15:21:18.363][1] ******************************************************
[2026-01-14 15:21:18.370][1] emWebsite XData Server
[2026-01-14 15:21:18.376][1] Version: 1.0.0.0
[2026-01-14 15:21:18.387][1] by EM Systems, Inc.
[2026-01-14 15:21:18.395][1] ******************************************************
[2026-01-14 15:21:18.416][1] --- StartApiServer: Initializing ---
[2026-01-14 15:21:18.460][1] XData Server started at: http://localhost:2002/website/
[2026-01-14 15:21:18.469][1] --- StartApiServer: Complete ---
[2026-01-14 15:21:18.476][1] API Server started at: http://localhost:2002/website/
[2026-01-14 15:21:18.521][1] App server module listening at "http://localhost:2002/website/app", rootDir: static
[2026-01-14 15:21:18.521][1] App Server started at: http://localhost:2002/website/app
[2026-01-14 15:21:18.536][1] --- StartServer: Complete ---
[2026-01-14 15:27:38.658][1] --- Initialization Timer Triggered ---
[2026-01-14 15:27:38.664][1] Exe version: 1.0.0.0
[2026-01-14 15:27:38.678][1] --TServerConfig.Create - start
[2026-01-14 15:27:38.688][1] --TServerConfig.Create - end
[2026-01-14 15:27:38.701][1] --LoadServerConfig - start
[2026-01-14 15:27:38.715][1] -- Config file: serverconfig.json
[2026-01-14 15:27:38.726][1] -- Config file found.
[2026-01-14 15:27:38.734][1] --TServerConfig.Create - start
[2026-01-14 15:27:38.746][1] --TServerConfig.Create - end
[2026-01-14 15:27:38.762][1] -- localConfig loaded from config file
[2026-01-14 15:27:38.765][1] -- serverConfig.Free - called
[2026-01-14 15:27:38.779][1] -- serverConfig := localConfig - called
[2026-01-14 15:27:38.781][1] -------------------------------------------------------------
[2026-01-14 15:27:38.783][1] -- serverConfig.Server url: http://localhost:2002/website/
[2026-01-14 15:27:38.785][1] -- serverConfig.adminPassword: whatisthisusedfor
[2026-01-14 15:27:38.795][1] -- serverConfig.jwtTokenSecret: super_secret0123super_secret4567
[2026-01-14 15:27:38.804][1] -- serverConfig.webAppFolder: static
[2026-01-14 15:27:38.819][1] --LoadServerConfig - end
[2026-01-14 15:27:38.839][1] ******************************************************
[2026-01-14 15:27:38.858][1] emWebsite XData Server
[2026-01-14 15:27:38.872][1] Version: 1.0.0.0
[2026-01-14 15:27:38.891][1] by EM Systems, Inc.
[2026-01-14 15:27:38.902][1] ******************************************************
[2026-01-14 15:27:38.916][1] --- StartApiServer: Initializing ---
[2026-01-14 15:27:38.989][1] XData Server started at: http://localhost:2002/website/
[2026-01-14 15:27:38.989][1] --- StartApiServer: Complete ---
[2026-01-14 15:27:39.013][1] API Server started at: http://localhost:2002/website/
[2026-01-14 15:27:39.085][1] App server module listening at "http://localhost:2002/website/app", rootDir: static
[2026-01-14 15:27:39.101][1] App Server started at: http://localhost:2002/website/app
[2026-01-14 15:27:39.116][1] --- StartServer: Complete ---
[2026-01-14 16:00:07.088][2] VerifyVersion: client=0.1.0 server=0.1.1 mismatch=True
[2026-01-14 16:00:11.648][2] VerifyVersion: client=0.1.0 server=0.1.1 mismatch=True
[2026-01-14 16:00:29.157][2] VerifyVersion: client=0.1.0 server=0.1.0 mismatch=False
[2026-01-14 16:17:07.622][2] VerifyVersion: client=0.1.0 server=0.1.0 mismatch=False
[2026-01-14 16:17:32.669][2] VerifyVersion: client=0.1.0 server=0.1.0 mismatch=False
[2026-01-14 16:25:28.559][2] VerifyVersion: client=0.1.0 server= mismatch=False
...@@ -3,13 +3,14 @@ unit Api.Service; ...@@ -3,13 +3,14 @@ unit Api.Service;
interface interface
uses uses
XData.Service.Common; XData.Service.Common, System.JSON;
type type
[ServiceContract] [ServiceContract]
IApiService = interface(IInvokable) IApiService = interface(IInvokable)
['{46B3B095-5873-4452-B338-AEE009604DED}'] ['{46B3B095-5873-4452-B338-AEE009604DED}']
[HttpGet] function SendEmail(Name, Email, Subject, Body: string): string; [HttpGet] function SendEmail(Name, Email, Subject, Body: string): string;
[HttpGet] function VerifyVersion(ClientVersion: string): TJSONObject;
end; end;
implementation implementation
......
...@@ -8,7 +8,7 @@ uses ...@@ -8,7 +8,7 @@ uses
IdSMTP, IdMessage, IdSSLOpenSSL, IdText, IdExplicitTLSClientServerBase, IdSMTP, IdMessage, IdSSLOpenSSL, IdText, IdExplicitTLSClientServerBase,
IdIOHandlerSocket, IdException, IdSSL, IdSMTPBase, IdGlobal, IdStack, IdWinsock2, IdIOHandlerSocket, IdException, IdSSL, IdSMTPBase, IdGlobal, IdStack, IdWinsock2,
IdStackConsts, IdIOHandler, IdIOHandlerStack, IdBaseComponent, IdStackConsts, IdIOHandler, IdIOHandlerStack, IdBaseComponent, System.JSON,
IdComponent, IdTCPConnection, IdTCPClient, IdMessageClient, VCL.Forms, Api.Service; IdComponent, IdTCPConnection, IdTCPClient, IdMessageClient, VCL.Forms, Api.Service;
type type
...@@ -16,6 +16,7 @@ type ...@@ -16,6 +16,7 @@ type
TApiService = class(TInterfacedObject, IApiService) TApiService = class(TInterfacedObject, IApiService)
public public
function SendEmail(Name, Email, Subject, Body: string): string; function SendEmail(Name, Email, Subject, Body: string): string;
function VerifyVersion(ClientVersion: string): TJSONObject;
end; end;
implementation implementation
...@@ -97,6 +98,36 @@ begin ...@@ -97,6 +98,36 @@ begin
end; end;
function TApiService.VerifyVersion(ClientVersion: string): TJSONObject;
var
iniFile: TIniFile;
iniPath: string;
webClientVersion: string;
errorMsg: string;
begin
iniPath := ChangeFileExt(Application.ExeName, '.ini');
iniFile := TIniFile.Create(iniPath);
try
webClientVersion := iniFile.ReadString('Settings', 'webClientVersion', '');
finally
iniFile.Free;
end;
errorMsg := '';
if (webClientVersion <> '') and (ClientVersion <> webClientVersion) then
errorMsg := Format('Client version mismatch. Server expects %s but client is %s.',
[webClientVersion, ClientVersion]);
Result := TJSONObject.Create;
Result.AddPair('webClientVersion', webClientVersion);
if errorMsg <> '' then
Result.AddPair('error', errorMsg);
Logger.Log(2, Format('VerifyVersion: client=%s server=%s mismatch=%s',
[ClientVersion, webClientVersion, BoolToStr(errorMsg <> '', True)]));
end;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment