mirror of
https://github.com/OneUptime/oneuptime
synced 2024-11-21 14:49:07 +00:00
fix fmt
This commit is contained in:
parent
a25a1ed0b9
commit
9bd8275321
@ -107,7 +107,7 @@ const LoginPage: () => JSX.Element = () => {
|
||||
maxPrimaryButtonWidth={true}
|
||||
footer={
|
||||
<div className="actions pointer text-center mt-4 hover:underline fw-semibold">
|
||||
<p>
|
||||
<div>
|
||||
{!showSsoTip && (
|
||||
<div
|
||||
onClick={() => {
|
||||
@ -128,13 +128,13 @@ const LoginPage: () => JSX.Element = () => {
|
||||
your project.
|
||||
</div>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-10 text-center">
|
||||
<p className="text-muted mb-0 text-gray-500">
|
||||
<div className="text-muted mb-0 text-gray-500">
|
||||
Don't have an account?{' '}
|
||||
<Link
|
||||
to={new Route('/accounts/register')}
|
||||
@ -142,7 +142,7 @@ const LoginPage: () => JSX.Element = () => {
|
||||
>
|
||||
Register.
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -9,12 +9,21 @@ import UserUtil from 'CommonUI/src/Utils/User';
|
||||
import Navigation from 'CommonUI/src/Utils/Navigation';
|
||||
import { ACCOUNTS_URL } from 'CommonUI/src/Config';
|
||||
import UiAnalytics from 'CommonUI/src/Utils/Analytics';
|
||||
import ErrorMessage from 'CommonUI/src/Components/ErrorMessage/ErrorMessage';
|
||||
|
||||
const Logout: FunctionComponent = (): ReactElement => {
|
||||
useEffect(() => {
|
||||
const [error, setError] = React.useState<string | null>(null);
|
||||
|
||||
const logout: Function = async () => {
|
||||
UiAnalytics.logout();
|
||||
UserUtil.logout();
|
||||
await UserUtil.logout();
|
||||
Navigation.navigate(ACCOUNTS_URL);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
logout().catch((error: Error) => {
|
||||
setError(error.message || error.toString());
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@ -35,7 +44,8 @@ const Logout: FunctionComponent = (): ReactElement => {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<PageLoader isVisible={true} />
|
||||
{!error ? <PageLoader isVisible={true} /> : <></>}
|
||||
{error ? <ErrorMessage error={error} /> : <></>}
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
@ -42,8 +42,11 @@ export default class UserMiddleware {
|
||||
public static getAccessToken(req: ExpressRequest): string | null {
|
||||
let accessToken: string | null = null;
|
||||
|
||||
if(CookieUtil.getCookie(req, "user-token")){
|
||||
accessToken = CookieUtil.getCookie(req, "user-token");
|
||||
if (CookieUtil.getCookie(req, CookieUtil.getUserTokenKey())) {
|
||||
accessToken = CookieUtil.getCookie(
|
||||
req,
|
||||
CookieUtil.getUserTokenKey()
|
||||
);
|
||||
}
|
||||
|
||||
return accessToken;
|
||||
@ -52,14 +55,13 @@ export default class UserMiddleware {
|
||||
public static getSsoTokens(req: ExpressRequest): Dictionary<string> {
|
||||
const ssoTokens: Dictionary<string> = {};
|
||||
|
||||
// get sso tokens from cookies.
|
||||
// get sso tokens from cookies.
|
||||
|
||||
const cookies: Dictionary<string> = CookieUtil.getAllCookies(req);
|
||||
|
||||
for (const key of Object.keys(cookies)) {
|
||||
if (key.startsWith('sso-')) {
|
||||
const value: string | undefined | Array<string> =
|
||||
cookies[key];
|
||||
if (key.startsWith(CookieUtil.getSSOKey())) {
|
||||
const value: string | undefined | Array<string> = cookies[key];
|
||||
let projectId: string | undefined = undefined;
|
||||
|
||||
try {
|
||||
|
@ -24,6 +24,7 @@ import TeamMemberService from './TeamMemberService';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import Hostname from 'Common/Types/API/Hostname';
|
||||
import Protocol from 'Common/Types/API/Protocol';
|
||||
import CookieUtil from '../Utils/Cookie';
|
||||
|
||||
export class Service extends DatabaseService<StatusPage> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
@ -191,8 +192,10 @@ export class Service extends DatabaseService<StatusPage> {
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
// token decode.
|
||||
const token: string | Array<string> | undefined =
|
||||
req.headers['status-page-token'];
|
||||
const token: string | undefined = CookieUtil.getCookie(
|
||||
req,
|
||||
CookieUtil.getUserTokenKey(statusPageId)
|
||||
);
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
|
@ -1,28 +1,53 @@
|
||||
import { CookieOptions } from "express";
|
||||
import { ExpressRequest, ExpressResponse } from "./Express";
|
||||
import { CookieOptions } from 'express';
|
||||
import { ExpressRequest, ExpressResponse } from './Express';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import Dictionary from 'Common/Types/Dictionary';
|
||||
|
||||
export default class CookieUtil {
|
||||
export default class CookieUtil {
|
||||
// set cookie with express response
|
||||
|
||||
public static setCookie(res: ExpressResponse, name: string, value: string, options: CookieOptions) {
|
||||
public static setCookie(
|
||||
res: ExpressResponse,
|
||||
name: string,
|
||||
value: string,
|
||||
options: CookieOptions
|
||||
): void {
|
||||
res.cookie(name, value, options);
|
||||
}
|
||||
|
||||
// get cookie with express request
|
||||
|
||||
public static getCookie(req: ExpressRequest, name: string) {
|
||||
public static getCookie(
|
||||
req: ExpressRequest,
|
||||
name: string
|
||||
): string | undefined {
|
||||
return req.cookies[name];
|
||||
}
|
||||
|
||||
// delete cookie with express response
|
||||
|
||||
public static removeCookie(res: ExpressResponse, name: string) {
|
||||
public static removeCookie(res: ExpressResponse, name: string): void {
|
||||
res.clearCookie(name);
|
||||
}
|
||||
|
||||
// get all cookies with express request
|
||||
public static getAllCookies(req: ExpressRequest) {
|
||||
public static getAllCookies(req: ExpressRequest): Dictionary<string> {
|
||||
return req.cookies;
|
||||
}
|
||||
|
||||
}
|
||||
public static getUserTokenKey(id?: ObjectID): string {
|
||||
if (!id) {
|
||||
return `user-token`;
|
||||
}
|
||||
|
||||
return `user-token-${id.toString()}`;
|
||||
}
|
||||
|
||||
public static getUserSSOKey(id: ObjectID): string {
|
||||
return `${this.getSSOKey()}${id.toString()}`;
|
||||
}
|
||||
|
||||
public static getSSOKey(): string {
|
||||
return `sso-`;
|
||||
}
|
||||
}
|
||||
|
@ -40,9 +40,9 @@ const FieldLabelElement: FunctionComponent<ComponentProps> = (
|
||||
</label>
|
||||
|
||||
{props.description && (
|
||||
<p className="mt-1 text-sm text-gray-500">
|
||||
<div className="mt-1 text-sm text-gray-500">
|
||||
{props.description}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
@ -176,7 +176,9 @@ const TableRow: FunctionComponent<ComponentProps> = (
|
||||
props.item
|
||||
)
|
||||
) {
|
||||
return <></>;
|
||||
return (
|
||||
<div key={i}></div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -7,10 +7,16 @@ import UniversalCookies from 'universal-cookie';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
|
||||
export default class Cookie {
|
||||
public static setItem(key: string, value: JSONValue | Email | URL, options?: {
|
||||
httpOnly?: boolean | undefined,
|
||||
path: Route,
|
||||
} | undefined): void {
|
||||
public static setItem(
|
||||
key: string,
|
||||
value: JSONValue | Email | URL,
|
||||
options?:
|
||||
| {
|
||||
httpOnly?: boolean | undefined;
|
||||
path: Route;
|
||||
}
|
||||
| undefined
|
||||
): void {
|
||||
if (typeof value === Typeof.Object) {
|
||||
// if of type jsonobject.
|
||||
value = JSON.stringify(
|
||||
@ -21,12 +27,11 @@ export default class Cookie {
|
||||
const cookies: UniversalCookies = new UniversalCookies();
|
||||
cookies.set(key, value as string, {
|
||||
httpOnly: options?.httpOnly || false,
|
||||
path: options?.path ? options.path.toString() : '/'
|
||||
path: options?.path ? options.path.toString() : '/',
|
||||
});
|
||||
}
|
||||
|
||||
public static getItem(key: string): JSONValue {
|
||||
|
||||
const cookies: UniversalCookies = new UniversalCookies();
|
||||
const value: JSONValue = cookies.get(key) as JSONValue;
|
||||
|
||||
|
@ -6,9 +6,10 @@ import ObjectID from 'Common/Types/ObjectID';
|
||||
import Name from 'Common/Types/Name';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import Dictionary from 'Common/Types/Dictionary';
|
||||
import API from 'Common/Utils/API';
|
||||
import { IDENTITY_URL } from '../Config';
|
||||
|
||||
export default class User {
|
||||
|
||||
public static setProfilePicId(id: ObjectID | null): void {
|
||||
if (!id) {
|
||||
LocalStorage.removeItem('profile_pic_id');
|
||||
@ -53,10 +54,10 @@ export default class User {
|
||||
}
|
||||
|
||||
public static getEmail(): Email | null {
|
||||
if(!LocalStorage.getItem('user_email')){
|
||||
if (!LocalStorage.getItem('user_email')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return new Email(LocalStorage.getItem('user_email') as string);
|
||||
}
|
||||
|
||||
@ -110,11 +111,13 @@ export default class User {
|
||||
}
|
||||
|
||||
public static isLoggedIn(): boolean {
|
||||
return !!this.getEmail();
|
||||
return Boolean(this.getEmail());
|
||||
}
|
||||
|
||||
public static async logout(): Promise<void> {
|
||||
// TODO: Clear all cookies here.
|
||||
await API.post(
|
||||
URL.fromString(IDENTITY_URL.toString()).addRoute('/logout')
|
||||
);
|
||||
LocalStorage.clear();
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,6 @@ const Init: FunctionComponent<ComponentProps> = (
|
||||
alert('Project ID not found in the SSO token. Logging out.');
|
||||
return Navigation.navigate(RouteMap[PageMap.LOGOUT] as Route);
|
||||
}
|
||||
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
@ -10,14 +10,25 @@ import Navigation from 'CommonUI/src/Utils/Navigation';
|
||||
import { ACCOUNTS_URL } from 'CommonUI/src/Config';
|
||||
import UiAnalytics from 'CommonUI/src/Utils/Analytics';
|
||||
import useAsyncEffect from 'use-async-effect';
|
||||
import ErrorMessage from 'CommonUI/src/Components/ErrorMessage/ErrorMessage';
|
||||
|
||||
const Logout: FunctionComponent<PageComponentProps> = (
|
||||
_props: PageComponentProps
|
||||
): ReactElement => {
|
||||
const [error, setError] = React.useState<string | null>(null);
|
||||
|
||||
useAsyncEffect(async () => {
|
||||
UiAnalytics.logout();
|
||||
await UserUtil.logout();
|
||||
Navigation.navigate(ACCOUNTS_URL);
|
||||
try {
|
||||
UiAnalytics.logout();
|
||||
await UserUtil.logout();
|
||||
Navigation.navigate(ACCOUNTS_URL);
|
||||
} catch (err: unknown) {
|
||||
if (err instanceof Error) {
|
||||
setError(err.message || err.toString());
|
||||
} else {
|
||||
setError('Unknown error');
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@ -32,7 +43,8 @@ const Logout: FunctionComponent<PageComponentProps> = (
|
||||
},
|
||||
]}
|
||||
>
|
||||
<PageLoader isVisible={true} />
|
||||
{!error ? <PageLoader isVisible={true} /> : <></>}
|
||||
{error ? <ErrorMessage error={error} /> : <></>}
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
@ -185,7 +185,7 @@ router.post(
|
||||
);
|
||||
|
||||
// Set a cookie with token.
|
||||
CookieUtil.setCookie(res, 'user-token', token, {
|
||||
CookieUtil.setCookie(res, CookieUtil.getUserTokenKey(), token, {
|
||||
maxAge: OneUptimeDate.getSecondsInDays(
|
||||
new PositiveNumber(30)
|
||||
),
|
||||
@ -494,15 +494,14 @@ router.post(
|
||||
next: NextFunction
|
||||
): Promise<void> => {
|
||||
try {
|
||||
CookieUtil.removeCookie(res, 'user-token');
|
||||
CookieUtil.removeCookie(res, CookieUtil.getUserTokenKey()); // remove the cookie.
|
||||
|
||||
// remove all sso cookies as well.
|
||||
|
||||
return Response.sendEmptyResponse(req, res);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/login',
|
||||
@ -576,13 +575,18 @@ router.post(
|
||||
OneUptimeDate.getSecondsInDays(new PositiveNumber(30))
|
||||
);
|
||||
|
||||
// Set a cookie with token.
|
||||
CookieUtil.setCookie(res, 'user-token', token, {
|
||||
maxAge: OneUptimeDate.getSecondsInDays(
|
||||
new PositiveNumber(30)
|
||||
),
|
||||
httpOnly: true,
|
||||
});
|
||||
// Set a cookie with token.
|
||||
CookieUtil.setCookie(
|
||||
res,
|
||||
CookieUtil.getUserTokenKey(),
|
||||
token,
|
||||
{
|
||||
maxAge: OneUptimeDate.getSecondsInDays(
|
||||
new PositiveNumber(30)
|
||||
),
|
||||
httpOnly: true,
|
||||
}
|
||||
);
|
||||
|
||||
return Response.sendEntityResponse(
|
||||
req,
|
||||
|
@ -327,10 +327,14 @@ router.post(
|
||||
});
|
||||
}
|
||||
|
||||
const projectId: ObjectID = new ObjectID(
|
||||
req.params['projectId'] as string
|
||||
);
|
||||
|
||||
const token: string = JSONWebToken.sign(
|
||||
{
|
||||
userId: alreadySavedUser.id!,
|
||||
projectId: new ObjectID(req.params['projectId']),
|
||||
projectId: projectId,
|
||||
email: email,
|
||||
isMasterAdmin: false,
|
||||
},
|
||||
@ -346,12 +350,17 @@ router.post(
|
||||
const httpProtocol: Protocol =
|
||||
await DatabaseConfig.getHttpProtocol();
|
||||
|
||||
CookieUtil.setCookie(res, 'sso-'+req.params['projectId'].toString(), token, {
|
||||
maxAge: OneUptimeDate.getSecondsInDays(
|
||||
new PositiveNumber(30)
|
||||
),
|
||||
httpOnly: true,
|
||||
});
|
||||
CookieUtil.setCookie(
|
||||
res,
|
||||
CookieUtil.getUserSSOKey(projectId),
|
||||
token,
|
||||
{
|
||||
maxAge: OneUptimeDate.getSecondsInDays(
|
||||
new PositiveNumber(30)
|
||||
),
|
||||
httpOnly: true,
|
||||
}
|
||||
);
|
||||
|
||||
return Response.redirect(
|
||||
req,
|
||||
|
@ -25,9 +25,38 @@ import StatusPageService from 'CommonServer/Services/StatusPageService';
|
||||
import Protocol from 'Common/Types/API/Protocol';
|
||||
import Hostname from 'Common/Types/API/Hostname';
|
||||
import DatabaseConfig from 'CommonServer/DatabaseConfig';
|
||||
import CookieUtil from 'CommonServer/Utils/Cookie';
|
||||
|
||||
const router: ExpressRouter = Express.getRouter();
|
||||
|
||||
router.post(
|
||||
'/logout/:status-page-id',
|
||||
async (
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
next: NextFunction
|
||||
): Promise<void> => {
|
||||
try {
|
||||
if (!req.params['status-page-id']) {
|
||||
throw new BadDataException('Status Page ID is required.');
|
||||
}
|
||||
|
||||
const statusPageId: ObjectID = new ObjectID(
|
||||
req.params['status-page-id'].toString()
|
||||
);
|
||||
|
||||
CookieUtil.removeCookie(
|
||||
res,
|
||||
CookieUtil.getUserTokenKey(statusPageId)
|
||||
); // remove the cookie.
|
||||
|
||||
return Response.sendEmptyResponse(req, res);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/forgot-password',
|
||||
async (
|
||||
@ -364,16 +393,24 @@ router.post(
|
||||
OneUptimeDate.getSecondsInDays(new PositiveNumber(30))
|
||||
);
|
||||
|
||||
// Set a cookie with token.
|
||||
CookieUtil.setCookie(
|
||||
res,
|
||||
CookieUtil.getUserTokenKey(user.statusPageId!),
|
||||
token,
|
||||
{
|
||||
maxAge: OneUptimeDate.getSecondsInDays(
|
||||
new PositiveNumber(30)
|
||||
),
|
||||
httpOnly: true,
|
||||
}
|
||||
);
|
||||
|
||||
return Response.sendEntityResponse(
|
||||
req,
|
||||
res,
|
||||
alreadySavedUser,
|
||||
StatusPagePrivateUser,
|
||||
{
|
||||
miscData: {
|
||||
token,
|
||||
},
|
||||
}
|
||||
StatusPagePrivateUser
|
||||
);
|
||||
}
|
||||
throw new BadDataException(
|
||||
|
@ -24,6 +24,7 @@ import StatusPagePrivateUser from 'Model/Models/StatusPagePrivateUser';
|
||||
import StatusPagePrivateUserService from 'CommonServer/Services/StatusPagePrivateUserService';
|
||||
import HashedString from 'Common/Types/HashedString';
|
||||
import StatusPageService from 'CommonServer/Services/StatusPageService';
|
||||
import CookieUtil from 'CommonServer/Utils/Cookie';
|
||||
|
||||
const router: ExpressRouter = Express.getRouter();
|
||||
|
||||
@ -274,6 +275,18 @@ router.post(
|
||||
OneUptimeDate.getSecondsInDays(new PositiveNumber(30))
|
||||
);
|
||||
|
||||
CookieUtil.setCookie(
|
||||
res,
|
||||
CookieUtil.getUserTokenKey(statusPageId),
|
||||
token,
|
||||
{
|
||||
maxAge: OneUptimeDate.getSecondsInDays(
|
||||
new PositiveNumber(30)
|
||||
),
|
||||
httpOnly: true,
|
||||
}
|
||||
);
|
||||
|
||||
// get status page URL.
|
||||
const statusPageURL: string =
|
||||
await StatusPageService.getStatusPageFirstURL(statusPageId);
|
||||
|
@ -5,11 +5,14 @@ import RouteMap, { RouteUtil } from '../../Utils/RouteMap';
|
||||
import PageMap from '../../Utils/PageMap';
|
||||
import PageLoader from 'CommonUI/src/Components/Loader/PageLoader';
|
||||
import StatusPageUtil from '../../Utils/StatusPage';
|
||||
import ErrorMessage from 'CommonUI/src/Components/ErrorMessage/ErrorMessage';
|
||||
|
||||
const Logout: () => JSX.Element = () => {
|
||||
useEffect(() => {
|
||||
const [error, setError] = React.useState<string | null>(null);
|
||||
|
||||
const logout: Function = async () => {
|
||||
if (StatusPageUtil.getStatusPageId()) {
|
||||
UserUtil.logout(StatusPageUtil.getStatusPageId()!);
|
||||
await UserUtil.logout(StatusPageUtil.getStatusPageId()!);
|
||||
Navigation.navigate(
|
||||
StatusPageUtil.isPreviewPage()
|
||||
? RouteUtil.populateRouteParams(
|
||||
@ -22,8 +25,18 @@ const Logout: () => JSX.Element = () => {
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
logout().catch((error: Error) => {
|
||||
setError(error.message || error.toString());
|
||||
});
|
||||
}, [StatusPageUtil.getStatusPageId()]);
|
||||
|
||||
if (error) {
|
||||
return <ErrorMessage error={error} />;
|
||||
}
|
||||
|
||||
return <PageLoader isVisible={true} />;
|
||||
};
|
||||
|
||||
|
@ -11,11 +11,9 @@ export default abstract class LoginUtil {
|
||||
value['user'] as JSONObject,
|
||||
StatusPagePrivateUser
|
||||
) as StatusPagePrivateUser;
|
||||
const token: string = value['token'] as string;
|
||||
|
||||
const statusPageId: ObjectID = user.statusPageId!;
|
||||
|
||||
UserUtil.setAccessToken(statusPageId, token);
|
||||
UserUtil.setEmail(statusPageId, user.email as Email);
|
||||
UserUtil.setUserId(statusPageId, user.id as ObjectID);
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import ObjectID from 'Common/Types/ObjectID';
|
||||
import Name from 'Common/Types/Name';
|
||||
|
||||
export default class User {
|
||||
|
||||
public static setUserId(statusPageId: ObjectID, userId: ObjectID): void {
|
||||
LocalStorage.setItem(
|
||||
statusPageId.toString() + 'user_id',
|
||||
@ -35,7 +34,11 @@ export default class User {
|
||||
);
|
||||
}
|
||||
|
||||
public static getEmail(statusPageId: ObjectID): Email {
|
||||
public static getEmail(statusPageId: ObjectID): Email | null {
|
||||
if (!LocalStorage.getItem(statusPageId.toString() + 'user_email')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Email(
|
||||
LocalStorage.getItem(
|
||||
statusPageId.toString() + 'user_email'
|
||||
@ -51,10 +54,6 @@ export default class User {
|
||||
LocalStorage.removeItem(statusPageId.toString() + 'user_id');
|
||||
}
|
||||
|
||||
public static removeAccessToken(statusPageId: ObjectID): void {
|
||||
LocalStorage.removeItem(statusPageId.toString() + 'access_token');
|
||||
}
|
||||
|
||||
public static removeInitialUrl(statusPageId: ObjectID): void {
|
||||
return sessionStorage.removeItem(
|
||||
statusPageId.toString() + 'initialUrl'
|
||||
@ -62,13 +61,10 @@ export default class User {
|
||||
}
|
||||
|
||||
public static isLoggedIn(statusPageId: ObjectID): boolean {
|
||||
return LocalStorage.getItem(statusPageId.toString() + 'access_token')
|
||||
? true
|
||||
: false;
|
||||
return Boolean(this.getEmail(statusPageId));
|
||||
}
|
||||
|
||||
public static logout(statusPageId: ObjectID): void {
|
||||
User.removeAccessToken(statusPageId);
|
||||
public static async logout(statusPageId: ObjectID): Promise<void> {
|
||||
User.removeUserId(statusPageId);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user