From a53c834043115878451413a18246e60300865ab6 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Wed, 28 Feb 2024 14:59:21 +0100 Subject: [PATCH 1/5] feat: allow inviting to scope via email --- api/src/api/scope.rs | 26 ++++++---- api/src/api/types.rs | 5 +- .../@[scope]/(_islands)/ScopeInviteForm.tsx | 49 ++++++++++++++----- 3 files changed, 58 insertions(+), 22 deletions(-) diff --git a/api/src/api/scope.rs b/api/src/api/scope.rs index 0529c106..e884fef1 100644 --- a/api/src/api/scope.rs +++ b/api/src/api/scope.rs @@ -220,7 +220,7 @@ async fn invite_member_handler( let scope = req.param_scope()?; Span::current().record("scope", &field::display(&scope)); - let ApiAddScopeMemberRequest { github_login } = decode_json(&mut req).await?; + let invite = decode_json::(&mut req).await?; let iam = req.iam(); let current_user = iam.check_current_user_access()?.to_owned(); @@ -233,14 +233,22 @@ async fn invite_member_handler( let iam = req.iam(); iam.check_scope_admin_access(&scope).await?; - let new_user = lookup_user_by_github_login( - db, - github_oauth2_client, - ¤t_user, - &github_login, - ) - .await? - .ok_or(ApiError::UserNotFound)?; + let new_user = match invite { + ApiAddScopeMemberRequest::GithubLogin(github_login) => { + lookup_user_by_github_login( + db, + github_oauth2_client, + ¤t_user, + &github_login, + ) + .await? + .ok_or(ApiError::UserNotFound)? + } + ApiAddScopeMemberRequest::Email(email) => db + .get_user_by_email(&email) + .await? + .ok_or(ApiError::UserNotFound)?, + }; if db.get_scope_member(&scope, new_user.id).await?.is_some() { return Err(ApiError::AlreadyScopeMember); diff --git a/api/src/api/types.rs b/api/src/api/types.rs index 256f24a1..6f44d6a7 100644 --- a/api/src/api/types.rs +++ b/api/src/api/types.rs @@ -282,8 +282,9 @@ impl From<(ScopeMember, UserPublic)> for ApiScopeMember { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct ApiAddScopeMemberRequest { - pub github_login: String, +pub enum ApiAddScopeMemberRequest { + GithubLogin(String), + Email(String), } #[derive(Debug, Deserialize)] diff --git a/frontend/routes/@[scope]/(_islands)/ScopeInviteForm.tsx b/frontend/routes/@[scope]/(_islands)/ScopeInviteForm.tsx index 2d2ebed8..ae544a64 100644 --- a/frontend/routes/@[scope]/(_islands)/ScopeInviteForm.tsx +++ b/frontend/routes/@[scope]/(_islands)/ScopeInviteForm.tsx @@ -1,6 +1,6 @@ // Copyright 2024 the JSR authors. All rights reserved. MIT license. import { useSignal } from "@preact/signals"; -import { useCallback } from "preact/hooks"; +import { useCallback, useRef } from "preact/hooks"; import { JSX } from "preact/jsx-runtime"; import { ScopeInvite } from "../../../utils/api_types.ts"; import { api, path } from "../../../utils/api.ts"; @@ -12,18 +12,25 @@ interface ScopeInviteFormProps { export function ScopeInviteForm(props: ScopeInviteFormProps) { const submitting = useSignal(false); const error = useSignal(""); + const kind = useSignal<"github" | "email">("github"); + const inputRef = useRef(null); const onSubmit = useCallback( (e: JSX.TargetedEvent) => { e.preventDefault(); const formData = new FormData(e.currentTarget); - const githubLogin = String(formData.get("githubLogin")); + + const kind = String(formData.get("kind")); + const inviteValue = String(formData.get("inviteValue")); submitting.value = true; api.post( path`/scopes/${props.scope}/members`, - { githubLogin }, + { + githubLogin: kind === "github" ? inviteValue : undefined, + email: kind === "email" ? inviteValue : undefined, + }, ).then((res) => { submitting.value = false; if (!res.ok) { @@ -47,14 +54,34 @@ export function ScopeInviteForm(props: ScopeInviteFormProps) { onSubmit={onSubmit} >
- +
+ + +