From ba7ad794f363f0fb4d55a1344bd58190d70d8235 Mon Sep 17 00:00:00 2001 From: Gilles <43683714+corp-0@users.noreply.github.com> Date: Sat, 9 Mar 2024 13:42:51 -0300 Subject: [PATCH 01/21] fix: fix bug where password confirmation field would get the username helper text. --- app/(account)/register/page.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/(account)/register/page.tsx b/app/(account)/register/page.tsx index 2060643..f318007 100644 --- a/app/(account)/register/page.tsx +++ b/app/(account)/register/page.tsx @@ -108,12 +108,10 @@ const RegisterPage = () => { placeholder='********' shadow required - helperText={(state.error && isFieldError(state.error) && state.error?.error.password2) ? + helperText={(state.error && isFieldError(state.error) && state.error?.error.password2) &&
{state.error?.error.password2}
- : - usernameHelperText() } /> From f69a84be97e63f570a5ef9e56755fd9b7e5cdfc3 Mon Sep 17 00:00:00 2001 From: Gilles <43683714+corp-0@users.noreply.github.com> Date: Sat, 9 Mar 2024 13:45:30 -0300 Subject: [PATCH 02/21] fix: fix wrong URL on reset-password action which caused the process to always fail --- app/(account)/reset-password/actions.ts | 4 ++-- app/(account)/reset-password/page.tsx | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/(account)/reset-password/actions.ts b/app/(account)/reset-password/actions.ts index 3ed3af8..6064da0 100644 --- a/app/(account)/reset-password/actions.ts +++ b/app/(account)/reset-password/actions.ts @@ -10,7 +10,7 @@ export interface ResendMailResponse { fieldErrors?: { [key: string]: string }; } -export const resendMailConfirmationToken = async (prevState: ResendMailResponse, formData : FormData): Promise => { +export const requestAPasswordReset = async (prevState: ResendMailResponse, formData : FormData): Promise => { const schema = z.object({ email: z.string().email(), }); @@ -26,7 +26,7 @@ export const resendMailConfirmationToken = async (prevState: ResendMailResponse, const email = parsed.data.email; try { - const response = await fetch(`${process.env.CC_API_URL}/accounts/resend-account-confirmation/asd`, { + const response = await fetch(`${process.env.CC_API_URL}/accounts/reset-password/`, { method: "POST", headers: { "Content-Type": "application/json", diff --git a/app/(account)/reset-password/page.tsx b/app/(account)/reset-password/page.tsx index 6dba675..388584c 100644 --- a/app/(account)/reset-password/page.tsx +++ b/app/(account)/reset-password/page.tsx @@ -4,7 +4,7 @@ import Button from "../../common/uiLibrary/Button"; import React from "react"; import FormContainer from "../../common/uiLibrary/Layouters/formContainer"; import TextField from "../../common/uiLibrary/forms/textField"; -import {resendMailConfirmationToken, ResendMailResponse} from "./actions"; +import {requestAPasswordReset, ResendMailResponse} from "./actions"; import {useFormState} from "react-dom"; import ContactInformation from "../../(home)/contactInformation"; @@ -15,14 +15,14 @@ const initialState: ResendMailResponse = { }; const ResetPasswordPage = () => { - const [state, formAction] = useFormState(resendMailConfirmationToken, initialState); + const [state, formAction] = useFormState(requestAPasswordReset, initialState); const successMessage = () => (

Success!

An email has been sent with instructions to reset your password.

Please check your inbox and follow the instructions to complete the process.

-

Didn't receive the email? Check your Spam folder or try resending the email. Ensure your email address is +

Didn't receive the email? Check your Spam folder or try requesting a password reset again. Ensure your email address is entered correctly.

); From 4052a1e04ec310bba06921fc9a1764bd7f9ae09b Mon Sep 17 00:00:00 2001 From: Gilles <43683714+corp-0@users.noreply.github.com> Date: Sat, 9 Mar 2024 13:54:16 -0300 Subject: [PATCH 03/21] fix: fix navbar links being relative instead of absolute path --- app/common/defaultNavbar.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/common/defaultNavbar.tsx b/app/common/defaultNavbar.tsx index d1fb833..14da603 100644 --- a/app/common/defaultNavbar.tsx +++ b/app/common/defaultNavbar.tsx @@ -16,9 +16,10 @@ export default function DefaultNavbar() { const loggedOptions = () => ( <> - My Account + {/* hidden while we work on it */} + {/*My Account*/} - Logout + Logout ) @@ -26,11 +27,11 @@ export default function DefaultNavbar() { const notLoggedOptions = () => ( <> - Login/Register + Login/Register - Reset password + Reset password ) @@ -50,10 +51,10 @@ export default function DefaultNavbar() {

Home

- +

Blog

- +

Changelog

From c5d19c7f4324d53ade8761cc8f3041f85a38ccc3 Mon Sep 17 00:00:00 2001 From: Gilles <43683714+corp-0@users.noreply.github.com> Date: Sat, 9 Mar 2024 14:02:21 -0300 Subject: [PATCH 04/21] refactor: move confirm-email page to (account) internal category --- app/{ => (account)}/confirm-email/[token]/actions.ts | 0 app/{ => (account)}/confirm-email/[token]/page.tsx | 5 +++-- 2 files changed, 3 insertions(+), 2 deletions(-) rename app/{ => (account)}/confirm-email/[token]/actions.ts (100%) rename app/{ => (account)}/confirm-email/[token]/page.tsx (91%) diff --git a/app/confirm-email/[token]/actions.ts b/app/(account)/confirm-email/[token]/actions.ts similarity index 100% rename from app/confirm-email/[token]/actions.ts rename to app/(account)/confirm-email/[token]/actions.ts diff --git a/app/confirm-email/[token]/page.tsx b/app/(account)/confirm-email/[token]/page.tsx similarity index 91% rename from app/confirm-email/[token]/page.tsx rename to app/(account)/confirm-email/[token]/page.tsx index 771a6de..92defc2 100644 --- a/app/confirm-email/[token]/page.tsx +++ b/app/(account)/confirm-email/[token]/page.tsx @@ -2,8 +2,9 @@ import {usePathname} from "next/navigation"; import {postMailConfirmationToken} from "./actions"; import React, {useEffect, useState} from "react"; -import Panel from "../../common/uiLibrary/panel"; -import ContactInformation from "../../(home)/contactInformation"; +import Panel from "../../../common/uiLibrary/panel"; +import ContactInformation from "../../../(home)/contactInformation"; + const MailConfirmationPage = () => { const [response, setResponse] = useState<{ success?: boolean; error?: string }>({}); From c59ea1034cc6b7fcf228c52fd5d9518509fd3a23 Mon Sep 17 00:00:00 2001 From: Gilles <43683714+corp-0@users.noreply.github.com> Date: Sat, 9 Mar 2024 14:05:49 -0300 Subject: [PATCH 05/21] refactor: use new guards to handle errors in confirm-email action --- app/(account)/confirm-email/[token]/actions.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/(account)/confirm-email/[token]/actions.ts b/app/(account)/confirm-email/[token]/actions.ts index 0ebe69b..bb54cfd 100644 --- a/app/(account)/confirm-email/[token]/actions.ts +++ b/app/(account)/confirm-email/[token]/actions.ts @@ -1,5 +1,7 @@ "use server" +import {isFieldError, isGeneralError} from "../../../../lib/auth/guards"; + export const postMailConfirmationToken = async (token: string): Promise => { try { const response = await fetch(`${process.env.CC_API_URL}/accounts/confirm-account`, { @@ -13,12 +15,12 @@ export const postMailConfirmationToken = async (token: string): Promise => if (!response.ok) { const errorResponse = await response.json(); if (errorResponse.error) { - if (typeof errorResponse.error === 'string') { - return { error: errorResponse.error }; - } else if (errorResponse.error.token) { + if (isGeneralError(errorResponse.error)) { + return { error: "An unexpected error occurred." }; + } + + if (isFieldError(errorResponse.error) && errorResponse.error.token) { return { error: errorResponse.error.token.join(' ') }; - } else if (errorResponse.error.non_field_errors) { - return { error: errorResponse.error.non_field_errors.join(' ') }; } } return { error: "An unexpected error occurred." }; From b20f80a1600d631f4494a0f97a5be0bb028c2e55 Mon Sep 17 00:00:00 2001 From: Gilles <43683714+corp-0@users.noreply.github.com> Date: Sat, 9 Mar 2024 14:33:00 -0300 Subject: [PATCH 06/21] refactor: simplify error handling in confirm-email actions.ts --- .../confirm-email/[token]/actions.ts | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/app/(account)/confirm-email/[token]/actions.ts b/app/(account)/confirm-email/[token]/actions.ts index bb54cfd..deedb65 100644 --- a/app/(account)/confirm-email/[token]/actions.ts +++ b/app/(account)/confirm-email/[token]/actions.ts @@ -9,25 +9,20 @@ export const postMailConfirmationToken = async (token: string): Promise => headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ token }), + body: JSON.stringify({token}), }); if (!response.ok) { const errorResponse = await response.json(); - if (errorResponse.error) { - if (isGeneralError(errorResponse.error)) { - return { error: "An unexpected error occurred." }; - } - - if (isFieldError(errorResponse.error) && errorResponse.error.token) { - return { error: errorResponse.error.token.join(' ') }; - } + if (isFieldError(errorResponse) && errorResponse.error.token) { + return {error: errorResponse.error.token.join(' ')}; } - return { error: "An unexpected error occurred." }; + + return {error: "An unexpected error occurred."}; } - return { success: true }; + return {success: true}; } catch (error) { - return { error: "An unexpected error occurred." }; + return {error: "An unexpected error occurred."}; } }; From 3fd1cf59e94e25dde3cd204188c37416c9270713 Mon Sep 17 00:00:00 2001 From: Gilles <43683714+corp-0@users.noreply.github.com> Date: Sat, 9 Mar 2024 14:33:59 -0300 Subject: [PATCH 07/21] refactor: use useParams to get the dynamic url instead of rebuilding it with usePathname in confirm-email --- app/(account)/confirm-email/[token]/page.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/(account)/confirm-email/[token]/page.tsx b/app/(account)/confirm-email/[token]/page.tsx index 92defc2..acb087a 100644 --- a/app/(account)/confirm-email/[token]/page.tsx +++ b/app/(account)/confirm-email/[token]/page.tsx @@ -1,5 +1,5 @@ "use client" -import {usePathname} from "next/navigation"; +import {useParams} from "next/navigation"; import {postMailConfirmationToken} from "./actions"; import React, {useEffect, useState} from "react"; import Panel from "../../../common/uiLibrary/panel"; @@ -8,7 +8,7 @@ import ContactInformation from "../../../(home)/contactInformation"; const MailConfirmationPage = () => { const [response, setResponse] = useState<{ success?: boolean; error?: string }>({}); - const token = usePathname().split('/').filter(Boolean).pop(); + const {token} = useParams<{token: string}>(); useEffect(() => { const fetchData = async () => { From d39ffa40e45d83f34a4a1cb06ba244863631ecf4 Mon Sep 17 00:00:00 2001 From: Gilles <43683714+corp-0@users.noreply.github.com> Date: Sat, 9 Mar 2024 14:34:22 -0300 Subject: [PATCH 08/21] chore: remove unneeded type hint --- app/(home)/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/(home)/page.tsx b/app/(home)/page.tsx index 2207cc2..ba71221 100644 --- a/app/(home)/page.tsx +++ b/app/(home)/page.tsx @@ -49,7 +49,7 @@ const fetchLatestBlogPost = async (): Promise => { return resPage1.results.concat(resPage2.results); } -const HomePage: () => Promise = async () => { +const HomePage = async () => { const latestBlogPosts: BlogPost[] = await fetchLatestBlogPost(); const NoSsrHeroImageClient = dynamic(() => import('./HeroRandomImageClient'), {ssr: false}); From c115f474acb17f5b6f5a541b5a3b048b9eec8499 Mon Sep 17 00:00:00 2001 From: Gilles <43683714+corp-0@users.noreply.github.com> Date: Sat, 9 Mar 2024 15:54:03 -0300 Subject: [PATCH 09/21] feat: add page to type your new password as a second step in password-reset process --- .../reset-password/[token]/actions.ts | 65 ++++++++++++++ app/(account)/reset-password/[token]/page.tsx | 86 +++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 app/(account)/reset-password/[token]/actions.ts create mode 100644 app/(account)/reset-password/[token]/page.tsx diff --git a/app/(account)/reset-password/[token]/actions.ts b/app/(account)/reset-password/[token]/actions.ts new file mode 100644 index 0000000..115104f --- /dev/null +++ b/app/(account)/reset-password/[token]/actions.ts @@ -0,0 +1,65 @@ +import {FieldError, GeneralError} from "../../../../lib/auth/guards"; +import {z} from "zod"; + +export interface ResetPasswordStep2Response { + success: boolean; + error?: GeneralError | FieldError; +} + +export const postPasswordReset = async (_: ResetPasswordStep2Response, formData: FormData): Promise => { + const schema = z.object({ + password: z.string().min(6), + token: z.string().min(1) + }); + + const parsed = schema.safeParse({ + password: formData.get('password'), + password2: formData.get('password2'), + token: formData.get('token') + }); + + if (!parsed.success) { + const fieldErrors = parsed.error.errors.reduce((acc, error) => { + return {...acc, [error.path[0]]: error.message} + }, {}); + + return {success: false, error: {status: 400, error: fieldErrors}}; + } + + const password2 = formData.get('password2'); + if (password2 !== parsed.data.password) { + return { + success: false, + error: + { + status: 400, + error: { + password2: ['Passwords do not match'] + } + } + } + } + + const body = { + password: parsed.data.password, + token: parsed.data.token + } + + try { + const response = await fetch(`${process.env.CC_API_URL}/accounts/reset-password/${parsed.data.token}`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + if (!response.ok) { + return { success: false, error: {status: 400, error: {password: ['An unexpected error occurred']}}}; + } + + return { success: true}; + } catch (error) { + return { success: false, error: {status: 400, error: {password: ['An unexpected error occurred']}}}; + } +} \ No newline at end of file diff --git a/app/(account)/reset-password/[token]/page.tsx b/app/(account)/reset-password/[token]/page.tsx new file mode 100644 index 0000000..d296f1b --- /dev/null +++ b/app/(account)/reset-password/[token]/page.tsx @@ -0,0 +1,86 @@ +"use client" + + +import {useParams} from "next/navigation"; +import React from "react"; +import FormContainer from "../../../common/uiLibrary/Layouters/formContainer"; +import TextField from "../../../common/uiLibrary/forms/textField"; +import Button from "../../../common/uiLibrary/Button"; +import {useFormState} from "react-dom"; +import {postPasswordReset, ResetPasswordStep2Response} from "./actions"; +import {isFieldError} from "../../../../lib/auth/guards"; + +const ResetPasswordPageStep2 = () => { + const {token} = useParams<{token: string}>(); + const initialState: ResetPasswordStep2Response = { + success: false, + error: undefined + } + + const [state, formAction] = useFormState(postPasswordReset, initialState); + + const successMessage = () => ( +
+

Success!

+

Your password has been reset successfully.

+

You can now log in using your new password.

+
+ ); + + const errorMessage = () => { + return ( +
+

Oops!

+

There was an unexpected error while trying to reset your password.

+

Please try again later or contact us.

+
+ ) + } + + return ( +
+
+ + {state.success ? successMessage() : errorMessage()} + + + {state.error?.error.password} +
+ } + /> + + + {state.error?.error.password2} +
+ } + /> + + + + + + + + + ) +} + +export default ResetPasswordPageStep2; \ No newline at end of file From e336e858022db0b0fd3338173b274d58e8d980f8 Mon Sep 17 00:00:00 2001 From: Gilles <43683714+corp-0@users.noreply.github.com> Date: Sat, 9 Mar 2024 15:55:43 -0300 Subject: [PATCH 10/21] chore: rename the step1 password reset request type, so it is actually called what it represents --- app/(account)/reset-password/actions.ts | 4 ++-- app/(account)/reset-password/page.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/(account)/reset-password/actions.ts b/app/(account)/reset-password/actions.ts index 6064da0..675c059 100644 --- a/app/(account)/reset-password/actions.ts +++ b/app/(account)/reset-password/actions.ts @@ -3,14 +3,14 @@ import {revalidatePath} from "next/cache"; import {z} from "zod"; -export interface ResendMailResponse { +export interface ResetPassowrdStep1 { success: boolean; email?: string; message?: string; fieldErrors?: { [key: string]: string }; } -export const requestAPasswordReset = async (prevState: ResendMailResponse, formData : FormData): Promise => { +export const requestAPasswordReset = async (_: ResetPassowrdStep1, formData : FormData): Promise => { const schema = z.object({ email: z.string().email(), }); diff --git a/app/(account)/reset-password/page.tsx b/app/(account)/reset-password/page.tsx index 388584c..ff32b60 100644 --- a/app/(account)/reset-password/page.tsx +++ b/app/(account)/reset-password/page.tsx @@ -4,11 +4,11 @@ import Button from "../../common/uiLibrary/Button"; import React from "react"; import FormContainer from "../../common/uiLibrary/Layouters/formContainer"; import TextField from "../../common/uiLibrary/forms/textField"; -import {requestAPasswordReset, ResendMailResponse} from "./actions"; +import {requestAPasswordReset, ResetPassowrdStep1} from "./actions"; import {useFormState} from "react-dom"; import ContactInformation from "../../(home)/contactInformation"; -const initialState: ResendMailResponse = { +const initialState: ResetPassowrdStep1 = { success: false, message: undefined, email: '' From dc04ea2731ca05769b8b1808dd5feb720e85a77e Mon Sep 17 00:00:00 2001 From: Gilles <43683714+corp-0@users.noreply.github.com> Date: Sat, 9 Mar 2024 16:29:23 -0300 Subject: [PATCH 11/21] feat: finish reset-password page and functionality --- app/(account)/login/page.tsx | 3 +- .../reset-password/[token]/actions.ts | 16 ++++- app/(account)/reset-password/[token]/page.tsx | 68 ++++++++++--------- 3 files changed, 52 insertions(+), 35 deletions(-) diff --git a/app/(account)/login/page.tsx b/app/(account)/login/page.tsx index bde0fa6..d6eb1c1 100644 --- a/app/(account)/login/page.tsx +++ b/app/(account)/login/page.tsx @@ -89,7 +89,8 @@ const LoginPage = () => { links={ [ {link: '/register', linkText: 'Don\'t have an account?'}, - {link: '/reset-password', linkText: 'Forgot your password?'} + {link: '/reset-password', linkText: 'Forgot your password?'}, + {link: '/resend-confirmation-email', linkText: 'Haven\'t received confirmation email yet?'}, ] } /> diff --git a/app/(account)/reset-password/[token]/actions.ts b/app/(account)/reset-password/[token]/actions.ts index 115104f..f233447 100644 --- a/app/(account)/reset-password/[token]/actions.ts +++ b/app/(account)/reset-password/[token]/actions.ts @@ -1,4 +1,6 @@ -import {FieldError, GeneralError} from "../../../../lib/auth/guards"; +"use server" + +import {FieldError, GeneralError, isFieldError, isGeneralError} from "../../../../lib/auth/guards"; import {z} from "zod"; export interface ResetPasswordStep2Response { @@ -55,11 +57,19 @@ export const postPasswordReset = async (_: ResetPasswordStep2Response, formData: }); if (!response.ok) { - return { success: false, error: {status: 400, error: {password: ['An unexpected error occurred']}}}; + if (isFieldError(response) && response.error.token) { + return {success: false, error: {status: 400, error: "Your link has expired. Please request a new one."}}; + } + + if (isFieldError(response) || isGeneralError(response)) { + return {success: false, error: response}; + } + + return { success: false, error: {status: 400, error: "An unexpected error occurred"}}; } return { success: true}; } catch (error) { - return { success: false, error: {status: 400, error: {password: ['An unexpected error occurred']}}}; + return { success: false, error: {status: 400, error: "An unexpected error occurred"}}; } } \ No newline at end of file diff --git a/app/(account)/reset-password/[token]/page.tsx b/app/(account)/reset-password/[token]/page.tsx index d296f1b..b3e4e99 100644 --- a/app/(account)/reset-password/[token]/page.tsx +++ b/app/(account)/reset-password/[token]/page.tsx @@ -11,7 +11,7 @@ import {postPasswordReset, ResetPasswordStep2Response} from "./actions"; import {isFieldError} from "../../../../lib/auth/guards"; const ResetPasswordPageStep2 = () => { - const {token} = useParams<{token: string}>(); + const {token} = useParams<{ token: string }>(); const initialState: ResetPasswordStep2Response = { success: false, error: undefined @@ -31,52 +31,58 @@ const ResetPasswordPageStep2 = () => { return (

Oops!

-

There was an unexpected error while trying to reset your password.

-

Please try again later or contact us.

+

There was an error while trying to reset your password. Your password-reset token might be invalid or expired.

+

Please try requesting a new password reset or contact us.

) } - return ( -
-
- - {state.success ? successMessage() : errorMessage()} - - { + return ( + <> + {state.error && errorMessage()} + {state.error?.error.password}
} - /> + /> - {state.error?.error.password2}
} - /> + /> - + - + + + ) + } + return ( +
+
+ + {state.success ? successMessage() : resetPasswordForm()}
From 625b843a9f86e3af79f770062bb477f81e91c6da Mon Sep 17 00:00:00 2001 From: Gilles <43683714+corp-0@users.noreply.github.com> Date: Sat, 9 Mar 2024 16:42:05 -0300 Subject: [PATCH 12/21] refactor: move layout for occupying the whole page but header into a component --- app/(account)/login/page.tsx | 7 ++++--- app/(account)/reset-password/[token]/page.tsx | 5 +++-- app/common/uiLibrary/Layouters/fullPage.tsx | 12 ++++++++++++ 3 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 app/common/uiLibrary/Layouters/fullPage.tsx diff --git a/app/(account)/login/page.tsx b/app/(account)/login/page.tsx index d6eb1c1..9204921 100644 --- a/app/(account)/login/page.tsx +++ b/app/(account)/login/page.tsx @@ -11,6 +11,7 @@ import {AuthorizerContext} from "../../../context/AuthorizerContextProvider"; import {isFieldError, isGeneralError} from "../../../lib/auth/guards"; import GenericLoading from "../../common/uiLibrary/genericLoading"; import {redirect} from "next/navigation"; +import FullPage from "../../common/uiLibrary/Layouters/fullPage"; const LoginPage = () => { const {state, credentialsLogin} = useContext(AuthorizerContext); @@ -41,7 +42,7 @@ const LoginPage = () => { const loginForm = () => { return ( -
+
{isLoading &&
@@ -90,14 +91,14 @@ const LoginPage = () => { [ {link: '/register', linkText: 'Don\'t have an account?'}, {link: '/reset-password', linkText: 'Forgot your password?'}, - {link: '/resend-confirmation-email', linkText: 'Haven\'t received confirmation email yet?'}, + {link: '/resend-confirm-email', linkText: 'Haven\'t received confirmation email yet?'}, ] } />
-
+
) } diff --git a/app/(account)/reset-password/[token]/page.tsx b/app/(account)/reset-password/[token]/page.tsx index b3e4e99..b52e520 100644 --- a/app/(account)/reset-password/[token]/page.tsx +++ b/app/(account)/reset-password/[token]/page.tsx @@ -9,6 +9,7 @@ import Button from "../../../common/uiLibrary/Button"; import {useFormState} from "react-dom"; import {postPasswordReset, ResetPasswordStep2Response} from "./actions"; import {isFieldError} from "../../../../lib/auth/guards"; +import FullPage from "../../../common/uiLibrary/Layouters/fullPage"; const ResetPasswordPageStep2 = () => { const {token} = useParams<{ token: string }>(); @@ -79,13 +80,13 @@ const ResetPasswordPageStep2 = () => { } return ( -
+
{state.success ? successMessage() : resetPasswordForm()}
-
+ ) } diff --git a/app/common/uiLibrary/Layouters/fullPage.tsx b/app/common/uiLibrary/Layouters/fullPage.tsx new file mode 100644 index 0000000..ef34bfa --- /dev/null +++ b/app/common/uiLibrary/Layouters/fullPage.tsx @@ -0,0 +1,12 @@ +import layoutChildren from "../../../../types/layoutChildren"; + +// makes the view occupy the full page, excluding the header. +const FullPage = (props: layoutChildren) => { + return ( +
+ {props.children} +
+ ) +} + +export default FullPage; \ No newline at end of file From 4fbf02d1605241cc752fc16b139ad3f476805d31 Mon Sep 17 00:00:00 2001 From: Gilles <43683714+corp-0@users.noreply.github.com> Date: Sat, 9 Mar 2024 17:12:28 -0300 Subject: [PATCH 13/21] feat: add page to resend confirmation email --- app/(account)/resend-confirm-email/actions.ts | 53 ++++++++++++++ app/(account)/resend-confirm-email/page.tsx | 70 +++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 app/(account)/resend-confirm-email/actions.ts create mode 100644 app/(account)/resend-confirm-email/page.tsx diff --git a/app/(account)/resend-confirm-email/actions.ts b/app/(account)/resend-confirm-email/actions.ts new file mode 100644 index 0000000..5ff606f --- /dev/null +++ b/app/(account)/resend-confirm-email/actions.ts @@ -0,0 +1,53 @@ +"use server" + +import {z} from 'zod'; +import {FieldError, GeneralError, isFieldError} from "../../../lib/auth/guards"; + +export interface ResendConfirmationMailRequest { + success: boolean; + error?: GeneralError | FieldError; +} + +export const postResendConfirmationMail = async (_: ResendConfirmationMailRequest, formData: FormData): Promise => { + const schema = z.object({ + email: z.string().email() + }); + + const parsed = schema.safeParse({ + email: formData.get('email') + }); + + if (!parsed.success) { + const fieldErrors = parsed.error.errors.reduce((acc, error) => { + return {...acc, [error.path[0]]: error.message} + }, {}); + + return {success: false, error: {status: 400, error: fieldErrors}}; + } + + try { + const response = await fetch(`${process.env.CC_API_URL}/accounts/resend-account-confirmation`, { + method: "POST", + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + email: parsed.data.email + }) + }); + + if (!response.ok) { + const error = await response.json(); + if (isFieldError(error)) { + return {success: false, error: error}; + } + + throw new Error('Unknown error'); + } + + } catch (e) { + return {success: false, error: {error: 'An unexpected error happened', status: 500}}; + } + + return {success: true} +} \ No newline at end of file diff --git a/app/(account)/resend-confirm-email/page.tsx b/app/(account)/resend-confirm-email/page.tsx new file mode 100644 index 0000000..156ca55 --- /dev/null +++ b/app/(account)/resend-confirm-email/page.tsx @@ -0,0 +1,70 @@ +"use client" + + +import FormContainer from "../../common/uiLibrary/Layouters/formContainer"; +import TextField from "../../common/uiLibrary/forms/textField"; +import Button from "../../common/uiLibrary/Button"; +import ContactInformation from "../../(home)/contactInformation"; +import React from "react"; +import FullPage from "../../common/uiLibrary/Layouters/fullPage"; +import {useFormState} from "react-dom"; +import {postResendConfirmationMail, ResendConfirmationMailRequest} from "./actions"; + +const ResendConfirmationMail = () => { + const initialState: ResendConfirmationMailRequest = { + success: false, + } + + const [state, formAction] = useFormState(postResendConfirmationMail, initialState); + + const resendForm = () => { + return ( + <> + {!state.success && state.error && errorMessage()} + + + + + ) + } + const errorMessage = () => { + return ( +
+

Oops!

+

There was an unexpected error while trying to resend the confirmation email.

+

Please try again later or contact us.

+
+ ) + } + + const successMessage = () => ( +
+

Success!

+

Your request has been processed successfully. If your account is found in our system and the email + address you provided matches our records, we have sent a confirmation email to that address.

+

Please check your inbox for the confirmation email. If you don't receive it within a few minutes, check + your spam or junk folder. For further assistance, don't hesitate to contact us.

+
+ ); + + return ( + +
+ + {state.success ? successMessage() : resendForm()} + +
+ +
+ ) +}; + +export default ResendConfirmationMail; \ No newline at end of file From e4609485f908afbdf034cf697b531b331a59039a Mon Sep 17 00:00:00 2001 From: Gilles <43683714+corp-0@users.noreply.github.com> Date: Sat, 9 Mar 2024 17:16:43 -0300 Subject: [PATCH 14/21] chore: fuck you linter --- app/(account)/resend-confirm-email/page.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/(account)/resend-confirm-email/page.tsx b/app/(account)/resend-confirm-email/page.tsx index 156ca55..86f6777 100644 --- a/app/(account)/resend-confirm-email/page.tsx +++ b/app/(account)/resend-confirm-email/page.tsx @@ -50,8 +50,8 @@ const ResendConfirmationMail = () => {

Success!

Your request has been processed successfully. If your account is found in our system and the email address you provided matches our records, we have sent a confirmation email to that address.

-

Please check your inbox for the confirmation email. If you don't receive it within a few minutes, check - your spam or junk folder. For further assistance, don't hesitate to contact us.

+

Please check your inbox for the confirmation email. If you don't receive it within a few minutes, check + your spam or junk folder. For further assistance, don't hesitate to contact us.

); From 596b9644b8fd12b57b282b0e72d7dcae3206efc1 Mon Sep 17 00:00:00 2001 From: Gilles <43683714+corp-0@users.noreply.github.com> Date: Sat, 9 Mar 2024 17:19:02 -0300 Subject: [PATCH 15/21] chore: remove unused import --- app/(account)/confirm-email/[token]/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/(account)/confirm-email/[token]/actions.ts b/app/(account)/confirm-email/[token]/actions.ts index deedb65..d555853 100644 --- a/app/(account)/confirm-email/[token]/actions.ts +++ b/app/(account)/confirm-email/[token]/actions.ts @@ -1,6 +1,6 @@ "use server" -import {isFieldError, isGeneralError} from "../../../../lib/auth/guards"; +import {isFieldError} from "../../../../lib/auth/guards"; export const postMailConfirmationToken = async (token: string): Promise => { try { From 8c8361ee810f56568580f5867ce667df0053d209 Mon Sep 17 00:00:00 2001 From: Gilles <43683714+corp-0@users.noreply.github.com> Date: Sat, 9 Mar 2024 17:19:21 -0300 Subject: [PATCH 16/21] chore: remove unused import --- app/(account)/resend-confirm-email/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/(account)/resend-confirm-email/actions.ts b/app/(account)/resend-confirm-email/actions.ts index 5ff606f..b27851b 100644 --- a/app/(account)/resend-confirm-email/actions.ts +++ b/app/(account)/resend-confirm-email/actions.ts @@ -42,7 +42,7 @@ export const postResendConfirmationMail = async (_: ResendConfirmationMailReques return {success: false, error: error}; } - throw new Error('Unknown error'); + return {success: false, error: {error: 'An unexpected error happened', status: 500}}; } } catch (e) { From ef25810d623de5d968321248c2d0b8a7ddb58160 Mon Sep 17 00:00:00 2001 From: MaxIsJoe <34368774+MaxIsJoe@users.noreply.github.com> Date: Thu, 4 Jul 2024 18:27:15 +0300 Subject: [PATCH 17/21] First Draft of rules --- app/hub-rules/page.tsx | 159 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 app/hub-rules/page.tsx diff --git a/app/hub-rules/page.tsx b/app/hub-rules/page.tsx new file mode 100644 index 0000000..3b7d366 --- /dev/null +++ b/app/hub-rules/page.tsx @@ -0,0 +1,159 @@ +import FullPage from "../common/uiLibrary/Layouters/fullPage" + +const HubRules = async () => { + return ( + +
+
+

Stationhub Rules

+

This document specifies the rules that need to be followed when listing your community on our official server hub. If you are not sure whether something is allowed, or you think that something that is not allowed by the current rules should be allowed, feel free to contact us. We will clarify and possibly amend the rules.

+

We may change these rules from time to time, for example to add clarifications. When we do, it will be announced on our discord server.

+
+

How These Rules Are Applied

+
+

Strike System

+

+ Breaking some rules will lead to your community receiving one or more strikes. Strikes expire a year after their cause or causes are resolved. If you have three or more active strikes, your community will be permanently removed from the hub. +

+

+ You will be allowed to be relisted after enough strikes have expired to put you below three again. You must also have resolved the issue that caused the last strike. Contact us when this is the case, as we may not automatically relist you ourselves. +

+
+
+

Scope of Rules

+

+ These rules apply to any communities that have at least one server listed on the server hub. Our jurisdiction is as far as to remove your server(s) from the hub, and nothing more. +

+

+ We expect you to enforce some of these rules in other places than simply on-hub game servers. For example, 18+ rules may need to be enforced in your Discord or on any off-hub servers you have. +

+

+ We draw the line at what encapsulates a “community” on a case-by-case basis. This is based on shared branding, community spaces (e.g., Discord), infrastructure, and staff. For example, if you are a host that merely provides infrastructure for another community, you will get some degree of separation from said community. However, severe enough offenses may still make us come to you. +

+

+ When deciding whether an issue is your community’s fault, we will look at factors such as: +

+
    +
  • The status of the perpetrators in your community
  • +
  • The severity of the issue
  • +
  • Whether your community facilitates the issue or punished people for it
  • +
+

Some examples:

+
    +
  • Not accountable: a random player trash-talking another server after being banned there.
  • +
  • Accountable: a staff member perpetuating lies about another server to the point it becomes an issue for them.
  • +
  • Accountable: harassment perpetuated by a large group of members, with staff aware but letting it happen.
  • +
+
+
+

Enforcement Procedure

+

+ Depending on the scope and nature of the violation in question we will try to contact you privately and resolve things cleanly without a lasting strike. This depends on the kind offense in question and how cooperative you were to resolve the matter. +

+

+ If we do decide to hand out a strike, we expect you to resolve the problem within a reasonable timeframe. Failing this we may delist your server until the root problem is solved, regardless of total strikes remaining. +

+

+ We expect to be able to contact you about matters of the hub rules. You should have some form of contact information on your server: something as simple as a Discord or website link we can follow as a paper trail is good enough. If we are unable to contact you we may be forced to go immediately to delisting. +

+
+
+

The Rules

+

Section 1 (high severity)

+

These are the most important rules. Breaking one of them will lead to your community receiving up to three strikes at once. If you have a history of breaking these rules, that alone might be enough to disallow you from listing your server on the hub.

+

1.1 Do not harass, bully, brigade, defame, or doxx players, developers, or communities.

+
    +
  • Sharing IPs or hardware IDs with other server hosts for the purpose of banning and moderation is allowed.
  • +
  • Some guidance on what "harassment" constitutes: if somebody wants you to stop talking to or about them, you probably should.
  • +
+

1.2 Do not attempt anything that is illegal in the European Union.

+
    +
  • In order to keep Unitystation as a project and global community safe, we follow EU laws and regulations. We expect you to comply with them as well regardless of where you live. Actions that are considered illegal may include, but are not limited to: +
      +
    • Hosting content or facilitating activities that promote discrimination, hostility, or violence against individuals or groups based on identity or individual characteristics such as race, ethnicity, religion, or sexual orientation,
    • +
    • Network attacks such as distributed denial of service or unauthorized access,
    • +
    • Collecting data without user consent,
    • +
    • Distribution of malware,
    • +
    • Phishing and scams.
    • +
    +
  • +
  • If applicable, we may report you to government authorities.
  • +
  • Security vulnerabilities can be reported to our security team by joining our Discord and pinging or talking to someone with the @Engineers or @Lead Developer role.
  • +
  • Do not violate software licenses of other servers on the hub. This includes re-distributing the source code of secret repos or other license violations.
  • +
+ +

1.3 Do not abuse the hardware or internet connection of players for purposes that are not directly related to playing the game or collecting telemetry, even with consent.

+
    +
  • For example, do not mine cryptocurrency using the players` hardware.
  • +
  • Redirecting the players` connection to another server you control or have permission to redirect to is allowed, as long as you have player consent.
  • +
+ +

1.4 Servers containing mature elements such as erotic roleplay MUST clearly be marked as being 18+.

+
    +
  • Do this by putting [18+] clearly in the server name and tags.
  • +
+ +

1.5 If your server or community as a whole is 18+, you must do due diligence to remove underage players

+
    +
  • You must ensure that minors do not have an easy way to access your community by using age verification methods that are suitable for your community and moderation capabilities.
  • +
  • Upon learning that one of your community members is underage, you must remove them from your community immediately.
  • +
  • If you do not have mature themes (rule 1.4) and choose to mark your server as 18+ anyways, you still cannot make exceptions here.
  • +
+ +

1.6 Server staff members must not have a record of grooming or other predatory behavior.

+
    +
  • This counts for all servers, not just exclusively 18+ servers.
  • +
+ +

1.7 Do not send false information to the hub.

+
    +
  • For example, do not lie about player count or about what region your server is in.
  • +
+

1.8 Do not attempt to abuse loopholes in the hub rules or circumvent rulings

+
    +
  • For example: trying to circumvent strikes by making a "new" community.
  • +
+
+

Section 2 (medium severity)

+

Breaking one of these rules will lead to your community receiving at most one strike.

+

2.1. Keep your server names and descriptions clean

+
    +
  • They are visible to every player who uses the hub.
  • +
  • Keep it safe for work and free from vulgarity.
  • +
  • No bigotry, hate speech, descrimination, etc...
  • +
+

2.2. Do not impersonate other servers, developers, or organizations.

+
    +
  • If there is a reasonable way for players to be confused about the affiliations of your server, you're probably breaking this.
  • +
+

2.3. Don`t intentionally cause any sort of technical trouble for other communities, servers, the hub, or players.

+
+

Section 3 (low severity)

+

Breaking these rules will not lead your community to receiving any strikes, unless they are repeatedly broken or not resolved within a reasonable timeframe.

+

3.1. No advertising in the server name.

+

Server names are for describing a game, server, or community, and not for advertising unrelated services, causes, or other information.

+
    +
  • For example: +
      +
    • A name consisting of only "Hosted by XXX" is not allowed, because it is advertising a hosting service.
    • +
    • A name such as "Foo Station | Now with new and improved X and Y | Running map Z" is allowed, because it describes Foo Station.
    • +
    +
  • +
  • "Advertisements" as described in this rule are permitted in the server description (inside the foldout).
  • +
+

3.2. You may not use any of Unitystation`s services to keep up with the downfall of a civilization.

+

During the event a of a widespread viral infection transmitted via bites or contact with bodily fluids that causes human corpses to reanimate and seek to consume living human flesh, blood, brain or nerve tissue and is likely to result in the fall of organized civilization, You may not use any of Unitystation`s services to spread updates or information about the event. Services include but are not limited to:

+
    +
  • Stationhub
  • +
  • The official discord server*
  • +
+

*: The secret nsfw admin channel is exempt from this rule.

+
+
+
+
+
+ ) +} + +export default HubRules; From ba9bd7fcd199b334541718e913e715cbc400d7f0 Mon Sep 17 00:00:00 2001 From: MaxIsJoe <34368774+MaxIsJoe@users.noreply.github.com> Date: Thu, 4 Jul 2024 18:30:51 +0300 Subject: [PATCH 18/21] Update page.tsx --- app/hub-rules/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/hub-rules/page.tsx b/app/hub-rules/page.tsx index 3b7d366..0635f6c 100644 --- a/app/hub-rules/page.tsx +++ b/app/hub-rules/page.tsx @@ -70,7 +70,7 @@ const HubRules = async () => {
  • In order to keep Unitystation as a project and global community safe, we follow EU laws and regulations. We expect you to comply with them as well regardless of where you live. Actions that are considered illegal may include, but are not limited to:
      -
    • Hosting content or facilitating activities that promote discrimination, hostility, or violence against individuals or groups based on identity or individual characteristics such as race, ethnicity, religion, or sexual orientation,
    • +
    • Hosting content or facilitating activities that promote discrimination, hostility, or violence against individuals or groups based on identity or individual characteristics such as gender, race, ethnicity, religion, or sexual orientation,
    • Network attacks such as distributed denial of service or unauthorized access,
    • Collecting data without user consent,
    • Distribution of malware,
    • From 7194ba7d54387781337cba620b130104f3da384b Mon Sep 17 00:00:00 2001 From: MaxIsJoe <34368774+MaxIsJoe@users.noreply.github.com> Date: Thu, 4 Jul 2024 18:40:43 +0300 Subject: [PATCH 19/21] Update page.tsx --- app/hub-rules/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/hub-rules/page.tsx b/app/hub-rules/page.tsx index 0635f6c..3c59396 100644 --- a/app/hub-rules/page.tsx +++ b/app/hub-rules/page.tsx @@ -31,7 +31,7 @@ const HubRules = async () => { We draw the line at what encapsulates a “community” on a case-by-case basis. This is based on shared branding, community spaces (e.g., Discord), infrastructure, and staff. For example, if you are a host that merely provides infrastructure for another community, you will get some degree of separation from said community. However, severe enough offenses may still make us come to you.

      - When deciding whether an issue is your community’s fault, we will look at factors such as: + When deciding whether an issue is your community`s fault, we will look at factors such as:

      • The status of the perpetrators in your community
      • From 4437ea3aece9e55dc7f520e331872e15d3b0c991 Mon Sep 17 00:00:00 2001 From: MaxIsJoe <34368774+MaxIsJoe@users.noreply.github.com> Date: Thu, 4 Jul 2024 18:41:50 +0300 Subject: [PATCH 20/21] Update page.tsx --- app/hub-rules/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/hub-rules/page.tsx b/app/hub-rules/page.tsx index 3c59396..c0e75fe 100644 --- a/app/hub-rules/page.tsx +++ b/app/hub-rules/page.tsx @@ -3,7 +3,7 @@ import FullPage from "../common/uiLibrary/Layouters/fullPage" const HubRules = async () => { return ( -
        +

        Stationhub Rules

        This document specifies the rules that need to be followed when listing your community on our official server hub. If you are not sure whether something is allowed, or you think that something that is not allowed by the current rules should be allowed, feel free to contact us. We will clarify and possibly amend the rules.

        From e116a529c8f3e9e58daafd961c3fddc8c4c325a9 Mon Sep 17 00:00:00 2001 From: MaxIsJoe <34368774+MaxIsJoe@users.noreply.github.com> Date: Thu, 4 Jul 2024 19:52:38 +0300 Subject: [PATCH 21/21] COMPONENTS RGGAAHHH --- app/hub-rules/EnforcementProcedure.tsx | 20 +++ app/hub-rules/HowRulesApplied.tsx | 17 +++ app/hub-rules/Rule.tsx | 36 +++++ app/hub-rules/RuleCategory.tsx | 23 ++++ app/hub-rules/RulesIntroduction.tsx | 16 +++ app/hub-rules/RulesSection.tsx | 149 +++++++++++++++++++++ app/hub-rules/ScopeOfRules.tsx | 34 +++++ app/hub-rules/StrikeSystem.tsx | 17 +++ app/hub-rules/layout.tsx | 8 ++ app/hub-rules/page.tsx | 177 +++---------------------- 10 files changed, 340 insertions(+), 157 deletions(-) create mode 100644 app/hub-rules/EnforcementProcedure.tsx create mode 100644 app/hub-rules/HowRulesApplied.tsx create mode 100644 app/hub-rules/Rule.tsx create mode 100644 app/hub-rules/RuleCategory.tsx create mode 100644 app/hub-rules/RulesIntroduction.tsx create mode 100644 app/hub-rules/RulesSection.tsx create mode 100644 app/hub-rules/ScopeOfRules.tsx create mode 100644 app/hub-rules/StrikeSystem.tsx create mode 100644 app/hub-rules/layout.tsx diff --git a/app/hub-rules/EnforcementProcedure.tsx b/app/hub-rules/EnforcementProcedure.tsx new file mode 100644 index 0000000..79a8d6b --- /dev/null +++ b/app/hub-rules/EnforcementProcedure.tsx @@ -0,0 +1,20 @@ +import React from 'react'; + +const EnforcementProcedure = () => { + return ( +
        +

        Enforcement Procedure

        +

        + Depending on the scope and nature of the violation in question we will try to contact you privately and resolve things cleanly without a lasting strike. This depends on the kind offense in question and how cooperative you were to resolve the matter. +

        +

        + If we do decide to hand out a strike, we expect you to resolve the problem within a reasonable timeframe. Failing this we may delist your server until the root problem is solved, regardless of total strikes remaining. +

        +

        + We expect to be able to contact you about matters of the hub rules. You should have some form of contact information on your server: something as simple as a Discord or website link we can follow as a paper trail is good enough. If we are unable to contact you we may be forced to go immediately to delisting. +

        +
        + ); +}; + +export default EnforcementProcedure; diff --git a/app/hub-rules/HowRulesApplied.tsx b/app/hub-rules/HowRulesApplied.tsx new file mode 100644 index 0000000..ea967e1 --- /dev/null +++ b/app/hub-rules/HowRulesApplied.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import StrikeSystem from './StrikeSystem'; +import ScopeOfRules from './ScopeOfRules'; +import EnforcementProcedure from './EnforcementProcedure'; + +const HowRulesApplied = () => { + return ( +
        +

        How These Rules Are Applied

        + + + +
        + ); +}; + +export default HowRulesApplied; \ No newline at end of file diff --git a/app/hub-rules/Rule.tsx b/app/hub-rules/Rule.tsx new file mode 100644 index 0000000..49e1dc4 --- /dev/null +++ b/app/hub-rules/Rule.tsx @@ -0,0 +1,36 @@ +import React from 'react'; + +export interface RuleProps { + number: string; + text: string; + description?: string; + subRules?: string[]; + postNotes?: string[]; +} + +const Rule: React.FC = ({ number, text, description, subRules, postNotes }) => { + return ( + <> +

        {number}. {text}

        + {description && ( +

        {description}

        + )} + {subRules && ( +
          + {subRules.map((subRule, index) => ( +
        • {subRule}
        • + ))} +
        + )} + {postNotes && ( +
          + {postNotes.map((note, index) => ( +
        • {note}
        • + ))} +
        + )} + + ); +}; + +export default Rule; \ No newline at end of file diff --git a/app/hub-rules/RuleCategory.tsx b/app/hub-rules/RuleCategory.tsx new file mode 100644 index 0000000..d4c2f79 --- /dev/null +++ b/app/hub-rules/RuleCategory.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import Rule, { RuleProps } from './Rule'; + +interface RuleCategoryProps { + title: string; + description: string; + rules: RuleProps[]; +} + +const RuleCategory: React.FC = ({ title, description, rules }) => { + return ( + <> +

        {title}

        +

        {description}

        + {rules.map((rule, index) => ( + + ))} +
        + + ); +}; + +export default RuleCategory; diff --git a/app/hub-rules/RulesIntroduction.tsx b/app/hub-rules/RulesIntroduction.tsx new file mode 100644 index 0000000..c06291f --- /dev/null +++ b/app/hub-rules/RulesIntroduction.tsx @@ -0,0 +1,16 @@ +import React from 'react'; + +const RulesIntroduction = () => { + return ( + <> +

        + This document specifies the rules that need to be followed when listing your community on our official server hub. If you are not sure whether something is allowed, or you think that something that is not allowed by the current rules should be allowed, feel free to contact us. We will clarify and possibly amend the rules. +

        +

        + We may change these rules from time to time, for example to add clarifications. When we do, it will be announced on our discord server. +

        + + ); +}; + +export default RulesIntroduction; \ No newline at end of file diff --git a/app/hub-rules/RulesSection.tsx b/app/hub-rules/RulesSection.tsx new file mode 100644 index 0000000..aaecc83 --- /dev/null +++ b/app/hub-rules/RulesSection.tsx @@ -0,0 +1,149 @@ +// RulesSection.js +import React from 'react'; +import RuleCategory from './RuleCategory'; + +const RulesSection = () => { + const section1Rules = [ + { + number: "1.1", + text: "Do not harass, bully, brigade, defame, or doxx players, developers, or communities.", + subRules: [ + "Sharing IPs or hardware IDs with other server hosts for the purpose of banning and moderation is allowed.", + "Some guidance on what \"harassment\" constitutes: if somebody wants you to stop talking to or about them, you probably should." + ] + }, + { + number: "1.2", + text: "Do not attempt anything that is illegal in the European Union.", + description: "In order to keep Unitystation as a project and global community safe, we follow EU laws and regulations. We expect you to comply with them as well regardless of where you live. Actions that are considered illegal may include, but are not limited to:", + subRules: [ + "Hosting content or facilitating activities that promote discrimination, hostility, or violence against individuals or groups based on identity or individual characteristics such as gender, race, ethnicity, religion, or sexual orientation,", + "Network attacks such as distributed denial of service or unauthorized access,", + "Collecting data without user consent,", + "Distribution of malware,", + "Phishing and scams.", + ], + postNotes: [ + "If applicable, we may report you to government authorities.", + "Security vulnerabilities can be reported to our security team by joining our Discord and pinging or talking to someone with the @Engineers or @Lead Developer role.", + "Do not violate software licenses of other servers on the hub. This includes re-distributing the source code of secret repos or other license violations." + ], + }, + { + number: "1.3", + text: "Do not abuse the hardware or internet connection of players for purposes that are not directly related to playing the game or collecting telemetry, even with consent.", + subRules: [ + "For example, do not mine cryptocurrency using the players' hardware.", + "Redirecting the players' connection to another server you control or have permission to redirect to is allowed, as long as you have player consent." + ] + }, + { + number: "1.4", + text: "Servers containing mature elements such as erotic roleplay MUST clearly be marked as being 18+.", + subRules: [ + "Do this by putting [18+] clearly in the server name and tags." + ] + }, + { + number: "1.5", + text: "If your server or community as a whole is 18+, you must do due diligence to remove underage players", + subRules: [ + "You must ensure that minors do not have an easy way to access your community by using age verification methods that are suitable for your community and moderation capabilities.", + "Upon learning that one of your community members is underage, you must remove them from your community immediately.", + "If you do not have mature themes (rule 1.4) and choose to mark your server as 18+ anyways, you still cannot make exceptions here." + ] + }, + { + number: "1.6", + text: "Server staff members must not have a record of grooming or other predatory behavior.", + subRules: [ + "This counts for all servers, not just exclusively 18+ servers." + ] + }, + { + number: "1.7", + text: "Do not send false information to the hub.", + subRules: [ + "For example, do not lie about player count or about what region your server is in." + ] + }, + { + number: "1.8", + text: "Do not attempt to abuse loopholes in the hub rules or circumvent rulings", + subRules: [ + "For example: trying to circumvent strikes by making a \"new\" community." + ] + } + ]; + + const section2Rules = [ + { + number: "2.1", + text: "Keep your server names and descriptions clean", + subRules: [ + "They are visible to every player who uses the hub.", + "Keep it safe for work and free from vulgarity.", + "No bigotry, hate speech, discrimination, etc..." + ] + }, + { + number: "2.2", + text: "Do not impersonate other servers, developers, or organizations.", + subRules: [ + "If there is a reasonable way for players to be confused about the affiliations of your server, you're probably breaking this." + ] + }, + { + number: "2.3", + text: "Don't intentionally cause any sort of technical trouble for other communities, servers, the hub, or players." + } + ]; + + const section3Rules = [ + { + number: "3.1", + text: "No advertising in the server name.", + description: "Server names are for describing a game, server, or community, and not for advertising unrelated services, causes, or other information. For Example:", + subRules: [ + "A name consisting of only \"Hosted by XXX\" is not allowed, because it is advertising a hosting service.", + "A name such as \"Foo Station | Now with new and improved X and Y | Running map Z\" is allowed, because it describes Foo Station.", + "\"Advertisements\" as described in this rule are permitted in the server description (inside the foldout)." + ] + }, + { + number: "3.2", + text: "You may not use any of Unitystation's services to keep up with the downfall of a civilization.", + description: "During the event a of a widespread viral infection transmitted via bites or contact with bodily fluids that causes human corpses to reanimate and seek to consume living human flesh, blood, brain or nerve tissue and is likely to result in the fall of organized civilization, You may not use any of Unitystation's services to spread updates or information about the event. Services include but are not limited to:", + subRules: [ + "Stationhub", + "The official discord server*", + ], + postNotes: [ + "*: The secret nsfw admin channel is exempt from this rule." + ] + } + ]; + + return ( +
        +

        The Rules

        + + + +
        + ); +}; + +export default RulesSection; \ No newline at end of file diff --git a/app/hub-rules/ScopeOfRules.tsx b/app/hub-rules/ScopeOfRules.tsx new file mode 100644 index 0000000..62be06c --- /dev/null +++ b/app/hub-rules/ScopeOfRules.tsx @@ -0,0 +1,34 @@ +import React from 'react'; + +const ScopeOfRules = () => { + return ( +
        +

        Scope of Rules

        +

        + These rules apply to any communities that have at least one server listed on the server hub. Our jurisdiction is as far as to remove your server(s) from the hub, and nothing more. +

        +

        + We expect you to enforce some of these rules in other places than simply on-hub game servers. For example, 18+ rules may need to be enforced in your Discord or on any off-hub servers you have. +

        +

        + We draw the line at what encapsulates a “community” on a case-by-case basis. This is based on shared branding, community spaces (e.g., Discord), infrastructure, and staff. For example, if you are a host that merely provides infrastructure for another community, you will get some degree of separation from said community. However, severe enough offenses may still make us come to you. +

        +

        + When deciding whether an issue is your community's fault, we will look at factors such as: +

        +
          +
        • The status of the perpetrators in your community
        • +
        • The severity of the issue
        • +
        • Whether your community facilitates the issue or punished people for it
        • +
        +

        Some examples:

        +
          +
        • Not accountable: a random player trash-talking another server after being banned there.
        • +
        • Accountable: a staff member perpetuating lies about another server to the point it becomes an issue for them.
        • +
        • Accountable: harassment perpetuated by a large group of members, with staff aware but letting it happen.
        • +
        +
        + ); +}; + +export default ScopeOfRules; diff --git a/app/hub-rules/StrikeSystem.tsx b/app/hub-rules/StrikeSystem.tsx new file mode 100644 index 0000000..f470a12 --- /dev/null +++ b/app/hub-rules/StrikeSystem.tsx @@ -0,0 +1,17 @@ +import React from 'react'; + +const StrikeSystem = () => { + return ( +
        +

        Strike System

        +

        + Breaking some rules will lead to your community receiving one or more strikes. Strikes expire a year after their cause or causes are resolved. If you have three or more active strikes, your community will be permanently removed from the hub. +

        +

        + You will be allowed to be relisted after enough strikes have expired to put you below three again. You must also have resolved the issue that caused the last strike. Contact us when this is the case, as we may not automatically relist you ourselves. +

        +
        + ); +}; + +export default StrikeSystem; diff --git a/app/hub-rules/layout.tsx b/app/hub-rules/layout.tsx new file mode 100644 index 0000000..a93046b --- /dev/null +++ b/app/hub-rules/layout.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import FullPage from "../common/uiLibrary/Layouters/fullPage"; + +const PageLayout = ({ children }) => { + return {children}; +}; + +export default PageLayout; \ No newline at end of file diff --git a/app/hub-rules/page.tsx b/app/hub-rules/page.tsx index c0e75fe..570ea81 100644 --- a/app/hub-rules/page.tsx +++ b/app/hub-rules/page.tsx @@ -1,159 +1,22 @@ -import FullPage from "../common/uiLibrary/Layouters/fullPage" +import React from 'react'; +import PageLayout from './layout'; +import RulesIntroduction from './RulesIntroduction'; +import HowRulesApplied from './HowRulesApplied'; +import RulesSection from './RulesSection'; -const HubRules = async () => { - return ( - -
        -
        -

        Stationhub Rules

        -

        This document specifies the rules that need to be followed when listing your community on our official server hub. If you are not sure whether something is allowed, or you think that something that is not allowed by the current rules should be allowed, feel free to contact us. We will clarify and possibly amend the rules.

        -

        We may change these rules from time to time, for example to add clarifications. When we do, it will be announced on our discord server.

        -
        -

        How These Rules Are Applied

        -
        -

        Strike System

        -

        - Breaking some rules will lead to your community receiving one or more strikes. Strikes expire a year after their cause or causes are resolved. If you have three or more active strikes, your community will be permanently removed from the hub. -

        -

        - You will be allowed to be relisted after enough strikes have expired to put you below three again. You must also have resolved the issue that caused the last strike. Contact us when this is the case, as we may not automatically relist you ourselves. -

        -
        -
        -

        Scope of Rules

        -

        - These rules apply to any communities that have at least one server listed on the server hub. Our jurisdiction is as far as to remove your server(s) from the hub, and nothing more. -

        -

        - We expect you to enforce some of these rules in other places than simply on-hub game servers. For example, 18+ rules may need to be enforced in your Discord or on any off-hub servers you have. -

        -

        - We draw the line at what encapsulates a “community” on a case-by-case basis. This is based on shared branding, community spaces (e.g., Discord), infrastructure, and staff. For example, if you are a host that merely provides infrastructure for another community, you will get some degree of separation from said community. However, severe enough offenses may still make us come to you. -

        -

        - When deciding whether an issue is your community`s fault, we will look at factors such as: -

        -
          -
        • The status of the perpetrators in your community
        • -
        • The severity of the issue
        • -
        • Whether your community facilitates the issue or punished people for it
        • -
        -

        Some examples:

        -
          -
        • Not accountable: a random player trash-talking another server after being banned there.
        • -
        • Accountable: a staff member perpetuating lies about another server to the point it becomes an issue for them.
        • -
        • Accountable: harassment perpetuated by a large group of members, with staff aware but letting it happen.
        • -
        -
        -
        -

        Enforcement Procedure

        -

        - Depending on the scope and nature of the violation in question we will try to contact you privately and resolve things cleanly without a lasting strike. This depends on the kind offense in question and how cooperative you were to resolve the matter. -

        -

        - If we do decide to hand out a strike, we expect you to resolve the problem within a reasonable timeframe. Failing this we may delist your server until the root problem is solved, regardless of total strikes remaining. -

        -

        - We expect to be able to contact you about matters of the hub rules. You should have some form of contact information on your server: something as simple as a Discord or website link we can follow as a paper trail is good enough. If we are unable to contact you we may be forced to go immediately to delisting. -

        -
        -
        -

        The Rules

        -

        Section 1 (high severity)

        -

        These are the most important rules. Breaking one of them will lead to your community receiving up to three strikes at once. If you have a history of breaking these rules, that alone might be enough to disallow you from listing your server on the hub.

        -

        1.1 Do not harass, bully, brigade, defame, or doxx players, developers, or communities.

        -
          -
        • Sharing IPs or hardware IDs with other server hosts for the purpose of banning and moderation is allowed.
        • -
        • Some guidance on what "harassment" constitutes: if somebody wants you to stop talking to or about them, you probably should.
        • -
        -

        1.2 Do not attempt anything that is illegal in the European Union.

        -
          -
        • In order to keep Unitystation as a project and global community safe, we follow EU laws and regulations. We expect you to comply with them as well regardless of where you live. Actions that are considered illegal may include, but are not limited to: -
            -
          • Hosting content or facilitating activities that promote discrimination, hostility, or violence against individuals or groups based on identity or individual characteristics such as gender, race, ethnicity, religion, or sexual orientation,
          • -
          • Network attacks such as distributed denial of service or unauthorized access,
          • -
          • Collecting data without user consent,
          • -
          • Distribution of malware,
          • -
          • Phishing and scams.
          • -
          -
        • -
        • If applicable, we may report you to government authorities.
        • -
        • Security vulnerabilities can be reported to our security team by joining our Discord and pinging or talking to someone with the @Engineers or @Lead Developer role.
        • -
        • Do not violate software licenses of other servers on the hub. This includes re-distributing the source code of secret repos or other license violations.
        • -
        - -

        1.3 Do not abuse the hardware or internet connection of players for purposes that are not directly related to playing the game or collecting telemetry, even with consent.

        -
          -
        • For example, do not mine cryptocurrency using the players` hardware.
        • -
        • Redirecting the players` connection to another server you control or have permission to redirect to is allowed, as long as you have player consent.
        • -
        - -

        1.4 Servers containing mature elements such as erotic roleplay MUST clearly be marked as being 18+.

        -
          -
        • Do this by putting [18+] clearly in the server name and tags.
        • -
        - -

        1.5 If your server or community as a whole is 18+, you must do due diligence to remove underage players

        -
          -
        • You must ensure that minors do not have an easy way to access your community by using age verification methods that are suitable for your community and moderation capabilities.
        • -
        • Upon learning that one of your community members is underage, you must remove them from your community immediately.
        • -
        • If you do not have mature themes (rule 1.4) and choose to mark your server as 18+ anyways, you still cannot make exceptions here.
        • -
        - -

        1.6 Server staff members must not have a record of grooming or other predatory behavior.

        -
          -
        • This counts for all servers, not just exclusively 18+ servers.
        • -
        - -

        1.7 Do not send false information to the hub.

        -
          -
        • For example, do not lie about player count or about what region your server is in.
        • -
        -

        1.8 Do not attempt to abuse loopholes in the hub rules or circumvent rulings

        -
          -
        • For example: trying to circumvent strikes by making a "new" community.
        • -
        -
        -

        Section 2 (medium severity)

        -

        Breaking one of these rules will lead to your community receiving at most one strike.

        -

        2.1. Keep your server names and descriptions clean

        -
          -
        • They are visible to every player who uses the hub.
        • -
        • Keep it safe for work and free from vulgarity.
        • -
        • No bigotry, hate speech, descrimination, etc...
        • -
        -

        2.2. Do not impersonate other servers, developers, or organizations.

        -
          -
        • If there is a reasonable way for players to be confused about the affiliations of your server, you're probably breaking this.
        • -
        -

        2.3. Don`t intentionally cause any sort of technical trouble for other communities, servers, the hub, or players.

        -
        -

        Section 3 (low severity)

        -

        Breaking these rules will not lead your community to receiving any strikes, unless they are repeatedly broken or not resolved within a reasonable timeframe.

        -

        3.1. No advertising in the server name.

        -

        Server names are for describing a game, server, or community, and not for advertising unrelated services, causes, or other information.

        -
          -
        • For example: -
            -
          • A name consisting of only "Hosted by XXX" is not allowed, because it is advertising a hosting service.
          • -
          • A name such as "Foo Station | Now with new and improved X and Y | Running map Z" is allowed, because it describes Foo Station.
          • -
          -
        • -
        • "Advertisements" as described in this rule are permitted in the server description (inside the foldout).
        • -
        -

        3.2. You may not use any of Unitystation`s services to keep up with the downfall of a civilization.

        -

        During the event a of a widespread viral infection transmitted via bites or contact with bodily fluids that causes human corpses to reanimate and seek to consume living human flesh, blood, brain or nerve tissue and is likely to result in the fall of organized civilization, You may not use any of Unitystation`s services to spread updates or information about the event. Services include but are not limited to:

        -
          -
        • Stationhub
        • -
        • The official discord server*
        • -
        -

        *: The secret nsfw admin channel is exempt from this rule.

        -
        -
        -
        -
        -
        - ) -} +const HubRules = () => { + return ( + +
        +
        +

        Stationhub Rules

        + + + +
        +
        +
        + ); +}; -export default HubRules; +export default HubRules; \ No newline at end of file