mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 15:51:26 +00:00
feat(invites): team invite links — admin create/revoke, public accept (#42)
* feat(branding): white-label — public /branding, admin write, shell theming app_settings branding.* keys (product name, logo/favicon URLs, accent color, docs/support links). Public GET /branding so login and shell theme pre-auth; admin writes via PUT /settings. useBranding() applies document.title, accent CSS var and favicon; BrandWordmark replaces hardcoded wordmarks; admin Platform settings gain a Branding form. MCP containr_branding_get + settings_update. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * feat(invites): team invite links — admin create/revoke, public accept Admins mint single-use invite links (sha256-hashed token at rest, optional email binding, configurable TTL). Public endpoints let the accept page validate the link and register — working even while public signup is disabled. - migration + sqlc queries/model for user_invites - POST /admin/invites (returns one-time token+url), GET list, DELETE revoke - GET /auth/invites/:token public validation, POST /auth/accept-invite - CLI containr invites list|create|revoke; MCP invites tools - /auth/accept-invite page (expired/used/invalid states, bound-email lock) - Admin page Team invites section: create, copy link, revoke - OpenAPI + generated types + CLI guide Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
b47ced0135
commit
50e39fe140
20 files changed
+1194
-4
No files matched your search
@@ -0,0 +1,23 @@
|
||||
-- name: CreateUserInvite :one
|
||||
INSERT INTO user_invites (token_hash, email, created_by, expires_at)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING user_invites.*;
|
||||
|
||||
-- name: GetUserInviteByTokenHash :one
|
||||
SELECT user_invites.*
|
||||
FROM user_invites
|
||||
WHERE token_hash = $1;
|
||||
|
||||
-- name: ListUserInvites :many
|
||||
SELECT user_invites.*
|
||||
FROM user_invites
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- name: MarkUserInviteUsed :exec
|
||||
UPDATE user_invites
|
||||
SET used_by = $2, used_at = now()
|
||||
WHERE id = $1 AND used_at IS NULL;
|
||||
|
||||
-- name: DeleteUserInvite :exec
|
||||
DELETE FROM user_invites
|
||||
WHERE id = $1;
|
||||
@@ -316,3 +316,14 @@ CREATE TABLE banners (
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE user_invites (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
token_hash VARCHAR(64) NOT NULL UNIQUE,
|
||||
email VARCHAR(255),
|
||||
created_by UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
used_by UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
used_at TIMESTAMP WITH TIME ZONE,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
Reference in new issue
Block a user