Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
emiMobile
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Mac Stephens
emiMobile
Commits
4a520774
You need to sign in or sign up before continuing.
Commit
4a520774
authored
Sep 16, 2026
by
Michael Brachmann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
unrevoke a revoked device
parent
8fc67879
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
90 additions
and
1 deletions
+90
-1
Api.Service.pas
emiMobileServer/Source/Api.Service.pas
+1
-0
Api.ServiceImpl.pas
emiMobileServer/Source/Api.ServiceImpl.pas
+52
-0
View.DeviceManager.pas
webEMIMobile/View.DeviceManager.pas
+37
-1
No files found.
emiMobileServer/Source/Api.Service.pas
View file @
4a520774
...
@@ -34,6 +34,7 @@ type
...
@@ -34,6 +34,7 @@ type
// Device management — requires valid JWT; caller must also have user_admin = true
// Device management — requires valid JWT; caller must also have user_admin = true
[
HttpGet
]
function
GetDeviceList
:
TDeviceList
;
[
HttpGet
]
function
GetDeviceList
:
TDeviceList
;
function
RevokeDevice
(
const
CredentialId
:
string
):
TJSONObject
;
function
RevokeDevice
(
const
CredentialId
:
string
):
TJSONObject
;
function
UnrevokeDevice
(
const
CredentialId
:
string
):
TJSONObject
;
function
AddPendingDevice
(
const
DeviceName
,
PhoneNumber
:
string
):
TJSONObject
;
function
AddPendingDevice
(
const
DeviceName
,
PhoneNumber
:
string
):
TJSONObject
;
function
DeletePendingDevice
(
const
PhoneNumber
:
string
):
TJSONObject
;
function
DeletePendingDevice
(
const
PhoneNumber
:
string
):
TJSONObject
;
function
SendAppLink
(
const
PhoneNumber
:
string
):
TJSONObject
;
function
SendAppLink
(
const
PhoneNumber
:
string
):
TJSONObject
;
...
...
emiMobileServer/Source/Api.ServiceImpl.pas
View file @
4a520774
...
@@ -40,6 +40,7 @@ type
...
@@ -40,6 +40,7 @@ type
function
GetComplaintMemos
(
const
CfsId
:
string
):
TJSONObject
;
function
GetComplaintMemos
(
const
CfsId
:
string
):
TJSONObject
;
function
GetDeviceList
:
TDeviceList
;
function
GetDeviceList
:
TDeviceList
;
function
RevokeDevice
(
const
CredentialId
:
string
):
TJSONObject
;
function
RevokeDevice
(
const
CredentialId
:
string
):
TJSONObject
;
function
UnrevokeDevice
(
const
CredentialId
:
string
):
TJSONObject
;
function
AddPendingDevice
(
const
DeviceName
,
PhoneNumber
:
string
):
TJSONObject
;
function
AddPendingDevice
(
const
DeviceName
,
PhoneNumber
:
string
):
TJSONObject
;
function
DeletePendingDevice
(
const
PhoneNumber
:
string
):
TJSONObject
;
function
DeletePendingDevice
(
const
PhoneNumber
:
string
):
TJSONObject
;
function
SendAppLink
(
const
PhoneNumber
:
string
):
TJSONObject
;
function
SendAppLink
(
const
PhoneNumber
:
string
):
TJSONObject
;
...
@@ -1478,6 +1479,57 @@ begin
...
@@ -1478,6 +1479,57 @@ begin
end
;
end
;
function
TApiService
.
UnrevokeDevice
(
const
CredentialId
:
string
):
TJSONObject
;
var
conn
:
TUniConnection
;
q
:
TUniQuery
;
begin
RequireAdmin
;
Result
:=
TJSONObject
.
Create
;
TXDataOperationContext
.
Current
.
Handler
.
ManagedObjects
.
Add
(
Result
);
if
Trim
(
CredentialId
)
=
''
then
begin
Result
.
AddPair
(
'status'
,
'error'
);
Result
.
AddPair
(
'message'
,
'CredentialId is required.'
);
Exit
;
end
;
Logger
.
Log
(
2
,
'TApiService.UnrevokeDevice - credId: '
+
Copy
(
CredentialId
,
1
,
20
));
conn
:=
OpenLemsConnection
;
try
q
:=
TUniQuery
.
Create
(
nil
);
try
q
.
Connection
:=
conn
;
q
.
SQL
.
Text
:=
'UPDATE lems.device_registrations '
+
'SET revoked_at = NULL, revoked_by = NULL, status = ''active'' '
+
'WHERE credential_id = :CID AND status = ''revoked'''
;
q
.
ParamByName
(
'CID'
).
AsString
:=
Trim
(
CredentialId
);
q
.
ExecSQL
;
if
q
.
RowsAffected
>
0
then
begin
Logger
.
Log
(
2
,
'TApiService.UnrevokeDevice - restored: '
+
Copy
(
CredentialId
,
1
,
20
));
Result
.
AddPair
(
'status'
,
'ok'
);
Result
.
AddPair
(
'message'
,
'Device access restored.'
);
end
else
begin
Logger
.
Log
(
2
,
'TApiService.UnrevokeDevice - not found or not revoked: '
+
Copy
(
CredentialId
,
1
,
20
));
Result
.
AddPair
(
'status'
,
'error'
);
Result
.
AddPair
(
'message'
,
'Device not found or not revoked.'
);
end
;
finally
q
.
Free
;
end
;
finally
conn
.
Free
;
end
;
end
;
function
NormalizePhoneE164Api
(
const
APhone
:
string
):
string
;
function
NormalizePhoneE164Api
(
const
APhone
:
string
):
string
;
var
var
digits
:
string
;
digits
:
string
;
...
...
webEMIMobile/View.DeviceManager.pas
View file @
4a520774
...
@@ -27,6 +27,7 @@ type
...
@@ -27,6 +27,7 @@ type
AUserAgent
,
ARegisteredAt
,
AStatus
:
string
);
AUserAgent
,
ARegisteredAt
,
AStatus
:
string
);
[
async
]
procedure
LoadDevices
;
[
async
]
procedure
LoadDevices
;
[
async
]
procedure
RevokeDevice
(
const
ACredentialId
,
AName
:
string
);
[
async
]
procedure
RevokeDevice
(
const
ACredentialId
,
AName
:
string
);
[
async
]
procedure
UnrevokeDevice
(
const
ACredentialId
,
AName
:
string
);
[
async
]
procedure
DeletePendingDevice
(
const
APhoneNumber
,
AName
:
string
);
[
async
]
procedure
DeletePendingDevice
(
const
APhoneNumber
,
AName
:
string
);
[
async
]
procedure
SendAppLink
(
const
APhoneNumber
,
AName
:
string
);
[
async
]
procedure
SendAppLink
(
const
APhoneNumber
,
AName
:
string
);
[
async
]
procedure
AddPendingDevice
;
[
async
]
procedure
AddPendingDevice
;
...
@@ -225,7 +226,18 @@ begin
...
@@ -225,7 +226,18 @@ begin
end
);
end
);
tdAction
.
appendChild
(
btn
);
tdAction
.
appendChild
(
btn
);
end
end
else
if
not
isRevoked
then
else
if
isRevoked
then
begin
btn
:=
TJSHTMLElement
(
document
.
createElement
(
'button'
));
btn
.
className
:=
'btn btn-outline-success btn-sm'
;
btn
.
innerText
:=
'Unrevoke'
;
btn
.
addEventListener
(
'click'
,
procedure
(
Event
:
TJSMouseEvent
)
begin
UnrevokeDevice
(
ACredentialId
,
AName
);
end
);
tdAction
.
appendChild
(
btn
);
end
else
begin
begin
btn
:=
TJSHTMLElement
(
document
.
createElement
(
'button'
));
btn
:=
TJSHTMLElement
(
document
.
createElement
(
'button'
));
btn
.
className
:=
'btn btn-danger btn-sm'
;
btn
.
className
:=
'btn btn-danger btn-sm'
;
...
@@ -372,6 +384,30 @@ begin
...
@@ -372,6 +384,30 @@ begin
end
;
end
;
end
;
end
;
procedure
TFViewDeviceManager
.
UnrevokeDevice
(
const
ACredentialId
,
AName
:
string
);
var
resp
:
TXDataClientResponse
;
res
:
TJSObject
;
status
:
string
;
begin
try
resp
:=
await
(
XDataWebClient
.
RawInvokeAsync
(
'IApiService.UnrevokeDevice'
,
[
ACredentialId
]));
res
:=
TJSObject
(
resp
.
Result
);
status
:=
string
(
res
[
'status'
]);
if
status
=
'ok'
then
begin
ShowNotification
(
'Device "'
+
AName
+
'" has been restored.'
,
False
);
LoadDevices
;
end
else
ShowNotification
(
string
(
res
[
'message'
]));
except
on
E
:
Exception
do
ShowNotification
(
'Unrevoke failed: '
+
E
.
Message
);
end
;
end
;
procedure
TFViewDeviceManager
.
btnAddDeviceClick
(
Sender
:
TObject
);
procedure
TFViewDeviceManager
.
btnAddDeviceClick
(
Sender
:
TObject
);
begin
begin
AddPendingDevice
;
AddPendingDevice
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment