mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
upgrade deps
This commit is contained in:
9 files changed
+36
-74
No files matched your search
@@ -4,9 +4,9 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "react.yaml",
|
"main": "react.yaml",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@stylistic/eslint-plugin": "^2.12.0",
|
"@stylistic/eslint-plugin": "^2.12.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.17.0",
|
"@typescript-eslint/eslint-plugin": "^8.18.0",
|
||||||
"@typescript-eslint/parser": "^8.17.0",
|
"@typescript-eslint/parser": "^8.18.0",
|
||||||
"eslint-config-airbnb": "^19.0.4",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
"eslint-plugin-github": "^5.1.4",
|
"eslint-plugin-github": "^5.1.4",
|
||||||
"eslint-plugin-import": "2.31.0",
|
"eslint-plugin-import": "2.31.0",
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@
|
|||||||
"esbuild": "0.24.0",
|
"esbuild": "0.24.0",
|
||||||
"eslint": "^8.57.1",
|
"eslint": "^8.57.1",
|
||||||
"eslint-import-resolver-typescript": "^3.7.0",
|
"eslint-import-resolver-typescript": "^3.7.0",
|
||||||
"eslint-import-resolver-webpack": "^0.13.9",
|
"eslint-import-resolver-webpack": "^0.13.10",
|
||||||
"fs-extra": "^11.2.0",
|
"fs-extra": "^11.2.0",
|
||||||
"globby": "^14.0.2",
|
"globby": "^14.0.2",
|
||||||
"inspectpack": "^4.7.1",
|
"inspectpack": "^4.7.1",
|
||||||
|
|||||||
@@ -6,6 +6,6 @@
|
|||||||
"author": "undefined <i@undefined.moe>",
|
"author": "undefined <i@undefined.moe>",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@elastic/elasticsearch": "^8.16.2"
|
"@elastic/elasticsearch": "^8.17.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,11 +12,11 @@
|
|||||||
},
|
},
|
||||||
"preferUnplugged": true,
|
"preferUnplugged": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "3.705.0",
|
"@aws-sdk/client-s3": "3.712.0",
|
||||||
"@aws-sdk/lib-storage": "3.705.0",
|
"@aws-sdk/lib-storage": "3.712.0",
|
||||||
"@aws-sdk/s3-presigned-post": "3.705.0",
|
"@aws-sdk/s3-presigned-post": "3.712.0",
|
||||||
"@aws-sdk/s3-request-presigner": "3.705.0",
|
"@aws-sdk/s3-request-presigner": "3.712.0",
|
||||||
"@graphql-tools/schema": "^10.0.11",
|
"@graphql-tools/schema": "^10.0.12",
|
||||||
"@hydrooj/framework": "workspace:^",
|
"@hydrooj/framework": "workspace:^",
|
||||||
"@hydrooj/utils": "workspace:^",
|
"@hydrooj/utils": "workspace:^",
|
||||||
"@simplewebauthn/server": "9.0.3",
|
"@simplewebauthn/server": "9.0.3",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { generateRegistrationOptions, verifyRegistrationResponse } from '@simple
|
|||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
import { pick } from 'lodash';
|
import { pick } from 'lodash';
|
||||||
import { Binary, ObjectId } from 'mongodb';
|
import { Binary, ObjectId } from 'mongodb';
|
||||||
import Parser from 'ua-parser-js';
|
import { UAParser } from 'ua-parser-js';
|
||||||
import { Context } from '../context';
|
import { Context } from '../context';
|
||||||
import {
|
import {
|
||||||
AuthOperationError, BlacklistedError, DomainAlreadyExistsError, InvalidTokenError,
|
AuthOperationError, BlacklistedError, DomainAlreadyExistsError, InvalidTokenError,
|
||||||
@@ -186,10 +186,7 @@ class HomeSecurityHandler extends Handler {
|
|||||||
session.isCurrent = session._id === this.session._id;
|
session.isCurrent = session._id === this.session._id;
|
||||||
session._id = md5(session._id);
|
session._id = md5(session._id);
|
||||||
const ua = session.updateUa || session.createUa;
|
const ua = session.updateUa || session.createUa;
|
||||||
if (ua) {
|
if (ua) session.updateUaInfo = UAParser(ua);
|
||||||
const parser = new Parser(ua);
|
|
||||||
session.updateUaInfo = parser.getResult();
|
|
||||||
}
|
|
||||||
session.updateGeoip = this.ctx.geoip?.lookup?.(
|
session.updateGeoip = this.ctx.geoip?.lookup?.(
|
||||||
session.updateIp || session.createIp,
|
session.updateIp || session.createIp,
|
||||||
this.translate('geoip_locale'),
|
this.translate('geoip_locale'),
|
||||||
@@ -253,7 +250,7 @@ class HomeSecurityHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@param('tokenDigest', Types.String)
|
@param('tokenDigest', Types.String)
|
||||||
async postDeleteToken(domainId: string, tokenDigest: string) {
|
async postDeleteToken({ }, tokenDigest: string) {
|
||||||
const sessions = await token.getSessionListByUid(this.user._id);
|
const sessions = await token.getSessionListByUid(this.user._id);
|
||||||
for (const session of sessions) {
|
for (const session of sessions) {
|
||||||
if (tokenDigest === md5(session._id)) {
|
if (tokenDigest === md5(session._id)) {
|
||||||
@@ -273,7 +270,7 @@ class HomeSecurityHandler extends Handler {
|
|||||||
@requireSudo
|
@requireSudo
|
||||||
@param('code', Types.String)
|
@param('code', Types.String)
|
||||||
@param('secret', Types.String)
|
@param('secret', Types.String)
|
||||||
async postEnableTfa(domainId: string, code: string, secret: string) {
|
async postEnableTfa({ }, code: string, secret: string) {
|
||||||
if (this.user._tfa) throw new AuthOperationError('2FA', 'enabled');
|
if (this.user._tfa) throw new AuthOperationError('2FA', 'enabled');
|
||||||
if (!verifyTFA(secret, code)) throw new InvalidTokenError('2FA');
|
if (!verifyTFA(secret, code)) throw new InvalidTokenError('2FA');
|
||||||
await user.setById(this.user._id, { tfa: secret });
|
await user.setById(this.user._id, { tfa: secret });
|
||||||
@@ -287,7 +284,7 @@ class HomeSecurityHandler extends Handler {
|
|||||||
|
|
||||||
@requireSudo
|
@requireSudo
|
||||||
@param('type', Types.Range(['cross-platform', 'platform']))
|
@param('type', Types.Range(['cross-platform', 'platform']))
|
||||||
async postRegister(domainId: string, type: 'cross-platform' | 'platform') {
|
async postRegister({ }, type: 'cross-platform' | 'platform') {
|
||||||
const options = await generateRegistrationOptions({
|
const options = await generateRegistrationOptions({
|
||||||
rpName: system.get('server.name'),
|
rpName: system.get('server.name'),
|
||||||
rpID: this.getAuthnHost(),
|
rpID: this.getAuthnHost(),
|
||||||
@@ -309,7 +306,7 @@ class HomeSecurityHandler extends Handler {
|
|||||||
|
|
||||||
@requireSudo
|
@requireSudo
|
||||||
@param('name', Types.String)
|
@param('name', Types.String)
|
||||||
async postEnableAuthn(domainId: string, name: string) {
|
async postEnableAuthn({ }, name: string) {
|
||||||
if (!this.session.webauthnVerify) throw new InvalidTokenError(token.TYPE_TEXTS[token.TYPE_WEBAUTHN]);
|
if (!this.session.webauthnVerify) throw new InvalidTokenError(token.TYPE_TEXTS[token.TYPE_WEBAUTHN]);
|
||||||
const verification = await verifyRegistrationResponse({
|
const verification = await verifyRegistrationResponse({
|
||||||
response: this.args.result,
|
response: this.args.result,
|
||||||
@@ -336,7 +333,7 @@ class HomeSecurityHandler extends Handler {
|
|||||||
|
|
||||||
@requireSudo
|
@requireSudo
|
||||||
@param('id', Types.String)
|
@param('id', Types.String)
|
||||||
async postDisableAuthn(domainId: string, id: string) {
|
async postDisableAuthn({ }, id: string) {
|
||||||
const authenticators = this.user._authenticators?.filter((c) => Buffer.from(c.credentialID.buffer).toString('base64') !== id);
|
const authenticators = this.user._authenticators?.filter((c) => Buffer.from(c.credentialID.buffer).toString('base64') !== id);
|
||||||
if (this.user._authenticators?.length === authenticators?.length) throw new ValidationError('authenticator');
|
if (this.user._authenticators?.length === authenticators?.length) throw new ValidationError('authenticator');
|
||||||
await user.setById(this.user._id, { authenticators });
|
await user.setById(this.user._id, { authenticators });
|
||||||
@@ -395,7 +392,7 @@ function set(s: Setting, key: string, value: any) {
|
|||||||
|
|
||||||
class HomeSettingsHandler extends Handler {
|
class HomeSettingsHandler extends Handler {
|
||||||
@param('category', Types.Range(['preference', 'account', 'domain']))
|
@param('category', Types.Range(['preference', 'account', 'domain']))
|
||||||
async get(domainId: string, category: string) {
|
async get({ }, category: string) {
|
||||||
this.response.template = 'home_settings.html';
|
this.response.template = 'home_settings.html';
|
||||||
this.response.body = {
|
this.response.body = {
|
||||||
category,
|
category,
|
||||||
@@ -432,7 +429,7 @@ class HomeSettingsHandler extends Handler {
|
|||||||
|
|
||||||
class HomeAvatarHandler extends Handler {
|
class HomeAvatarHandler extends Handler {
|
||||||
@param('avatar', Types.String, true)
|
@param('avatar', Types.String, true)
|
||||||
async post(domainId: string, input: string) {
|
async post({ }, input: string) {
|
||||||
if (input) {
|
if (input) {
|
||||||
if (!validate(input)) throw new ValidationError('avatar');
|
if (!validate(input)) throw new ValidationError('avatar');
|
||||||
await user.setById(this.user._id, { avatar: input });
|
await user.setById(this.user._id, { avatar: input });
|
||||||
@@ -565,7 +562,7 @@ class HomeMessagesHandler extends Handler {
|
|||||||
|
|
||||||
@param('uid', Types.Int)
|
@param('uid', Types.Int)
|
||||||
@param('content', Types.Content)
|
@param('content', Types.Content)
|
||||||
async postSend(domainId: string, uid: number, content: string) {
|
async postSend({ }, uid: number, content: string) {
|
||||||
this.checkPriv(PRIV.PRIV_SEND_MESSAGE);
|
this.checkPriv(PRIV.PRIV_SEND_MESSAGE);
|
||||||
const udoc = await user.getById('system', uid);
|
const udoc = await user.getById('system', uid);
|
||||||
if (!udoc) throw new UserNotFoundError(uid);
|
if (!udoc) throw new UserNotFoundError(uid);
|
||||||
@@ -575,7 +572,7 @@ class HomeMessagesHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@param('messageId', Types.ObjectId)
|
@param('messageId', Types.ObjectId)
|
||||||
async postDeleteMessage(domainId: string, messageId: ObjectId) {
|
async postDeleteMessage({ }, messageId: ObjectId) {
|
||||||
const msg = await message.get(messageId);
|
const msg = await message.get(messageId);
|
||||||
if ([msg.from, msg.to].includes(this.user._id)) await message.del(messageId);
|
if ([msg.from, msg.to].includes(this.user._id)) await message.del(messageId);
|
||||||
else throw new PermissionError();
|
else throw new PermissionError();
|
||||||
@@ -583,7 +580,7 @@ class HomeMessagesHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@param('messageId', Types.ObjectId)
|
@param('messageId', Types.ObjectId)
|
||||||
async postRead(domainId: string, messageId: ObjectId) {
|
async postRead({ }, messageId: ObjectId) {
|
||||||
const msg = await message.get(messageId);
|
const msg = await message.get(messageId);
|
||||||
if ([msg.from, msg.to].includes(this.user._id)) {
|
if ([msg.from, msg.to].includes(this.user._id)) {
|
||||||
await message.setFlag(messageId, message.FLAG_UNREAD);
|
await message.setFlag(messageId, message.FLAG_UNREAD);
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
"version": "0.0.3",
|
"version": "0.0.3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-spring/web": "^9.7.5",
|
"@react-spring/web": "^9.7.5",
|
||||||
"react-use": "^17.5.1"
|
"react-use": "^17.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
/* eslint-disable jsx-a11y/role-supports-aria-props */
|
/* eslint-disable jsx-a11y/role-supports-aria-props */
|
||||||
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
|
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
|
||||||
import { debounce, uniqueId } from 'lodash';
|
import { debounce, uniqueId } from 'lodash';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, {
|
import React, {
|
||||||
forwardRef, useEffect,
|
forwardRef, useEffect,
|
||||||
useImperativeHandle, useRef, useState,
|
useImperativeHandle, useRef, useState,
|
||||||
@@ -102,8 +101,8 @@ const AutoComplete = forwardRef(function Impl<T>(props: AutoCompleteProps<T>, re
|
|||||||
const [rerender, setRerender] = useState(false);
|
const [rerender, setRerender] = useState(false);
|
||||||
const [draggableId] = useState(uniqueId());
|
const [draggableId] = useState(uniqueId());
|
||||||
|
|
||||||
const inputRef = useRef<HTMLInputElement>();
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
const listRef = useRef<HTMLUListElement>();
|
const listRef = useRef<HTMLUListElement>(null);
|
||||||
|
|
||||||
let [queryCache, valueCache] = [useRef({}).current, useRef({}).current];
|
let [queryCache, valueCache] = [useRef({}).current, useRef({}).current];
|
||||||
if (props.cacheKey) {
|
if (props.cacheKey) {
|
||||||
@@ -347,40 +346,6 @@ const AutoComplete = forwardRef(function Impl<T>(props: AutoCompleteProps<T>, re
|
|||||||
);
|
);
|
||||||
}) as (<T>(props: AutoCompleteProps<T> & { ref: React.Ref<AutoCompleteHandle<T>> }) => React.ReactElement) & React.FC;
|
}) as (<T>(props: AutoCompleteProps<T> & { ref: React.Ref<AutoCompleteHandle<T>> }) => React.ReactElement) & React.FC;
|
||||||
|
|
||||||
AutoComplete.propTypes = {
|
|
||||||
width: PropTypes.string,
|
|
||||||
height: PropTypes.string,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
disabledHint: PropTypes.string,
|
|
||||||
listStyle: PropTypes.object,
|
|
||||||
queryItems: PropTypes.func.isRequired,
|
|
||||||
itemKey: PropTypes.func,
|
|
||||||
renderItem: PropTypes.func,
|
|
||||||
itemText: PropTypes.func,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
multi: PropTypes.bool,
|
|
||||||
selectedKeys: PropTypes.arrayOf(PropTypes.string),
|
|
||||||
allowEmptyQuery: PropTypes.bool,
|
|
||||||
freeSolo: PropTypes.bool,
|
|
||||||
freeSoloConverter: PropTypes.func,
|
|
||||||
placeholder: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
AutoComplete.defaultProps = {
|
|
||||||
width: '100%',
|
|
||||||
height: 'auto',
|
|
||||||
disabled: false,
|
|
||||||
disabledHint: '',
|
|
||||||
listStyle: {},
|
|
||||||
renderItem: (item) => item,
|
|
||||||
itemText: (item) => item.toString(),
|
|
||||||
multi: false,
|
|
||||||
selectedKeys: [],
|
|
||||||
allowEmptyQuery: false,
|
|
||||||
freeSolo: false,
|
|
||||||
freeSoloConverter: (input) => input,
|
|
||||||
};
|
|
||||||
|
|
||||||
AutoComplete.displayName = 'AutoComplete';
|
AutoComplete.displayName = 'AutoComplete';
|
||||||
|
|
||||||
export default AutoComplete;
|
export default AutoComplete;
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
"cli": false
|
"cli": false
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@blueprintjs/core": "^5.16.0",
|
"@blueprintjs/core": "^5.16.2",
|
||||||
"@cordisjs/core": "3.18.1",
|
"@cordisjs/core": "3.18.1",
|
||||||
"@fontsource/dm-mono": "^5.1.0",
|
"@fontsource/dm-mono": "^5.1.0",
|
||||||
"@fontsource/fira-code": "^5.1.0",
|
"@fontsource/fira-code": "^5.1.0",
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
"@fontsource/source-code-pro": "^5.1.0",
|
"@fontsource/source-code-pro": "^5.1.0",
|
||||||
"@fontsource/ubuntu-mono": "^5.1.0",
|
"@fontsource/ubuntu-mono": "^5.1.0",
|
||||||
"@hydrooj/utils": "workspace:^",
|
"@hydrooj/utils": "workspace:^",
|
||||||
"@sentry/browser": "^8.42.0",
|
"@sentry/browser": "^8.45.0",
|
||||||
"@sentry/webpack-plugin": "^2.22.7",
|
"@sentry/webpack-plugin": "^2.22.7",
|
||||||
"@simplewebauthn/browser": "9.0.1",
|
"@simplewebauthn/browser": "9.0.1",
|
||||||
"@svgr/webpack": "^8.1.0",
|
"@svgr/webpack": "^8.1.0",
|
||||||
@@ -37,8 +37,8 @@
|
|||||||
"@types/nunjucks": "^3.2.6",
|
"@types/nunjucks": "^3.2.6",
|
||||||
"@types/pickadate": "^3.5.35",
|
"@types/pickadate": "^3.5.35",
|
||||||
"@types/qrcode": "^1.5.5",
|
"@types/qrcode": "^1.5.5",
|
||||||
"@types/react": "^19.0.1",
|
"@types/react": "^18.3.16",
|
||||||
"@types/react-dom": "^19.0.1",
|
"@types/react-dom": "^18.3.5",
|
||||||
"@types/redux-logger": "^3.0.13",
|
"@types/redux-logger": "^3.0.13",
|
||||||
"@types/uuid": "^10.0.0",
|
"@types/uuid": "^10.0.0",
|
||||||
"@types/webpack-env": "^1.18.5",
|
"@types/webpack-env": "^1.18.5",
|
||||||
@@ -62,14 +62,14 @@
|
|||||||
"emojis-list": "2.1.0",
|
"emojis-list": "2.1.0",
|
||||||
"esbuild-loader": "^4.2.2",
|
"esbuild-loader": "^4.2.2",
|
||||||
"flatpickr": "^4.6.13",
|
"flatpickr": "^4.6.13",
|
||||||
"graphiql": "^3.7.2",
|
"graphiql": "^3.8.0",
|
||||||
"idb": "^8.0.0",
|
"idb": "^8.0.0",
|
||||||
"jquery": "^3.7.1",
|
"jquery": "^3.7.1",
|
||||||
"jquery-scroll-lock": "^3.1.3",
|
"jquery-scroll-lock": "^3.1.3",
|
||||||
"jquery.easing": "^1.4.1",
|
"jquery.easing": "^1.4.1",
|
||||||
"jquery.transit": "^0.9.12",
|
"jquery.transit": "^0.9.12",
|
||||||
"matchmedia-polyfill": "^0.3.2",
|
"matchmedia-polyfill": "^0.3.2",
|
||||||
"md-editor-rt": "^5.0.2",
|
"md-editor-rt": "^5.1.0",
|
||||||
"mini-css-extract-plugin": "^2.9.2",
|
"mini-css-extract-plugin": "^2.9.2",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"monaco-editor": "0.50.0",
|
"monaco-editor": "0.50.0",
|
||||||
@@ -94,7 +94,7 @@
|
|||||||
"react-dnd-html5-backend": "^16.0.1",
|
"react-dnd-html5-backend": "^16.0.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"react-redux": "^9.1.2",
|
"react-redux": "^9.2.0",
|
||||||
"reconnecting-websocket": "^4.4.0",
|
"reconnecting-websocket": "^4.4.0",
|
||||||
"redux": "^5.0.1",
|
"redux": "^5.0.1",
|
||||||
"redux-logger": "^3.0.6",
|
"redux-logger": "^3.0.6",
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
"web-streams-polyfill": "^4.0.0",
|
"web-streams-polyfill": "^4.0.0",
|
||||||
"webpack": "^5.97.1",
|
"webpack": "^5.97.1",
|
||||||
"webpack-bundle-analyzer": "^4.10.2",
|
"webpack-bundle-analyzer": "^4.10.2",
|
||||||
"webpack-dev-server": "^5.1.0",
|
"webpack-dev-server": "^5.2.0",
|
||||||
"webpack-manifest-plugin": "^5.0.0",
|
"webpack-manifest-plugin": "^5.0.0",
|
||||||
"webpackbar": "^7.0.0"
|
"webpackbar": "^7.0.0"
|
||||||
},
|
},
|
||||||
@@ -127,8 +127,8 @@
|
|||||||
"esbuild": "0.24.0",
|
"esbuild": "0.24.0",
|
||||||
"fs-extra": "^11.2.0",
|
"fs-extra": "^11.2.0",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"jsesc": "^3.0.2",
|
"jsesc": "^3.1.0",
|
||||||
"katex": "^0.16.14",
|
"katex": "^0.16.15",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"markdown-it": "^14.1.0",
|
"markdown-it": "^14.1.0",
|
||||||
"markdown-it-anchor": "^9.2.0",
|
"markdown-it-anchor": "^9.2.0",
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"mongodb": "^5.9.2",
|
"mongodb": "^5.9.2",
|
||||||
"reggol": "^1.7.1",
|
"reggol": "^1.7.1",
|
||||||
"search-query-parser": "^1.6.0",
|
"search-query-parser": "^1.6.0",
|
||||||
"systeminformation": "^5.23.6"
|
"systeminformation": "^5.23.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/fs-extra": "^11.0.4"
|
"@types/fs-extra": "^11.0.4"
|
||||||
|
|||||||
Reference in new issue
Block a user