refactor deployment config and exchange integrations
Simplify runtime configuration and remove legacy database and settings surface so new installs are easier to operate. Refresh deployment assets, docs, and order execution behavior to keep the packaged app aligned with the current backend. Made-with: Cursor
This commit is contained in:
+6
-24
@@ -1,31 +1,13 @@
|
||||
# QuantDinger Frontend — multi-stage build
|
||||
# QuantDinger Frontend — static runtime image
|
||||
# Build context: repository root (see docker-compose.yml)
|
||||
#
|
||||
# Stage 1: compile Vue app from QuantDinger-Vue-src
|
||||
# Stage 2: nginx static + API reverse proxy (nginx.conf)
|
||||
# The open-source repo ships prebuilt static assets in `frontend/dist`,
|
||||
# so no Node.js build stage is required.
|
||||
ARG RUNTIME_IMAGE=nginx:1.25-alpine
|
||||
FROM ${RUNTIME_IMAGE}
|
||||
|
||||
FROM node:18-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Layer cache: deps only
|
||||
COPY QuantDinger-Vue-src/package.json QuantDinger-Vue-src/package-lock.json ./
|
||||
RUN npm ci
|
||||
|
||||
COPY QuantDinger-Vue-src/ ./
|
||||
|
||||
# Match local production build (`npm run build` in QuantDinger-Vue-src)
|
||||
ENV NODE_OPTIONS=--max_old_space_size=4096
|
||||
RUN npm run build
|
||||
|
||||
# --- runtime ---
|
||||
|
||||
FROM nginx:1.25-alpine
|
||||
|
||||
# curl: docker-compose healthcheck
|
||||
RUN apk add --no-cache curl
|
||||
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html/
|
||||
COPY frontend/dist/ /usr/share/nginx/html/
|
||||
COPY frontend/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
+8
-8
@@ -189,14 +189,14 @@ body.dark .trading-records ::v-deep .ant-pagination .ant-pagination-next:hover .
|
||||
.user-manage-page .address-text[data-v-49c4f239],.user-manage-page .hash-text[data-v-49c4f239]{color:#1890ff}
|
||||
.user-manage-page.theme-dark .manage-tabs[data-v-49c4f239] .ant-tabs-tab-active{color:#1890ff}
|
||||
.user-manage-page .current-credits-info .value[data-v-49c4f239],.user-manage-page .current-vip-info .value[data-v-49c4f239]{color:#1890ff}
|
||||
.profile-page .page-header .page-title .anticon[data-v-2b760d50]{color:#1890ff}
|
||||
.profile-page .profile-card .profile-info .info-item .anticon[data-v-2b760d50]{color:#1890ff}
|
||||
.profile-page.theme-dark .edit-card[data-v-2b760d50] .ant-tabs-tab-active{color:#1890ff}
|
||||
.profile-page.theme-dark .edit-card[data-v-2b760d50] .ant-input-password:focus,.profile-page.theme-dark .edit-card[data-v-2b760d50] .ant-input-password:hover,.profile-page.theme-dark .edit-card[data-v-2b760d50] .ant-input:focus,.profile-page.theme-dark .edit-card[data-v-2b760d50] .ant-input:hover{border-color:#1890ff}
|
||||
.profile-page.theme-dark .notification-settings-form[data-v-2b760d50] .ant-checkbox-checked .ant-checkbox-inner,.profile-page.theme-dark .notification-settings-form[data-v-2b760d50] .ant-radio-checked .ant-radio-inner,.profile-page.theme-dark .password-form[data-v-2b760d50] .ant-checkbox-checked .ant-checkbox-inner,.profile-page.theme-dark .password-form[data-v-2b760d50] .ant-radio-checked .ant-radio-inner,.profile-page.theme-dark .profile-form[data-v-2b760d50] .ant-checkbox-checked .ant-checkbox-inner,.profile-page.theme-dark .profile-form[data-v-2b760d50] .ant-radio-checked .ant-radio-inner{background-color:#1890ff;border-color:#1890ff}
|
||||
.profile-page.theme-dark[data-v-2b760d50] .ant-pagination .ant-pagination-item:hover{border-color:#1890ff}
|
||||
.profile-page.theme-dark[data-v-2b760d50] .ant-pagination .ant-pagination-item-active{background:#1890ff;border-color:#1890ff}
|
||||
.profile-page.theme-dark[data-v-2b760d50] .ant-btn.ant-btn-default:hover{border-color:#1890ff;color:#1890ff}
|
||||
.profile-page .page-header .page-title .anticon[data-v-86a53e9c]{color:#1890ff}
|
||||
.profile-page .profile-card .profile-info .info-item .anticon[data-v-86a53e9c]{color:#1890ff}
|
||||
.profile-page.theme-dark .edit-card[data-v-86a53e9c] .ant-tabs-tab-active{color:#1890ff}
|
||||
.profile-page.theme-dark .edit-card[data-v-86a53e9c] .ant-input-password:focus,.profile-page.theme-dark .edit-card[data-v-86a53e9c] .ant-input-password:hover,.profile-page.theme-dark .edit-card[data-v-86a53e9c] .ant-input:focus,.profile-page.theme-dark .edit-card[data-v-86a53e9c] .ant-input:hover{border-color:#1890ff}
|
||||
.profile-page.theme-dark .notification-settings-form[data-v-86a53e9c] .ant-checkbox-checked .ant-checkbox-inner,.profile-page.theme-dark .notification-settings-form[data-v-86a53e9c] .ant-radio-checked .ant-radio-inner,.profile-page.theme-dark .password-form[data-v-86a53e9c] .ant-checkbox-checked .ant-checkbox-inner,.profile-page.theme-dark .password-form[data-v-86a53e9c] .ant-radio-checked .ant-radio-inner,.profile-page.theme-dark .profile-form[data-v-86a53e9c] .ant-checkbox-checked .ant-checkbox-inner,.profile-page.theme-dark .profile-form[data-v-86a53e9c] .ant-radio-checked .ant-radio-inner{background-color:#1890ff;border-color:#1890ff}
|
||||
.profile-page.theme-dark[data-v-86a53e9c] .ant-pagination .ant-pagination-item:hover{border-color:#1890ff}
|
||||
.profile-page.theme-dark[data-v-86a53e9c] .ant-pagination .ant-pagination-item-active{background:#1890ff;border-color:#1890ff}
|
||||
.profile-page.theme-dark[data-v-86a53e9c] .ant-btn.ant-btn-default:hover{border-color:#1890ff;color:#1890ff}
|
||||
.billing-page .plan-card.highlight[data-v-0cdd5f9c]{border:1px solid rgba(24,144,255,.35)}
|
||||
.usdt-checkout .checkout-body .info-section .addr-box .copy-btn:hover,.usdt-checkout .checkout-body .info-section .amt-box .copy-btn:hover{background:rgba(24,144,255,.08);color:#1890ff}
|
||||
.theme-dark .usdt-checkout .checkout-body .info-section .addr-box .copy-btn:hover,.theme-dark .usdt-checkout .checkout-body .info-section .amt-box .copy-btn:hover,body.realdark .usdt-checkout .checkout-body .info-section .addr-box .copy-btn:hover,body.realdark .usdt-checkout .checkout-body .info-section .amt-box .copy-btn:hover{background:rgba(24,144,255,.15);color:#40a9ff}
|
||||
Vendored
+1
-1
@@ -421,4 +421,4 @@
|
||||
.brand-text {
|
||||
font-size: 20px;
|
||||
}
|
||||
}</style><script defer="defer" src="/js/chunk-vendors.e3ae0d1f.js" type="module"></script><script defer="defer" src="/js/app.de48b29a.js" type="module"></script><link href="/css/chunk-vendors.b8cb9e53.css" rel="stylesheet"><link href="/css/app.ee3dda40.css" rel="stylesheet"><script defer="defer" src="/js/chunk-vendors-legacy.beabf087.js" nomodule></script><script defer="defer" src="/js/app-legacy.a9e4bd9c.js" nomodule></script></head><body><noscript><strong>We're sorry but vue-antd-pro doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"><div class="first-loading-wrp"><h2>Landing</h2><div class="loading-wrp"><div class="pixel-cat-container"><div class="ground"></div><div class="pixel-cat"><div class="cat-head"><div class="cat-ear-left"></div><div class="cat-ear-right"></div><div class="cat-eye-left"></div><div class="cat-eye-right"></div><div class="cat-nose"></div><div class="cat-whiskers"></div></div><div class="cat-body"></div><div class="cat-leg-front-left"></div><div class="cat-leg-front-right"></div><div class="cat-leg-back-left"></div><div class="cat-leg-back-right"></div><div class="cat-tail"></div></div></div></div><div class="brand-text">QuantDinger</div></div></div></body></html>
|
||||
}</style><script defer="defer" src="/js/chunk-vendors.47fd2294.js" type="module"></script><script defer="defer" src="/js/app.4799d28b.js" type="module"></script><link href="/css/chunk-vendors.b8cb9e53.css" rel="stylesheet"><link href="/css/app.ee3dda40.css" rel="stylesheet"><script defer="defer" src="/js/chunk-vendors-legacy.74c62065.js" nomodule></script><script defer="defer" src="/js/app-legacy.73c5f6b0.js" nomodule></script></head><body><noscript><strong>We're sorry but vue-antd-pro doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"><div class="first-loading-wrp"><h2>Landing</h2><div class="loading-wrp"><div class="pixel-cat-container"><div class="ground"></div><div class="pixel-cat"><div class="cat-head"><div class="cat-ear-left"></div><div class="cat-ear-right"></div><div class="cat-eye-left"></div><div class="cat-eye-right"></div><div class="cat-nose"></div><div class="cat-whiskers"></div></div><div class="cat-body"></div><div class="cat-leg-front-left"></div><div class="cat-leg-front-right"></div><div class="cat-leg-back-left"></div><div class="cat-leg-back-right"></div><div class="cat-tail"></div></div></div></div><div class="brand-text">QuantDinger</div></div></div></body></html>
|
||||
+1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
-1
@@ -1 +0,0 @@
|
||||
"use strict";(self["webpackChunkvue_antd_pro"]=self["webpackChunkvue_antd_pro"]||[]).push([[24],{20024:function(t,n,r){r.r(n),r.d(n,{changePassword:function(){return p},getGitHubOAuthUrl:function(){return g},getGoogleOAuthUrl:function(){return l},getSecurityConfig:function(){return o},getUserInfo:function(){return c},login:function(){return i},loginWithCode:function(){return s},logout:function(){return a},register:function(){return f},resetPassword:function(){return d},sendVerificationCode:function(){return h}});r(34782),r(27495),r(99449),r(25440),r(11392),r(42762);var u=r(76471);function e(t){var n="/api".trim(),r=t.startsWith("/")?t:"/".concat(t);if(!n)return r;var u=n.replace(/\/+$/,"");return u.endsWith("/api")&&r.startsWith("/api/")?u+r.slice(4):u+r}function o(){return(0,u.Ay)({url:"/api/auth/security-config",method:"get"})}function i(t){return(0,u.Ay)({url:"/api/auth/login",method:"post",data:t})}function a(){return(0,u.Ay)({url:"/api/auth/logout",method:"post"})}function c(){return(0,u.Ay)({url:"/api/auth/info",method:"get"})}function h(t){return(0,u.Ay)({url:"/api/auth/send-code",method:"post",data:t})}function s(t){return(0,u.Ay)({url:"/api/auth/login-code",method:"post",data:t})}function f(t){return(0,u.Ay)({url:"/api/auth/register",method:"post",data:t})}function d(t){return(0,u.Ay)({url:"/api/auth/reset-password",method:"post",data:t})}function p(t){return(0,u.Ay)({url:"/api/auth/change-password",method:"post",data:t})}function l(){return e("/api/auth/oauth/google")}function g(){return e("/api/auth/oauth/github")}}}]);
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
"use strict";(self["webpackChunkvue_antd_pro"]=self["webpackChunkvue_antd_pro"]||[]).push([[24],{20024:function(t,n,r){r.r(n),r.d(n,{changePassword:function(){return p},getGitHubOAuthUrl:function(){return g},getGoogleOAuthUrl:function(){return l},getSecurityConfig:function(){return o},getUserInfo:function(){return c},login:function(){return i},loginWithCode:function(){return s},logout:function(){return a},register:function(){return f},resetPassword:function(){return d},sendVerificationCode:function(){return h}});var u=r(76471);function e(t){var n="/api".trim(),r=t.startsWith("/")?t:"/".concat(t);if(!n)return r;var u=n.replace(/\/+$/,"");return u.endsWith("/api")&&r.startsWith("/api/")?u+r.slice(4):u+r}function o(){return(0,u.Ay)({url:"/api/auth/security-config",method:"get"})}function i(t){return(0,u.Ay)({url:"/api/auth/login",method:"post",data:t})}function a(){return(0,u.Ay)({url:"/api/auth/logout",method:"post"})}function c(){return(0,u.Ay)({url:"/api/auth/info",method:"get"})}function h(t){return(0,u.Ay)({url:"/api/auth/send-code",method:"post",data:t})}function s(t){return(0,u.Ay)({url:"/api/auth/login-code",method:"post",data:t})}function f(t){return(0,u.Ay)({url:"/api/auth/register",method:"post",data:t})}function d(t){return(0,u.Ay)({url:"/api/auth/reset-password",method:"post",data:t})}function p(t){return(0,u.Ay)({url:"/api/auth/change-password",method:"post",data:t})}function l(){return e("/api/auth/oauth/google")}function g(){return e("/api/auth/oauth/github")}}}]);
|
||||
Vendored
-1
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
-18
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
+18
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
-18
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
+18
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
"use strict";(self["webpackChunkvue_antd_pro"]=self["webpackChunkvue_antd_pro"]||[]).push([[824],{95824:function(t,n,r){r.r(n),r.d(n,{changePassword:function(){return p},getGitHubOAuthUrl:function(){return g},getGoogleOAuthUrl:function(){return l},getSecurityConfig:function(){return o},getUserInfo:function(){return c},login:function(){return i},loginWithCode:function(){return s},logout:function(){return a},register:function(){return f},resetPassword:function(){return d},sendVerificationCode:function(){return h}});r(34782),r(27495),r(99449),r(25440),r(11392),r(42762);var u=r(75769);function e(t){var n="/api".trim(),r=t.startsWith("/")?t:"/".concat(t);if(!n)return r;var u=n.replace(/\/+$/,"");return u.endsWith("/api")&&r.startsWith("/api/")?u+r.slice(4):u+r}function o(){return(0,u.Ay)({url:"/api/auth/security-config",method:"get"})}function i(t){return(0,u.Ay)({url:"/api/auth/login",method:"post",data:t})}function a(){return(0,u.Ay)({url:"/api/auth/logout",method:"post"})}function c(){return(0,u.Ay)({url:"/api/auth/info",method:"get"})}function h(t){return(0,u.Ay)({url:"/api/auth/send-code",method:"post",data:t})}function s(t){return(0,u.Ay)({url:"/api/auth/login-code",method:"post",data:t})}function f(t){return(0,u.Ay)({url:"/api/auth/register",method:"post",data:t})}function d(t){return(0,u.Ay)({url:"/api/auth/reset-password",method:"post",data:t})}function p(t){return(0,u.Ay)({url:"/api/auth/change-password",method:"post",data:t})}function l(){return e("/api/auth/oauth/google")}function g(){return e("/api/auth/oauth/github")}}}]);
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
"use strict";(self["webpackChunkvue_antd_pro"]=self["webpackChunkvue_antd_pro"]||[]).push([[824],{95824:function(t,n,r){r.r(n),r.d(n,{changePassword:function(){return p},getGitHubOAuthUrl:function(){return g},getGoogleOAuthUrl:function(){return l},getSecurityConfig:function(){return o},getUserInfo:function(){return c},login:function(){return i},loginWithCode:function(){return s},logout:function(){return a},register:function(){return f},resetPassword:function(){return d},sendVerificationCode:function(){return h}});var u=r(75769);function e(t){var n="/api".trim(),r=t.startsWith("/")?t:"/".concat(t);if(!n)return r;var u=n.replace(/\/+$/,"");return u.endsWith("/api")&&r.startsWith("/api/")?u+r.slice(4):u+r}function o(){return(0,u.Ay)({url:"/api/auth/security-config",method:"get"})}function i(t){return(0,u.Ay)({url:"/api/auth/login",method:"post",data:t})}function a(){return(0,u.Ay)({url:"/api/auth/logout",method:"post"})}function c(){return(0,u.Ay)({url:"/api/auth/info",method:"get"})}function h(t){return(0,u.Ay)({url:"/api/auth/send-code",method:"post",data:t})}function s(t){return(0,u.Ay)({url:"/api/auth/login-code",method:"post",data:t})}function f(t){return(0,u.Ay)({url:"/api/auth/register",method:"post",data:t})}function d(t){return(0,u.Ay)({url:"/api/auth/reset-password",method:"post",data:t})}function p(t){return(0,u.Ay)({url:"/api/auth/change-password",method:"post",data:t})}function l(){return e("/api/auth/oauth/google")}function g(){return e("/api/auth/oauth/github")}}}]);
|
||||
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
+5
-5
File diff suppressed because one or more lines are too long
+5
-5
File diff suppressed because one or more lines are too long
-1
@@ -1 +0,0 @@
|
||||
"use strict";(self["webpackChunkvue_antd_pro"]=self["webpackChunkvue_antd_pro"]||[]).push([[143],{4049:function(t,e,n){n.r(e),n.d(e,{default:function(){return l}});var u=function(){var t=this,e=t._self._c;return e("a-result",{attrs:{status:"404",title:"404","sub-title":"Sorry, the page you visited does not exist."},scopedSlots:t._u([{key:"extra",fn:function(){return[e("a-button",{attrs:{type:"primary"},on:{click:t.toHome}},[t._v(" Back Home ")])]},proxy:!0}])})},o=[],r={name:"Exception404",methods:{toHome:function(){this.$router.push({path:"/"})}}},s=r,a=n(845),i=(0,a.A)(s,u,o,!1,null,null,null),l=i.exports}}]);
|
||||
+1
@@ -0,0 +1 @@
|
||||
"use strict";(self["webpackChunkvue_antd_pro"]=self["webpackChunkvue_antd_pro"]||[]).push([[143],{55273:function(t,e,n){n.r(e),n.d(e,{default:function(){return l}});var u=function(){var t=this,e=t._self._c;return e("a-result",{attrs:{status:"404",title:"404","sub-title":"Sorry, the page you visited does not exist."},scopedSlots:t._u([{key:"extra",fn:function(){return[e("a-button",{attrs:{type:"primary"},on:{click:t.toHome}},[t._v(" Back Home ")])]},proxy:!0}])})},o=[],r={name:"Exception404",methods:{toHome:function(){this.$router.push({path:"/"})}}},s=r,a=n(845),i=(0,a.A)(s,u,o,!1,null,null,null),l=i.exports}}]);
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
"use strict";(self["webpackChunkvue_antd_pro"]=self["webpackChunkvue_antd_pro"]||[]).push([[143],{4049:function(t,e,n){n.r(e),n.d(e,{default:function(){return l}});var u=function(){var t=this,e=t._self._c;return e("a-result",{attrs:{status:"404",title:"404","sub-title":"Sorry, the page you visited does not exist."},scopedSlots:t._u([{key:"extra",fn:function(){return[e("a-button",{attrs:{type:"primary"},on:{click:t.toHome}},[t._v(" Back Home ")])]},proxy:!0}])})},o=[],r={name:"Exception404",methods:{toHome:function(){this.$router.push({path:"/"})}}},s=r,a=n(845),i=(0,a.A)(s,u,o,!1,null,null,null),l=i.exports}}]);
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
"use strict";(self["webpackChunkvue_antd_pro"]=self["webpackChunkvue_antd_pro"]||[]).push([[143],{55273:function(t,e,n){n.r(e),n.d(e,{default:function(){return l}});var u=function(){var t=this,e=t._self._c;return e("a-result",{attrs:{status:"404",title:"404","sub-title":"Sorry, the page you visited does not exist."},scopedSlots:t._u([{key:"extra",fn:function(){return[e("a-button",{attrs:{type:"primary"},on:{click:t.toHome}},[t._v(" Back Home ")])]},proxy:!0}])})},o=[],r={name:"Exception404",methods:{toHome:function(){this.$router.push({path:"/"})}}},s=r,a=n(845),i=(0,a.A)(s,u,o,!1,null,null,null),l=i.exports}}]);
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user