REST + Channels-style UI for DM pairing (list pending/approved, approve, revoke, clear). Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
1 parent
b91ac044b9
commit
5870b73397
9 files changed
+785
No files matched your search
@@ -0,0 +1,46 @@
|
||||
package com.m57.hermescontrol.data.model
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* DM pairing management (issue #776).
|
||||
*
|
||||
* Backend contract (hermes_cli/web_server.py + gateway/pairing.py):
|
||||
* - `GET /api/pairing` → `{pending: [...], approved: [...]}`
|
||||
* - Pending entries: `{platform, request_id, user_id, user_name, age_minutes}`
|
||||
* - Approved entries: `{platform, user_id, user_name, approved_at}`
|
||||
*
|
||||
* Codes are stored hashed server-side and never returned; pending requests are
|
||||
* approved by their `request_id` (the desktop dashboard does the same).
|
||||
*/
|
||||
@Serializable
|
||||
data class PairingResponse(
|
||||
val pending: List<PairingItem> = emptyList(),
|
||||
val approved: List<PairingItem> = emptyList(),
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PairingItem(
|
||||
val platform: String,
|
||||
@SerialName("request_id") val requestId: String? = null,
|
||||
@SerialName("user_id") val userId: String? = null,
|
||||
@SerialName("user_name") val userName: String? = null,
|
||||
@SerialName("age_minutes") val ageMinutes: Int? = null,
|
||||
) {
|
||||
/** Stable key for LazyColumn + per-item action state. */
|
||||
fun key(): String = "${platform}_${requestId ?: userId ?: ""}"
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class PairingApproveRequest(
|
||||
val platform: String,
|
||||
@SerialName("request_id") val requestId: String? = null,
|
||||
val code: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PairingRevokeRequest(
|
||||
val platform: String,
|
||||
@SerialName("user_id") val userId: String,
|
||||
)
|
||||
@@ -63,6 +63,9 @@ import com.m57.hermescontrol.data.model.OAuthProvidersResponse
|
||||
import com.m57.hermescontrol.data.model.OAuthStartResponse
|
||||
import com.m57.hermescontrol.data.model.OAuthSubmitRequest
|
||||
import com.m57.hermescontrol.data.model.OAuthSubmitResponse
|
||||
import com.m57.hermescontrol.data.model.PairingApproveRequest
|
||||
import com.m57.hermescontrol.data.model.PairingResponse
|
||||
import com.m57.hermescontrol.data.model.PairingRevokeRequest
|
||||
import com.m57.hermescontrol.data.model.PluginProvidersPutRequest
|
||||
import com.m57.hermescontrol.data.model.PluginsHubResponse
|
||||
import com.m57.hermescontrol.data.model.PortalResponse
|
||||
@@ -580,6 +583,28 @@ interface HermesApiService {
|
||||
@Path("pairing_id") pairingId: String,
|
||||
): Response<Unit>
|
||||
|
||||
// ── DM pairing management (issue #776) ──────────────────────────────
|
||||
// Approve/revoke messaging users who requested access via pairing
|
||||
// codes. Pending requests are approved by `request_id` (as returned by
|
||||
// GET /api/pairing); the `code` field is the one-time code a user
|
||||
// relays from their DM.
|
||||
|
||||
@GET("api/pairing")
|
||||
suspend fun getPairing(): Response<PairingResponse>
|
||||
|
||||
@POST("api/pairing/approve")
|
||||
suspend fun approvePairing(
|
||||
@Body body: PairingApproveRequest,
|
||||
): Response<Unit>
|
||||
|
||||
@POST("api/pairing/revoke")
|
||||
suspend fun revokePairing(
|
||||
@Body body: PairingRevokeRequest,
|
||||
): Response<Unit>
|
||||
|
||||
@POST("api/pairing/clear-pending")
|
||||
suspend fun clearPendingPairing(): Response<Unit>
|
||||
|
||||
// ── OAuth provider management (issue #534) ──────────────────────────
|
||||
// Auth: the dashboard gates /start, /submit, /disconnect, /cancel via
|
||||
// `_require_token`, which accepts either `X-Hermes-Session-Token` OR the
|
||||
|
||||
Reference in new issue
Block a user