From 0a4f4b1b104c2bac8f0354478fa4628401f8f6d0 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Thu, 07 Oct 2021 00:31:21 +0100 Subject: [PATCH] Show user profile pictures instead of placekittens --- chartered-db/src/users.rs | 7 +++++++ chartered-frontend/src/index.tsx | 12 ++---------- chartered-frontend/src/useAuth.tsx | 39 ++++++++++++++++++++++++++------------- chartered-frontend/src/util.tsx | 30 ++++++++++++++++++++++++++++++ chartered-frontend/src/pages/Login.tsx | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------- chartered-frontend/src/pages/User.tsx | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- chartered-frontend/src/pages/crate/CrateView.tsx | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++---------- chartered-frontend/src/pages/crate/Members.tsx | 36 ++++++++++++++++++++++-------------- chartered-frontend/src/pages/organisations/ListOrganisations.tsx | 43 ++++++++++++++++++++++++++----------------- chartered-frontend/src/pages/ssh-keys/ListSshKeys.tsx | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- chartered-web/src/endpoints/web_api/crates/info.rs | 15 +++++++++++++-- chartered-web/src/endpoints/web_api/crates/members.rs | 6 ++++-- chartered-web/src/endpoints/web_api/organisations/info.rs | 10 ++++++---- chartered-web/src/endpoints/web_api/users/info.rs | 2 +- chartered-web/src/endpoints/web_api/users/mod.rs | 2 +- 15 files changed, 467 insertions(+), 249 deletions(-) diff --git a/chartered-db/src/users.rs b/chartered-db/src/users.rs index a6a9780..62a1cc0 100644 --- a/chartered-db/src/users.rs +++ a/chartered-db/src/users.rs @@ -268,6 +268,13 @@ .unwrap_or_default() .permissions) } + + pub fn display_name(&self) -> &str { + self.nick + .as_ref() + .or(self.name.as_ref()) + .unwrap_or(&self.username) + } } #[derive(Identifiable, Queryable, Associations, PartialEq, Eq, Hash, Debug)] diff --git a/chartered-frontend/src/index.tsx b/chartered-frontend/src/index.tsx index 940f619..140e9e5 100644 --- a/chartered-frontend/src/index.tsx +++ a/chartered-frontend/src/index.tsx @@ -62,13 +62,9 @@ path="/crates/:organisation/:crate/:subview?" component={() => } /> + } /> } - /> - } /> @@ -126,11 +122,7 @@ {...rest} render={(props) => { // TODO: check if valid key - if ( - !unauthedOnly || - !auth || - !auth?.getAuthKey() - ) { + if (!unauthedOnly || !auth || !auth?.getAuthKey()) { return ; } else { return ( diff --git a/chartered-frontend/src/useAuth.tsx b/chartered-frontend/src/useAuth.tsx index 8703e54..8fd1679 100644 --- a/chartered-frontend/src/useAuth.tsx +++ a/chartered-frontend/src/useAuth.tsx @@ -38,16 +38,20 @@ useEffect(async () => { try { - let result = await fetch(unauthenticatedEndpoint(`login/oauth/complete${location.search}`)); + let result = await fetch( + unauthenticatedEndpoint(`login/oauth/complete${location.search}`) + ); let json = await result.json(); auth.handleLoginResponse(json); } catch (err) { setResult( - + ); } }); @@ -68,7 +72,11 @@ useEffect(() => { localStorage.setItem( "charteredAuthentication", - JSON.stringify({ userUuid: auth?.[0], authKey: auth?.[1], expires: auth?.[2] }) + JSON.stringify({ + userUuid: auth?.[0], + authKey: auth?.[1], + expires: auth?.[2], + }) ); }, [auth]); @@ -78,7 +86,7 @@ } setAuth([response.user_uuid, response.key, new Date(response.expires)]); - } + }; const login = async (username: string, password: string) => { let res = await fetch(unauthenticatedEndpoint("login/password"), { @@ -95,13 +103,16 @@ }; const oauthLogin = async (provider: string) => { - let res = await fetch(unauthenticatedEndpoint(`login/oauth/${provider}/begin`), { - method: "GET", - headers: { - "Content-Type": "application/json", - "User-Agent": window.navigator.userAgent, + let res = await fetch( + unauthenticatedEndpoint(`login/oauth/${provider}/begin`), + { + method: "GET", + headers: { + "Content-Type": "application/json", + "User-Agent": window.navigator.userAgent, + }, } - }); + ); let json = await res.json(); if (json.error) { @@ -109,7 +120,7 @@ } window.location.href = json.redirect_url; - } + }; const logout = async () => { // todo call the service so we can purge the key from the db diff --git a/chartered-frontend/src/util.tsx b/chartered-frontend/src/util.tsx index 28e26a7..2de96bd 100644 --- a/chartered-frontend/src/util.tsx +++ a/chartered-frontend/src/util.tsx @@ -71,6 +71,36 @@ return { response, error }; } +export function ProfilePicture({ + src, + height, + width, + className, +}: { + src: string; + height: string; + width: string; + className?: string; +}) { + if (src !== null) { + return ( + + ); + } else { + return ( +
+ ); + } +} + export function RoundedPicture({ src, height, diff --git a/chartered-frontend/src/pages/Login.tsx b/chartered-frontend/src/pages/Login.tsx index 6436fb9..95dffd6 100644 --- a/chartered-frontend/src/pages/Login.tsx +++ a/chartered-frontend/src/pages/Login.tsx @@ -19,7 +19,10 @@ const [loading, setLoading] = useState(null); const isMountedRef = useRef(null); - const { response: oauthProviders } = useUnauthenticatedRequest({ endpoint: "login/oauth/providers" }); + const { response: oauthProviders } = + useUnauthenticatedRequest({ + endpoint: "login/oauth/providers", + }); useEffect(() => { if (location.state?.error) { @@ -56,7 +59,7 @@ } catch (e) { setError(e.message); } - } + }; return (
@@ -96,7 +99,9 @@ onChange={(e) => setUsername(e.target.value)} /> - +
@@ -110,7 +115,9 @@ onChange={(e) => setPassword(e.target.value)} /> - +
- {oauthProviders?.providers.length > 0 ? (<> -
or
- - {oauthProviders.providers.map((v, i) => ( - { - evt.preventDefault(); - handleOAuthLogin(v); - }} - /> - ))} - ): <>} + {oauthProviders?.providers.length > 0 ? ( + <> +
or
+ + {oauthProviders.providers.map((v, i) => ( + { + evt.preventDefault(); + handleOAuthLogin(v); + }} + /> + ))} + + ) : ( + <> + )}
@@ -148,17 +159,27 @@ ); } -function ButtonOrSpinner({ type, variant, disabled, showSpinner, text, onClick }: { - type: "button" | "submit", - variant: string, - disabled: boolean, - showSpinner: boolean, - text: string, - onClick: (evt) => any, +function ButtonOrSpinner({ + type, + variant, + disabled, + showSpinner, + text, + onClick, +}: { + type: "button" | "submit"; + variant: string; + disabled: boolean; + showSpinner: boolean; + text: string; + onClick: (evt) => any; }) { if (showSpinner) { return ( -
+
Logging in...
); @@ -166,9 +187,14 @@ if (type) { return ( - ); } -}+} diff --git a/chartered-frontend/src/pages/User.tsx b/chartered-frontend/src/pages/User.tsx index 1f07a29..76bcf13 100644 --- a/chartered-frontend/src/pages/User.tsx +++ a/chartered-frontend/src/pages/User.tsx @@ -1,91 +1,165 @@ import React = require("react"); import { useParams } from "react-router-dom"; import { useAuth } from "../useAuth"; -import { RoundedPicture, useAuthenticatedRequest } from "../util"; +import { + ProfilePicture, + RoundedPicture, + useAuthenticatedRequest, +} from "../util"; import Nav from "../sections/Nav"; import ErrorPage from "./ErrorPage"; import ReactPlaceholder from "react-placeholder/lib"; import { Envelope, HouseDoor } from "react-bootstrap-icons"; interface Response { - uuid: string; - username: string; - name?: string; - nick?: string; - email?: string; - external_profile_url?: string; - picture_url?: string; + uuid: string; + username: string; + name?: string; + nick?: string; + email?: string; + external_profile_url?: string; + picture_url?: string; } export default function User() { - const auth = useAuth(); - const { uuid } = useParams(); - - const { response: user, error } = useAuthenticatedRequest({ - auth, - endpoint: "users/info/" + uuid, - }); - - if (error) { - return ; - } - - const ready = !!user; - - console.log(user); - - return ( -
-