Merge pull request #65 from TNG-dev/release-v2.0.1

This commit is contained in:
zkldi
2021-12-07 22:50:55 +00:00
committed by GitHub
16 changed files with 240 additions and 22 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "tachi-client",
"version": "2.0.0-prerelease",
"version": "2.0.1",
"private": true,
"scripts": {
"start": "node scripts/start.js -o",
@@ -1,6 +1,7 @@
import ApiError from "components/util/ApiError";
import Divider from "components/util/Divider";
import Loading from "components/util/Loading";
import OAuthMoreInfo from "components/util/OAuthMoreInfo";
import useApiQuery from "components/util/query/useApiQuery";
import { UserContext } from "context/UserContext";
import { TachiConfig } from "lib/config";
@@ -89,6 +90,10 @@ export default function ClientFileFlowPage() {
Create the key.
</button>
</div>
<div className="col-12" style={{ fontSize: "1.3rem" }}>
<Divider />
<OAuthMoreInfo client={data} />
</div>
</>
) : (
<>
@@ -0,0 +1,130 @@
import CenterLayoutPage from "components/layout/CenterLayoutPage";
import ApiError from "components/util/ApiError";
import Divider from "components/util/Divider";
import Loading from "components/util/Loading";
import OAuthMoreInfo from "components/util/OAuthMoreInfo";
import useApiQuery from "components/util/query/useApiQuery";
import useQueryString from "components/util/useQueryString";
import React from "react";
import { Link } from "react-router-dom";
import { integer, TachiAPIClientDocument } from "tachi-common";
import { APIFetchV1 } from "util/api";
export default function OAuthRequestAuthPage() {
const params = useQueryString();
const clientID = params.get("clientID");
if (!clientID) {
return (
<CenterLayoutPage>
No ClientID. Whoever gave you this link likely messed up somehow. <br />
<Link to="/">Go Home.</Link>
</CenterLayoutPage>
);
}
return (
<CenterLayoutPage>
<OAuthRequestAuthLoader clientID={clientID} />
</CenterLayoutPage>
);
}
function OAuthRequestAuthLoader({ clientID }: { clientID: string }) {
const { isLoading, error, data } = useApiQuery<Omit<TachiAPIClientDocument, "clientSecret">>(
`/clients/${clientID}`
);
if (error) {
return <ApiError error={error} />;
}
if (isLoading || !data) {
return <Loading />;
}
if (!data.redirectUri) {
return (
<>
This client does not support OAuth Flows.
<br />
Whoever gave you this link likely messed up somehow. <br />
<Link to="/">Go Home.</Link>
</>
);
}
return <OAuthRequestAuthMain client={data} />;
}
function OAuthRequestAuthMain({
client,
}: {
client: Omit<TachiAPIClientDocument, "clientSecret">;
}) {
const params = useQueryString();
const context = params.get("context");
return (
<div className="row">
<>
<div className="col-12">
{client.name} is requesting you authenticate with them.
<Divider />
</div>
<div className="col-12">
The key will have the following permissions.
<ul>
{client.requestedPermissions.map(e => (
<li key={e}>{e}</li>
))}
</ul>
</div>
<div className="col-12 d-flex" style={{ justifyContent: "space-evenly" }}>
<Link className="btn btn-danger" to="/">
No thanks.
</Link>
<button
className="btn btn-success"
onClick={async () => {
const tokenRes = await APIFetchV1<{
code: string;
userID: integer;
createdOn: number;
}>(
"/oauth/create-code",
{
method: "POST",
},
false,
true
);
if (!tokenRes.success) {
return;
}
const redirectURL = new URL(client.redirectUri!);
redirectURL.searchParams.set("code", tokenRes.body.code);
if (context) {
redirectURL.searchParams.set("context", context);
}
window.location.href = redirectURL.toString();
}}
>
I want to authenticate with {client.name}.
</button>
</div>
<div className="col-12" style={{ fontSize: "1.3rem" }}>
<Divider />
<OAuthMoreInfo client={client} />
</div>
</>
</div>
);
}
@@ -21,10 +21,7 @@ export default function BarbatosPage() {
<ol className="instructions-list">
<li>
Download <code>barbatos.dll</code> from{" "}
<ExternalLink href="#">
here (No download yet. Barbatos is not supported.)
</ExternalLink>
.
<ExternalLink href="https://f.wcal.xyz/vC3dW7cn">here</ExternalLink>.
</li>
<li>
Download your config file{" "}
@@ -32,8 +29,8 @@ export default function BarbatosPage() {
<b>This file contains an API Key, which is meant to be kept secret!</b>
</li>
<li>
Place all of these files inside your SDVX folder, next to your <code>.bat</code>{" "}
file.
Place <code>barbatos.dll</code> and the above config file inside your SDVX
folder, next to your <code>.bat</code> file.
</li>
<ul className="instructions-list">
<li>
@@ -36,7 +36,14 @@ export default function BeatorajaIRPage() {
Place the IR <code>.jar</code> file in the <code>ir/</code> folder.
</li>
<li>Open the game options, and navigate to the IR section.</li>
<li>Select {TachiConfig.name} IR.</li>
<li>
Select {TachiConfig.name} IR.
<br />
<span className="text-warning">
If the IR isn't showing up, make sure you're launching the game with the{" "}
<code>beatoraja-config.bat</code> file. Otherwise, IRs will never load.
</span>
</li>
<li>
Get an API token for the IR by clicking{" "}
<ExternalLink href="/client-file-flow/CXBeatorajaIR">this link</ExternalLink>.
@@ -133,13 +133,13 @@ function ImportInfoDisplayer({ game }: { game: Game }) {
);
} else if (game === "sdvx") {
Content.unshift(
// <ImportInfoCard
// name="Barbatos"
// href="barbatos"
// desc="Automatically import scores, whenever you get them!"
// moreInfo="This is the recommended way to import SDVX scores, as it provides high quality data in real-time."
// key="Barbatos"
// />,
<ImportInfoCard
name="Barbatos"
href="barbatos"
desc="Automatically import scores, whenever you get them!"
moreInfo="This is the recommended way to import SDVX scores, as it provides high quality data in real-time."
key="Barbatos"
/>,
// <ImportInfoCard
// name="Konaste Hook"
// href="ks-hook"
@@ -358,6 +358,12 @@ function OAuthClientRow({ client, clients, setClients }: OAuthClientProps) {
{window.location.origin}/client-file-flow/{client.clientID}
</code>
</h6>
<h6>
OAuth Flow Link: <br />
<code>
{window.location.origin}/oauth/request-auth?clientID={client.clientID}
</code>
</h6>
</div>
<Divider />
@@ -23,6 +23,7 @@ import { GPTLeaderboard, UGPTLeaderboardAdjacent } from "types/api-returns";
import { GamePT, SetState } from "types/react";
import { APIFetchV1, UnsuccessfulAPIFetchResponse } from "util/api";
import { ChangeOpacity } from "util/color-opacity";
import { UppercaseFirst } from "util/misc";
interface LeaderboardsData {
stats: UGPTLeaderboardAdjacent;
@@ -161,7 +162,10 @@ function LeaderboardsPageContent({
</Link>
}
>
<MiniTable className="text-center" headers={["Position", "User", alg, "Classes"]}>
<MiniTable
className="text-center"
headers={["Position", "User", UppercaseFirst(alg), "Classes"]}
>
<>
{bestNearbyUser >= 1 &&
leaderboard.gameStats
+5
View File
@@ -1,6 +1,7 @@
import { ErrorPage } from "app/pages/ErrorPage";
import ForgotPasswordPage from "app/pages/ForgotPasswordPage";
import LoginPage from "app/pages/LoginPage";
import OAuthRequestAuthPage from "app/pages/OAuthRequestAuthPage";
import RegisterPage from "app/pages/RegisterPage";
import ResetPasswordPage from "app/pages/ResetPasswordPage";
import VerifyEmailPage from "app/pages/VerifyEmailPage";
@@ -51,6 +52,10 @@ export function Routes() {
<Route path="/oauth2-callback">
<OAuth2CallbackRoutes />
</Route>
<Route path="/oauth/request-auth">
<OAuthRequestAuthPage />
</Route>
<Route path="/client-file-flow">
<ClientFileFlowRoutes />
</Route>
@@ -91,7 +91,7 @@ export default function ARCImportPage({ game }: { game: "sdvx" | "iidx" }) {
</Link>
) : (
<Link style={{ color: "purple" }} to="/dashboard/import/barbatos">
Barbatos (Although it's not supported yet, sorry.)
Barbatos
</Link>
)}{" "}
instead.
+25 -3
View File
@@ -1,10 +1,24 @@
import Divider from "components/util/Divider";
import ExternalLink from "components/util/ExternalLink";
import React from "react";
import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { ServerStatus } from "types/api-returns";
import { APIFetchV1 } from "util/api";
import { FORMATTED_VERSION } from "util/constants/version";
export function Footer() {
const [serverVersion, setServerVersion] = useState("Loading...");
useEffect(() => {
APIFetchV1<ServerStatus>("/status").then(r => {
if (!r.success) {
setServerVersion("Error Fetching data!");
} else {
setServerVersion(r.body.version);
}
});
}, []);
return (
<>
<Divider className="mt-8" />
@@ -14,12 +28,20 @@ export function Footer() {
<div className="order-2 order-md-1">
{/* is there a better way to do this? mt-md-3 is the intent */}
<div className="d-block d-lg-none mt-3"></div>
Client:{" "}
<ExternalLink
href="https://www.youtube.com/watch?v=JOb5f-TG6iI&list=PLGFFTE0Sw8tStwmuVsAoeOEdmWBLceK9b"
className="gentle-link px-3"
href="https://en.wikipedia.org/wiki/Disintegration_(The_Cure_album)"
className="gentle-link"
>
{FORMATTED_VERSION}
</ExternalLink>
, Server:{" "}
<ExternalLink
href="https://en.wikipedia.org/wiki/Dummy_(album)"
className="gentle-link"
>
{serverVersion}
</ExternalLink>
</div>
<div className="nav nav-dark order-1 order-md-2 justify-content-center">
@@ -14,6 +14,7 @@ import AllGames from "./AllGames";
import ImportScoresLink from "./ImportScoresLink";
import MenuDropdown from "./MenuDropdown";
import MenuLink from "./MenuLink";
import SearchBar from "./SearchBar";
export function HeaderMenu() {
const { user } = useContext(UserContext);
@@ -95,6 +96,13 @@ export function HeaderMenu() {
</div>
</div>
<ul className="menu-nav">
<li className="menu-item d-block d-lg-none">
<div className="d-flex w-100 mb-8 px-4">
<SearchBar />
</div>
<Divider />
</li>
{user && ugs && ugs.length !== 0 && (
<MenuDropdown name="Your Profiles">{userProfileLinks}</MenuDropdown>
)}
@@ -0,0 +1,24 @@
import React from "react";
import { PublicUserDocument, TachiAPIClientDocument } from "tachi-common";
import ApiError from "./ApiError";
import Loading from "./Loading";
import Muted from "./Muted";
import useApiQuery from "./query/useApiQuery";
export default function OAuthMoreInfo({
client,
}: {
client: Omit<TachiAPIClientDocument, "clientSecret">;
}) {
const { data, isLoading, error } = useApiQuery<PublicUserDocument>(`/users/${client.author}`);
if (error) {
return <ApiError error={error} />;
}
if (isLoading || !data) {
return <Loading />;
}
return <Muted>API Client Author: {data.username}.</Muted>;
}
+9
View File
@@ -1,4 +1,5 @@
import {
APIPermissions,
ChartDocument,
ClassAchievementDocument,
FolderDocument,
@@ -162,3 +163,11 @@ export interface UserRecentSummary {
recentSessions: SessionDocument[];
recentFolders: FolderDocument[];
}
export interface ServerStatus {
serverTime: number;
startTime: number;
version: string;
whoami: integer | null;
permissions: APIPermissions[];
}
+2 -2
View File
@@ -1,8 +1,8 @@
const MAJOR = 2;
const MINOR = 0;
const PATCH = 0;
const PATCH = 1;
// As is with all front-facing zkldi projects, the version names for tachi-server
// As is with all front-facing zkldi projects, the version names for tachi-client
// are from an album I like. In this case, the album is The Cure - Disintegration.
const THE_CURE_DISINTEGRATION = [
+1
View File
@@ -97,6 +97,7 @@ export const loggedInSplashes = [
"I'm thinking this one's brown.",
"My god is the sun!",
"...Like Clockwork",
"brooooyyddg",
];
// Stuff that's bad for the kids, you know?