diff options
author | Vendicated <vendicated@riseup.net> | 2023-10-06 19:40:53 +0200 |
---|---|---|
committer | Vendicated <vendicated@riseup.net> | 2023-10-06 19:43:24 +0200 |
commit | c0f2c974587d75a38e3e753368ef0e2e2be139fd (patch) | |
tree | c1e75f84785d10f207f1f142da0cec6ab01d2443 | |
parent | 664dd0a9920aa697359b1bb07b98795ff0f1beaf (diff) | |
download | Vencord-c0f2c974587d75a38e3e753368ef0e2e2be139fd.tar.gz Vencord-c0f2c974587d75a38e3e753368ef0e2e2be139fd.tar.bz2 Vencord-c0f2c974587d75a38e3e753368ef0e2e2be139fd.zip |
ReviewDB: proper multi account support
-rw-r--r-- | src/plugins/reviewDB/auth.tsx | 78 | ||||
-rw-r--r-- | src/plugins/reviewDB/components/ReviewComponent.tsx | 4 | ||||
-rw-r--r-- | src/plugins/reviewDB/components/ReviewModal.tsx | 5 | ||||
-rw-r--r-- | src/plugins/reviewDB/components/ReviewsView.tsx | 7 | ||||
-rw-r--r-- | src/plugins/reviewDB/entities.ts | 5 | ||||
-rw-r--r-- | src/plugins/reviewDB/index.tsx | 45 | ||||
-rw-r--r-- | src/plugins/reviewDB/reviewDbApi.ts | 18 | ||||
-rw-r--r-- | src/plugins/reviewDB/settings.tsx | 12 | ||||
-rw-r--r-- | src/plugins/reviewDB/utils.tsx | 55 |
9 files changed, 141 insertions, 88 deletions
diff --git a/src/plugins/reviewDB/auth.tsx b/src/plugins/reviewDB/auth.tsx new file mode 100644 index 0000000..1d95e47 --- /dev/null +++ b/src/plugins/reviewDB/auth.tsx @@ -0,0 +1,78 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2023 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { DataStore } from "@api/index"; +import { Logger } from "@utils/Logger"; +import { openModal } from "@utils/modal"; +import { findByPropsLazy } from "@webpack"; +import { showToast, Toasts, UserStore } from "@webpack/common"; + +import { ReviewDBAuth } from "./entities"; + +const DATA_STORE_KEY = "rdb-auth"; + +const OAuth = findByPropsLazy("OAuth2AuthorizeModal"); + +export let Auth: ReviewDBAuth = {}; + +export async function initAuth() { + Auth = await getAuth() ?? {}; +} + +export async function getAuth(): Promise<ReviewDBAuth | undefined> { + const auth = await DataStore.get(DATA_STORE_KEY); + return auth?.[UserStore.getCurrentUser()?.id]; +} + +export async function getToken() { + const auth = await getAuth(); + return auth?.token; +} + +export async function updateAuth(newAuth: ReviewDBAuth) { + return DataStore.update(DATA_STORE_KEY, auth => { + auth ??= {}; + Auth = auth[UserStore.getCurrentUser().id] ??= {}; + + if (newAuth.token) Auth.token = newAuth.token; + if (newAuth.user) Auth.user = newAuth.user; + + return auth; + }); +} + +export function authorize(callback?: any) { + openModal(props => + <OAuth.OAuth2AuthorizeModal + {...props} + scopes={["identify"]} + responseType="code" + redirectUri="https://manti.vendicated.dev/api/reviewdb/auth" + permissions={0n} + clientId="915703782174752809" + cancelCompletesFlow={false} + callback={async (response: any) => { + try { + const url = new URL(response.location); + url.searchParams.append("clientMod", "vencord"); + const res = await fetch(url, { + headers: new Headers({ Accept: "application/json" }) + }); + const { token, success } = await res.json(); + if (success) { + updateAuth({ token }); + showToast("Successfully logged in!"); + callback?.(); + } else if (res.status === 1) { + showToast("An Error occurred while logging in.", Toasts.Type.FAILURE); + } + } catch (e) { + new Logger("ReviewDB").error("Failed to authorize", e); + } + }} + /> + ); +} diff --git a/src/plugins/reviewDB/components/ReviewComponent.tsx b/src/plugins/reviewDB/components/ReviewComponent.tsx index 5792400..1865917 100644 --- a/src/plugins/reviewDB/components/ReviewComponent.tsx +++ b/src/plugins/reviewDB/components/ReviewComponent.tsx @@ -20,12 +20,12 @@ import { openUserProfile } from "@utils/discord"; import { classes } from "@utils/misc"; import { LazyComponent } from "@utils/react"; import { filters, findBulk } from "@webpack"; -import { Alerts, moment, Parser, Timestamp } from "@webpack/common"; +import { Alerts, moment, Parser, showToast, Timestamp } from "@webpack/common"; import { Review, ReviewType } from "../entities"; import { deleteReview, reportReview } from "../reviewDbApi"; import { settings } from "../settings"; -import { canDeleteReview, cl, showToast } from "../utils"; +import { canDeleteReview, cl } from "../utils"; import { DeleteButton, ReportButton } from "./MessageButton"; import ReviewBadge from "./ReviewBadge"; diff --git a/src/plugins/reviewDB/components/ReviewModal.tsx b/src/plugins/reviewDB/components/ReviewModal.tsx index 6e85dc2..9669a2b 100644 --- a/src/plugins/reviewDB/components/ReviewModal.tsx +++ b/src/plugins/reviewDB/components/ReviewModal.tsx @@ -21,8 +21,8 @@ import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, Mo import { useForceUpdater } from "@utils/react"; import { Paginator, Text, useRef, useState } from "@webpack/common"; +import { Auth } from "../auth"; import { Response, REVIEWS_PER_PAGE } from "../reviewDbApi"; -import { settings } from "../settings"; import { cl } from "../utils"; import ReviewComponent from "./ReviewComponent"; import ReviewsView, { ReviewsInputComponent } from "./ReviewsView"; @@ -35,7 +35,7 @@ function Modal({ modalProps, discordId, name }: { modalProps: any; discordId: st const ref = useRef<HTMLDivElement>(null); const reviewCount = data?.reviewCount; - const ownReview = data?.reviews.find(r => r.sender.discordID === settings.store.user?.discordID); + const ownReview = data?.reviews.find(r => r.sender.discordID === Auth.user?.discordID); return ( <ErrorBoundary> @@ -68,6 +68,7 @@ function Modal({ modalProps, discordId, name }: { modalProps: any; discordId: st <ReviewComponent refetch={refetch} review={ownReview} + profileId={discordId} /> )} <ReviewsInputComponent diff --git a/src/plugins/reviewDB/components/ReviewsView.tsx b/src/plugins/reviewDB/components/ReviewsView.tsx index 5eb370f..a87598b 100644 --- a/src/plugins/reviewDB/components/ReviewsView.tsx +++ b/src/plugins/reviewDB/components/ReviewsView.tsx @@ -18,12 +18,13 @@ import { LazyComponent, useAwaiter, useForceUpdater } from "@utils/react"; import { find, findByPropsLazy } from "@webpack"; -import { Forms, React, RelationshipStore, useRef, UserStore } from "@webpack/common"; +import { Forms, React, RelationshipStore, showToast, useRef, UserStore } from "@webpack/common"; +import { Auth, authorize } from "../auth"; import { Review } from "../entities"; import { addReview, getReviews, Response, REVIEWS_PER_PAGE } from "../reviewDbApi"; import { settings } from "../settings"; -import { authorize, cl, showToast } from "../utils"; +import { cl } from "../utils"; import ReviewComponent from "./ReviewComponent"; @@ -120,7 +121,7 @@ function ReviewList({ refetch, reviews, hideOwnReview, profileId }: { refetch(): export function ReviewsInputComponent({ discordId, isAuthor, refetch, name }: { discordId: string, name: string; isAuthor: boolean; refetch(): void; }) { - const { token } = settings.store; + const { token } = Auth; const editorRef = useRef<any>(null); const inputType = InputTypes.FORM; inputType.disableAutoFocus = true; diff --git a/src/plugins/reviewDB/entities.ts b/src/plugins/reviewDB/entities.ts index fefb1d3..0a77fef 100644 --- a/src/plugins/reviewDB/entities.ts +++ b/src/plugins/reviewDB/entities.ts @@ -36,6 +36,11 @@ export const enum NotificationType { Warning = 3 } +export interface ReviewDBAuth { + token?: string; + user?: ReviewDBUser; +} + export interface Badge { name: string; description: string; diff --git a/src/plugins/reviewDB/index.tsx b/src/plugins/reviewDB/index.tsx index a519713..b9350ba 100644 --- a/src/plugins/reviewDB/index.tsx +++ b/src/plugins/reviewDB/index.tsx @@ -23,16 +23,17 @@ import ErrorBoundary from "@components/ErrorBoundary"; import ExpandableHeader from "@components/ExpandableHeader"; import { OpenExternalIcon } from "@components/Icons"; import { Devs } from "@utils/constants"; +import { Logger } from "@utils/Logger"; import definePlugin from "@utils/types"; -import { Alerts, Menu, Parser, useState } from "@webpack/common"; +import { Alerts, Menu, Parser, showToast, useState } from "@webpack/common"; import { Guild, User } from "discord-types/general"; +import { Auth, initAuth, updateAuth } from "./auth"; import { openReviewsModal } from "./components/ReviewModal"; import ReviewsView from "./components/ReviewsView"; import { NotificationType } from "./entities"; import { getCurrentUserInfo, readNotification } from "./reviewDbApi"; import { settings } from "./settings"; -import { showToast } from "./utils"; const guildPopoutPatch: NavContextMenuPatchCallback = (children, props: { guild: Guild, onClose(): void; }) => () => { children.push( @@ -62,31 +63,48 @@ export default definePlugin({ } ], + flux: { + CONNECTION_OPEN: initAuth, + }, + async start() { + addContextMenuPatch("guild-header-popout", guildPopoutPatch); + const s = settings.store; - const { token, lastReviewId, notifyReviews } = s; + const { lastReviewId, notifyReviews } = s; + + const legacy = s as any as { token?: string; }; + if (legacy.token) { + await updateAuth({ token: legacy.token }); + legacy.token = undefined; + new Logger("ReviewDB").info("Migrated legacy settings"); + } - if (!notifyReviews || !token) return; + await initAuth(); setTimeout(async () => { - const user = await getCurrentUserInfo(token); - if (lastReviewId && lastReviewId < user.lastReviewID) { - s.lastReviewId = user.lastReviewID; - if (user.lastReviewID !== 0) - showToast("You have new reviews on your profile!"); - } + if (!Auth.token) return; + + const user = await getCurrentUserInfo(Auth.token); + updateAuth({ user }); - addContextMenuPatch("guild-header-popout", guildPopoutPatch); + if (notifyReviews) { + if (lastReviewId && lastReviewId < user.lastReviewID) { + s.lastReviewId = user.lastReviewID; + if (user.lastReviewID !== 0) + showToast("You have new reviews on your profile!"); + } + } if (user.notification) { const props = user.notification.type === NotificationType.Ban ? { cancelText: "Appeal", confirmText: "Ok", - onCancel: () => + onCancel: async () => VencordNative.native.openExternal( "https://reviewdb.mantikafasi.dev/api/redirect?" + new URLSearchParams({ - token: settings.store.token!, + token: Auth.token!, page: "dashboard/appeal" }) ) @@ -105,7 +123,6 @@ export default definePlugin({ readNotification(user.notification.id); } - s.user = user; }, 4000); }, diff --git a/src/plugins/reviewDB/reviewDbApi.ts b/src/plugins/reviewDB/reviewDbApi.ts index 5370a9b..add16dd 100644 --- a/src/plugins/reviewDB/reviewDbApi.ts +++ b/src/plugins/reviewDB/reviewDbApi.ts @@ -16,9 +16,11 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import { showToast, Toasts } from "@webpack/common"; + +import { authorize, getToken } from "./auth"; import { Review, ReviewDBUser } from "./entities"; import { settings } from "./settings"; -import { authorize, showToast } from "./utils"; const API_URL = "https://manti.vendicated.dev"; @@ -57,7 +59,7 @@ export async function getReviews(id: string, offset = 0): Promise<Response> { }; if (!res.success) { - showToast(res.message); + showToast(res.message, Toasts.Type.FAILURE); return { ...res, reviews: [ @@ -82,7 +84,7 @@ export async function getReviews(id: string, offset = 0): Promise<Response> { } export async function addReview(review: any): Promise<Response | null> { - review.token = settings.store.token; + review.token = await getToken(); if (!review.token) { showToast("Please authorize to add a review."); @@ -104,7 +106,7 @@ export async function addReview(review: any): Promise<Response | null> { }); } -export function deleteReview(id: number): Promise<Response> { +export async function deleteReview(id: number): Promise<Response> { return fetch(API_URL + `/api/reviewdb/users/${id}/reviews`, { method: "DELETE", headers: new Headers({ @@ -112,7 +114,7 @@ export function deleteReview(id: number): Promise<Response> { Accept: "application/json", }), body: JSON.stringify({ - token: settings.store.token, + token: await getToken(), reviewid: id }) }).then(r => r.json()); @@ -127,7 +129,7 @@ export async function reportReview(id: number) { }), body: JSON.stringify({ reviewid: id, - token: settings.store.token + token: await getToken() }) }).then(r => r.json()) as Response; @@ -141,11 +143,11 @@ export function getCurrentUserInfo(token: string): Promise<ReviewDBUser> { }).then(r => r.json()); } -export function readNotification(id: number) { +export async function readNotification(id: number) { return fetch(API_URL + `/api/reviewdb/notifications?id=${id}`, { method: "PATCH", headers: { - "Authorization": settings.store.token || "", + "Authorization": await getToken() || "", }, }); } diff --git a/src/plugins/reviewDB/settings.tsx b/src/plugins/reviewDB/settings.tsx index e318bc7..cf61a38 100644 --- a/src/plugins/reviewDB/settings.tsx +++ b/src/plugins/reviewDB/settings.tsx @@ -20,8 +20,7 @@ import { definePluginSettings } from "@api/Settings"; import { OptionType } from "@utils/types"; import { Button } from "@webpack/common"; -import { ReviewDBUser } from "./entities"; -import { authorize } from "./utils"; +import { authorize, getToken } from "./auth"; export const settings = definePluginSettings({ authorize: { @@ -57,10 +56,11 @@ export const settings = definePluginSettings({ type: OptionType.COMPONENT, description: "ReviewDB website", component: () => ( - <Button onClick={() => { + <Button onClick={async () => { let url = "https://reviewdb.mantikafasi.dev/"; - if (settings.store.token) - url += "/api/redirect?token=" + encodeURIComponent(settings.store.token); + const token = await getToken(); + if (token) + url += "/api/redirect?token=" + encodeURIComponent(token); VencordNative.native.openExternal(url); }}> @@ -80,8 +80,6 @@ export const settings = definePluginSettings({ ) } }).withPrivateSettings<{ - token?: string; - user?: ReviewDBUser; lastReviewId?: number; reviewsDropdownState?: boolean; }>(); diff --git a/src/plugins/reviewDB/utils.tsx b/src/plugins/reviewDB/utils.tsx index 63ab84d..ab66d53 100644 --- a/src/plugins/reviewDB/utils.tsx +++ b/src/plugins/reviewDB/utils.tsx @@ -17,67 +17,18 @@ */ import { classNameFactory } from "@api/Styles"; -import { Logger } from "@utils/Logger"; -import { openModal } from "@utils/modal"; -import { findByProps } from "@webpack"; -import { React, Toasts, UserStore } from "@webpack/common"; +import { UserStore } from "@webpack/common"; +import { Auth } from "./auth"; import { Review, UserType } from "./entities"; -import { settings } from "./settings"; export const cl = classNameFactory("vc-rdb-"); -export function authorize(callback?: any) { - const { OAuth2AuthorizeModal } = findByProps("OAuth2AuthorizeModal"); - - openModal((props: any) => - <OAuth2AuthorizeModal - {...props} - scopes={["identify"]} - responseType="code" - redirectUri="https://manti.vendicated.dev/api/reviewdb/auth" - permissions={0n} - clientId="915703782174752809" - cancelCompletesFlow={false} - callback={async (response: any) => { - try { - const url = new URL(response.location); - url.searchParams.append("clientMod", "vencord"); - const res = await fetch(url, { - headers: new Headers({ Accept: "application/json" }) - }); - const { token, success } = await res.json(); - if (success) { - settings.store.token = token; - showToast("Successfully logged in!"); - callback?.(); - } else if (res.status === 1) { - showToast("An Error occurred while logging in."); - } - } catch (e) { - new Logger("ReviewDB").error("Failed to authorize", e); - } - }} - /> - ); -} - -export function showToast(text: string) { - Toasts.show({ - type: Toasts.Type.MESSAGE, - message: text, - id: Toasts.genId(), - options: { - position: Toasts.Position.BOTTOM - }, - }); -} - export function canDeleteReview(profileId: string, review: Review) { const myId = UserStore.getCurrentUser().id; return ( myId === profileId || review.sender.discordID === profileId - || settings.store.user?.type === UserType.Admin + || Auth.user?.type === UserType.Admin ); } |