Compare commits

..

3 Commits

Author SHA1 Message Date
Glenn Thompson 30ff73a3e2 Merge remote-tracking branch 'upstream/main' 2025-11-22 10:22:19 +03:00
Luis Pereira 34ca61809b feat: add user role update routes 2025-11-21 18:06:49 -05:00
Luis Pereira ded376d971 feat: add user activate and deactivate routes 2025-11-21 18:06:49 -05:00
3 changed files with 96 additions and 15 deletions

View File

@ -157,3 +157,59 @@
(api-output `(("status" . "success") (api-output `(("status" . "success")
("message" . ,(format nil "Password reset for user: ~a" username))))))) ("message" . ,(format nil "Password reset for user: ~a" username)))))))
(define-api asteroid/user/activate (user-id active) ()
"API endpoint for setting the active state of an user account"
(format t "Activation of user: #~a set to ~a~%" user-id active)
(require-role :admin)
(with-error-handling
(let ((user (when user-id
(find-user-by-id user-id)))
(active (if (stringp active)
(parse-integer active)
active)))
(unless user
(error 'not-found-error :message "User not found"))
;; Change user active state
(let ((result (if (= 0 active)
(deactivate-user user-id)
(activate-user user-id))))
(if result
(api-output `(("status" . "success")
("message" . ,(format nil "User '~a' ~a."
(dm:field user "username")
(if (= 0 active)
"deactivated"
"activated")))))
(api-output `(("status" . "error")
("message" . ,(format nil "Could not ~a user '~a'."
(if (= 0 active)
"deactivated"
"activated")
(dm:field user "username"))))))))))
(define-api asteroid/user/role (user-id role) ()
"API endpoint for setting the access role of an user account"
(format t "Role of user: #~a set to ~a~%" user-id role)
(require-role :admin)
(with-error-handling
(let ((user (when user-id
(find-user-by-id user-id)))
(user-role (intern (string-upcase role) :keyword)))
(unless user
(error 'not-found-error :message "User not found"))
;; Change user role
(let ((result (update-user-role user-id user-role)))
(if result
(api-output `(("status" . "success")
("message" . ,(format nil "User '~a' is now a ~a."
(dm:field user "username")
role))))
(api-output `(("status" . "error")
("message" . ,(format nil "Could not set user '~a' as ~a."
(dm:field user "username")
role)))))))))

View File

@ -90,20 +90,23 @@ function hideUsersTable() {
async function updateUserRole(userId, newRole) { async function updateUserRole(userId, newRole) {
try { try {
const formData = new FormData(); const formData = new FormData();
formData.append('user-id', userId);
formData.append('role', newRole); formData.append('role', newRole);
const response = await fetch(`/api/asteroid/users/${userId}/role`, { const response = await fetch('/api/asteroid/user/role', {
method: 'POST', method: 'POST',
body: formData body: formData
}); });
const result = await response.json(); const result = await response.json();
// Handle Radiance API data wrapping
const data = result.data || result;
if (result.status === 'success') { if (data.status === 'success') {
loadUserStats(); loadUserStats();
alert('User role updated successfully'); alert(data.message);
} else { } else {
alert('Error updating user role: ' + result.message); alert('Error updating user role: ' + data.message);
} }
} catch (error) { } catch (error) {
console.error('Error updating user role:', error); console.error('Error updating user role:', error);
@ -117,18 +120,25 @@ async function deactivateUser(userId) {
} }
try { try {
const response = await fetch(`/api/asteroid/users/${userId}/deactivate`, { const formData = new FormData();
method: 'POST' formData.append('user-id', userId);
formData.append('active', 0);
const response = await fetch('/api/asteroid/user/activate', {
method: 'POST',
body: formData
}); });
const result = await response.json(); const result = await response.json();
// Handle Radiance API data wrapping
const data = result.data || result;
if (result.status === 'success') { if (data.status === 'success') {
loadUsers(); loadUsers();
loadUserStats(); loadUserStats();
alert('User deactivated successfully'); alert(data.message);
} else { } else {
alert('Error deactivating user: ' + result.message); alert('Error deactivating user: ' + data.message);
} }
} catch (error) { } catch (error) {
console.error('Error deactivating user:', error); console.error('Error deactivating user:', error);
@ -137,19 +147,31 @@ async function deactivateUser(userId) {
} }
async function activateUser(userId) { async function activateUser(userId) {
if (!confirm('Are you sure you want to activate this user?')) {
return;
}
try { try {
const response = await fetch(`/api/asteroid/users/${userId}/activate`, {
method: 'POST' const formData = new FormData();
formData.append('user-id', userId);
formData.append('active', 1);
const response = await fetch('/api/asteroid/user/activate', {
method: 'POST',
body: formData
}); });
const result = await response.json(); const result = await response.json();
// Handle Radiance API data wrapping
const data = result.data || result;
if (result.status === 'success') { if (data.status === 'success') {
loadUsers(); loadUsers();
loadUserStats(); loadUserStats();
alert('User activated successfully'); alert(data.message);
} else { } else {
alert('Error activating user: ' + result.message); alert('Error activating user: ' + data.message);
} }
} catch (error) { } catch (error) {
console.error('Error activating user:', error); console.error('Error activating user:', error);

View File

@ -40,7 +40,10 @@
(defun find-user-by-id (user-id) (defun find-user-by-id (user-id)
"Find a user by ID" "Find a user by ID"
(format t "Looking for user with ID: ~a (type: ~a)~%" user-id (type-of user-id)) (format t "Looking for user with ID: ~a (type: ~a)~%" user-id (type-of user-id))
(let ((user (dm:get-one "USERS" (db:query (:= '_id user-id))))) (let* ((user-id (if (stringp user-id)
(parse-integer user-id)
user-id))
(user (dm:get-one "USERS" (db:query (:= '_id user-id)))))
(when user (when user
(format t "Found user '~a' with id #~a~%" (format t "Found user '~a' with id #~a~%"
(dm:field user "username") (dm:field user "username")