Compare commits

...

2 Commits

Author SHA1 Message Date
1765485027 feat: decrease inner spacing 2025-06-15 19:41:05 +02:00
c5fb5e674a feat: revoke service session 2025-06-15 19:40:54 +02:00
4 changed files with 39 additions and 14 deletions

View File

@ -40,6 +40,7 @@ func (h *AdminHandler) RegisterRoutes(router chi.Router) {
r.Patch("/user-sessions/revoke/{id}", h.RevokeUserSession) r.Patch("/user-sessions/revoke/{id}", h.RevokeUserSession)
r.Get("/service-sessions", h.GetServiceSessions) r.Get("/service-sessions", h.GetServiceSessions)
r.Patch("/service-sessions/revoke/{id}", h.RevokeUserSession)
}) })
router.Get("/api-services/client/{client_id}", h.GetApiServiceCID) router.Get("/api-services/client/{client_id}", h.GetApiServiceCID)

View File

@ -73,6 +73,8 @@ func (h *AdminHandler) GetUserSessions(w http.ResponseWriter, r *http.Request) {
TotalPages: int(math.Ceil(float64(totalSessions) / float64(params.PageSize))), TotalPages: int(math.Ceil(float64(totalSessions) / float64(params.PageSize))),
} }
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(response); err != nil { if err := json.NewEncoder(w).Encode(response); err != nil {
log.Println("ERR: Failed to encode sessions in response:", err) log.Println("ERR: Failed to encode sessions in response:", err)
web.Error(w, "failed to encode sessions", http.StatusInternalServerError) web.Error(w, "failed to encode sessions", http.StatusInternalServerError)
@ -94,6 +96,8 @@ func (h *AdminHandler) RevokeUserSession(w http.ResponseWriter, r *http.Request)
return return
} }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write([]byte("{\"success\":true}")) w.Write([]byte("{\"success\":true}"))
} }
@ -151,8 +155,28 @@ func (h *AdminHandler) GetServiceSessions(w http.ResponseWriter, r *http.Request
TotalPages: int(math.Ceil(float64(totalSessions) / float64(params.PageSize))), TotalPages: int(math.Ceil(float64(totalSessions) / float64(params.PageSize))),
} }
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(response); err != nil { if err := json.NewEncoder(w).Encode(response); err != nil {
log.Println("ERR: Failed to encode sessions in response:", err) log.Println("ERR: Failed to encode sessions in response:", err)
web.Error(w, "failed to encode sessions", http.StatusInternalServerError) web.Error(w, "failed to encode sessions", http.StatusInternalServerError)
} }
} }
func (h *AdminHandler) RevokeServiceSession(w http.ResponseWriter, r *http.Request) {
sessionId := chi.URLParam(r, "id")
parsed, err := uuid.Parse(sessionId)
if err != nil {
web.Error(w, "provided service id is not valid", http.StatusBadRequest)
return
}
if err := h.repo.RevokeServiceSession(r.Context(), parsed); err != nil {
log.Println("ERR: Failed to revoke service session:", err)
web.Error(w, "failed to revoke service session", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("{\"success\":true}"))
}

View File

@ -109,7 +109,7 @@ const AdminServiceSessionsPage: FC = () => {
key={session.id} key={session.id}
className="hover:bg-gray-50 dark:hover:bg-gray-800" className="hover:bg-gray-50 dark:hover:bg-gray-800"
> >
<td className="px-6 py-4 text-sm text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-700"> <td className="px-5 py-3 text-sm text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-700">
<div className="flex flex-row items-center gap-2 justify-start"> <div className="flex flex-row items-center gap-2 justify-start">
{typeof session.user?.profile_picture === "string" && ( {typeof session.user?.profile_picture === "string" && (
<Avatar <Avatar
@ -126,11 +126,11 @@ const AdminServiceSessionsPage: FC = () => {
</Link> </Link>
</div> </div>
</td> </td>
<td className="px-6 py-4 text-sm text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-700"> <td className="px-5 py-3 text-sm text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-700">
{/* <SessionSource deviceInfo={session.} /> */} {/* <SessionSource deviceInfo={session.} /> */}
<p>{session.client_id}</p> <p>{session.client_id}</p>
</td> </td>
<td className="px-6 py-4 text-sm border border-gray-300 dark:border-gray-700"> <td className="px-5 py-3 text-sm border border-gray-300 dark:border-gray-700">
<span <span
className={`inline-block px-2 py-1 text-xs rounded-full font-semibold ${ className={`inline-block px-2 py-1 text-xs rounded-full font-semibold ${
!session.is_active || !session.is_active ||
@ -148,20 +148,20 @@ const AdminServiceSessionsPage: FC = () => {
) && " (Expired)"} ) && " (Expired)"}
</span> </span>
</td> </td>
<td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700"> <td className="px-5 py-3 text-sm text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700">
{moment(session.issued_at).format("LLLL")} {moment(session.issued_at).format("LLLL")}
</td> </td>
<td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700"> <td className="px-5 py-3 text-sm text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700">
{session.expires_at {session.expires_at
? moment(session.expires_at).format("LLLL") ? moment(session.expires_at).format("LLLL")
: "never"} : "never"}
</td> </td>
<td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700"> <td className="px-5 py-3 text-sm text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700">
{session.last_active {session.last_active
? moment(session.last_active).format("LLLL") ? moment(session.last_active).format("LLLL")
: "never"} : "never"}
</td> </td>
<td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700"> <td className="px-5 py-3 text-sm text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700">
{session.revoked_at {session.revoked_at
? new Date(session.revoked_at).toLocaleString() ? new Date(session.revoked_at).toLocaleString()
: "never"} : "never"}

View File

@ -123,7 +123,7 @@ const AdminUserSessionsPage: FC = () => {
key={session.id} key={session.id}
className="hover:bg-gray-50 dark:hover:bg-gray-800" className="hover:bg-gray-50 dark:hover:bg-gray-800"
> >
<td className="px-6 py-4 text-sm text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-700"> <td className="px-5 py-3 text-sm text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-700">
<div className="flex flex-row items-center gap-2 justify-start"> <div className="flex flex-row items-center gap-2 justify-start">
{typeof session.user?.profile_picture === "string" && ( {typeof session.user?.profile_picture === "string" && (
<Avatar <Avatar
@ -140,10 +140,10 @@ const AdminUserSessionsPage: FC = () => {
</Link> </Link>
</div> </div>
</td> </td>
<td className="px-6 py-4 text-sm text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-700"> <td className="px-5 py-3 text-sm text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-700">
<SessionSource deviceInfo={session.device_info} /> <SessionSource deviceInfo={session.device_info} />
</td> </td>
<td className="px-6 py-4 text-sm border border-gray-300 dark:border-gray-700"> <td className="px-5 py-3 text-sm border border-gray-300 dark:border-gray-700">
<span <span
className={`inline-block px-2 py-1 text-xs rounded-full font-semibold ${ className={`inline-block px-2 py-1 text-xs rounded-full font-semibold ${
!session.is_active || !session.is_active ||
@ -161,20 +161,20 @@ const AdminUserSessionsPage: FC = () => {
) && " (Expired)"} ) && " (Expired)"}
</span> </span>
</td> </td>
<td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700"> <td className="px-5 py-3 text-sm text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700">
{moment(session.issued_at).format("LLLL")} {moment(session.issued_at).format("LLLL")}
</td> </td>
<td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700"> <td className="px-5 py-3 text-sm text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700">
{session.expires_at {session.expires_at
? moment(session.expires_at).format("LLLL") ? moment(session.expires_at).format("LLLL")
: "never"} : "never"}
</td> </td>
<td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700"> <td className="px-5 py-3 text-sm text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700">
{session.last_active {session.last_active
? moment(session.last_active).format("LLLL") ? moment(session.last_active).format("LLLL")
: "never"} : "never"}
</td> </td>
<td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700"> <td className="px-5 py-3 text-sm text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700">
{session.revoked_at {session.revoked_at
? new Date(session.revoked_at).toLocaleString() ? new Date(session.revoked_at).toLocaleString()
: "never"} : "never"}