mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 17:36:08 +08:00
ui: simplify user_detail page
This commit is contained in:
1 parent
62ec797652
commit
dd037e36d7
7 files changed
+27
-110
No files matched your search
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hydrooj",
|
||||
"version": "2.36.12",
|
||||
"version": "2.36.13",
|
||||
"bin": "bin/hydrooj.js",
|
||||
"main": "src/loader",
|
||||
"module": "src/loader",
|
||||
|
||||
@@ -2,18 +2,15 @@ import moment from 'moment-timezone';
|
||||
import {
|
||||
BlacklistedError, InvalidTokenError, LoginError,
|
||||
SystemError, UserAlreadyExistError, UserFacingError,
|
||||
UserNotFoundError, VerifyPasswordError,
|
||||
UserNotFoundError, ValidationError, VerifyPasswordError,
|
||||
} from '../error';
|
||||
import { User } from '../interface';
|
||||
import avatar from '../lib/avatar';
|
||||
import { sendMail } from '../lib/mail';
|
||||
import paginate from '../lib/paginate';
|
||||
import { isEmail, isPassword, isUname } from '../lib/validator';
|
||||
import BlackListModel from '../model/blacklist';
|
||||
import { PERM, PRIV } from '../model/builtin';
|
||||
import oauth from '../model/oauth';
|
||||
import problem, { ProblemDoc } from '../model/problem';
|
||||
import record from '../model/record';
|
||||
import * as system from '../model/system';
|
||||
import task from '../model/task';
|
||||
import token from '../model/token';
|
||||
@@ -136,6 +133,7 @@ export class UserRegisterHandler extends Handler {
|
||||
});
|
||||
await sendMail(mail, 'Sign Up', 'user_register_mail', m);
|
||||
this.response.template = 'user_register_mail_sent.html';
|
||||
this.response.body = { mail };
|
||||
} else this.response.redirect = this.url('user_register_with_code', { code: t[0] });
|
||||
} else if (phoneNumber) {
|
||||
if (!global.Hydro.lib.sendSms) throw new SystemError('Cannot send sms');
|
||||
@@ -148,7 +146,7 @@ export class UserRegisterHandler extends Handler {
|
||||
);
|
||||
await global.Hydro.lib.sendSms(phoneNumber, 'register', t[0]);
|
||||
this.response.template = 'user_register_sms.html';
|
||||
}
|
||||
} else throw new ValidationError('mail');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,41 +235,19 @@ class UserDetailHandler extends Handler {
|
||||
async get(domainId: string, uid: number) {
|
||||
if (uid === 0) throw new UserNotFoundError(0);
|
||||
const isSelfProfile = this.user._id === uid;
|
||||
const udoc = await user.getById(domainId, uid);
|
||||
if (!udoc) throw new UserNotFoundError(uid);
|
||||
const [sdoc, rdocs, [pdocs, pcount]] = await Promise.all([
|
||||
const [udoc, sdoc] = await Promise.all([
|
||||
user.getById(domainId, uid),
|
||||
token.getMostRecentSessionByUid(uid),
|
||||
record.getByUid(domainId, uid, 30),
|
||||
this.user.hasPerm(PERM.PERM_VIEW_PROBLEM)
|
||||
? paginate(
|
||||
problem.getMulti(domainId, { owner: uid }),
|
||||
1,
|
||||
100,
|
||||
)
|
||||
: [[], 0, 0] as [ProblemDoc[], number, number],
|
||||
]);
|
||||
const pdict = this.user.hasPerm(PERM.PERM_VIEW_PROBLEM)
|
||||
? await problem.getList(
|
||||
domainId, rdocs.map((rdoc) => rdoc.pid),
|
||||
this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN) || this.user._id, false,
|
||||
)
|
||||
: Object.fromEntries(rdocs.map(
|
||||
(rdoc) => [rdoc.pid, { ...problem.default, pid: rdoc.pid }],
|
||||
));
|
||||
if (!udoc) throw new UserNotFoundError(uid);
|
||||
// Remove sensitive data
|
||||
if (!isSelfProfile && sdoc) {
|
||||
sdoc.createIp = '';
|
||||
sdoc.updateIp = '';
|
||||
sdoc._id = '';
|
||||
}
|
||||
const path = [
|
||||
['Hydro', 'homepage'],
|
||||
['user_detail', 'user_detail', { uid }],
|
||||
];
|
||||
this.response.template = 'user_detail.html';
|
||||
this.response.body = {
|
||||
isSelfProfile, udoc, sdoc, rdocs, pdocs, pcount, pdict, path,
|
||||
};
|
||||
this.response.body = { isSelfProfile, udoc, sdoc };
|
||||
this.extraTitleContent = udoc.uname;
|
||||
}
|
||||
}
|
||||
@@ -343,7 +319,6 @@ export async function apply() {
|
||||
Route('user_oauth', '/oauth/:type', OauthHandler);
|
||||
Route('user_oauth_callback', '/oauth/:type/callback', OauthCallbackHandler);
|
||||
Route('user_register', '/register', UserRegisterHandler, PRIV.PRIV_REGISTER_USER);
|
||||
Route('user_register_without_code', '/register/code', UserRegisterWithCodeHandler, PRIV.PRIV_REGISTER_USER);
|
||||
Route('user_register_with_code', '/register/:code', UserRegisterWithCodeHandler, PRIV.PRIV_REGISTER_USER);
|
||||
Route('user_logout', '/logout', UserLogoutHandler, PRIV.PRIV_USER_PROFILE);
|
||||
Route('user_lostpass', '/lostpass', UserLostPassHandler);
|
||||
|
||||
@@ -219,13 +219,6 @@ class RecordModel {
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@ArgMethod
|
||||
static getByUid(domainId: string, uid: number, limit: number): Promise<RecordDoc[]> {
|
||||
return RecordModel.coll.find({
|
||||
domainId, 'contest.tid': null, hidden: false, uid,
|
||||
}).sort({ _id: -1 }).limit(limit).toArray();
|
||||
}
|
||||
}
|
||||
|
||||
// Mark problem as deleted
|
||||
|
||||
@@ -5,7 +5,8 @@ import { FLAG_ALERT } from 'vj/constant/message';
|
||||
import i18n from 'vj/utils/i18n';
|
||||
import tpl from 'vj/utils/tpl';
|
||||
|
||||
const messagePage = new AutoloadPage('messagePage', () => {
|
||||
const messagePage = new AutoloadPage('messagePage', (pagename) => {
|
||||
if (pagename === 'home_messages') return;
|
||||
let visible = true;
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
const state = document.visibilityState;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@hydrooj/ui-default",
|
||||
"version": "4.21.9",
|
||||
"version": "4.21.10",
|
||||
"author": "undefined <i@undefined.moe>",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "hydro.js",
|
||||
|
||||
@@ -2,7 +2,7 @@ import { NamedPage } from 'vj/misc/Page';
|
||||
import api, { gql } from 'vj/utils/api';
|
||||
import loadReactRedux from 'vj/utils/loadReactRedux';
|
||||
import parseQueryString from 'vj/utils/parseQueryString';
|
||||
|
||||
import VjNotification from 'vj/components/notification';
|
||||
import { ActionDialog } from 'vj/components/dialog';
|
||||
import UserSelectAutoComplete from 'vj/components/autocomplete/UserSelectAutoComplete';
|
||||
|
||||
@@ -39,6 +39,13 @@ const page = new NamedPage('home_messages', () => {
|
||||
type: 'DIALOGUES_MESSAGE_PUSH',
|
||||
payload: msg,
|
||||
});
|
||||
new VjNotification({
|
||||
title: msg.udoc.uname,
|
||||
avatar: msg.udoc.avatarUrl,
|
||||
message: msg.mdoc.content,
|
||||
duration: 15000,
|
||||
action: () => createDialog(msg.udoc),
|
||||
}).show();
|
||||
};
|
||||
|
||||
const userSelector = UserSelectAutoComplete.getOrConstruct($('.dialog__body--user-select [name="user"]'));
|
||||
|
||||
@@ -46,12 +46,12 @@
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if udoc['qq'] %}
|
||||
<a class="profile-header__contact-item" href="javascript:;" name="profile_contact_copy" data-content="{{ udoc['qq'] | base64_encode }}" data-tooltip="{{ _('Copy QQ Number') }}">
|
||||
<a class="profile-header__contact-item" href="javascript:;" name="profile_qq_copy" data-content="{{ udoc['qq'] | base64_encode }}" data-tooltip="{{ _('Copy QQ Number') }}">
|
||||
<span class="icon icon-qq"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if udoc['wechat'] %}
|
||||
<a class="profile-header__contact-item" href="javascript:;" name="profile_contact_copy" data-content="{{ udoc['wechat'] | base64_encode }}" data-tooltip="{{ _('Copy WeChat Account') }}">
|
||||
<a class="profile-header__contact-item" href="javascript:;" name="profile_wechat_copy" data-content="{{ udoc['wechat'] | base64_encode }}" data-tooltip="{{ _('Copy WeChat Account') }}">
|
||||
<span class="icon icon-wechat"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
@@ -98,65 +98,6 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
<li class="section__tab-item">
|
||||
<h1 class="section__tab-title">{{ _('Contributions') }} ({{ pcount }})</h1>
|
||||
<div class="section__tab-main">
|
||||
{% if not pdocs %}
|
||||
{{ nothing.render("Oh, the user doesn't have any contributions!") }}
|
||||
{% else %}
|
||||
<div class="section__header">
|
||||
<h1 class="section__title">{{ _('Contributed Problems') }}</h1>
|
||||
</div>
|
||||
<div class="section__body">
|
||||
{%- for pdoc in pdocs -%}
|
||||
<p><a href="{{ url('problem_detail', pid=pdoc.pid|default(pdoc.docId)) }}">{{ pdoc['title'] }}</a></p>
|
||||
{%- endfor -%}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
<li class="section__tab-item">
|
||||
<h1 class="section__tab-title">{{ _('Submissions') }} ({{ udoc['nSubmit']|default(0) }})</h1>
|
||||
<div class="section__tab-main">
|
||||
{% if not rdocs %}
|
||||
{{ nothing.render("Oh, the user hasn't submitted yet!") }}
|
||||
{% else %}
|
||||
<div class="section__header">
|
||||
<h1 class="section__title">{{ _('Recent Submissions') }}</h1>
|
||||
</div>
|
||||
<div class="section__body no-padding">
|
||||
<table class="data-table record_main__table">
|
||||
<colgroup>
|
||||
<col class="col--status">
|
||||
<col class="col--problem">
|
||||
<col class="col--submit-by">
|
||||
<col class="col--time">
|
||||
<col class="col--memory">
|
||||
<col class="col--lang">
|
||||
<col class="col--submit-at">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col--status record-status--border">{{ _('Status') }}</th>
|
||||
<th class="col--problem">{{ _('Problem') }}</th>
|
||||
<th class="col--submit-by">{{ _('Submit By') }}</th>
|
||||
<th class="col--time">{{ _('Time') }}</th>
|
||||
<th class="col--memory">{{ _('Memory') }}</th>
|
||||
<th class="col--lang">{{ _('Language') }}</th>
|
||||
<th class="col--submit-at">{{ _('Submit At') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{%- for rdoc in rdocs -%}
|
||||
{% set pdoc = pdict[rdoc.pid] %}
|
||||
{% include 'record_main_tr.html' %}
|
||||
{%- endfor -%}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -174,6 +115,12 @@
|
||||
<div class="section side">
|
||||
<div class="section__body">
|
||||
<div class="balancer sidebar-user-stat">
|
||||
<div class="balancer__body">
|
||||
<div class="numbox">
|
||||
<div class="numbox__num medium">{{ udoc.nSubmit or 0 }}</div>
|
||||
<div class="numbox__text">{{ _('Submitted') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="balancer__body">
|
||||
<div class="numbox">
|
||||
<div class="numbox__num medium">{{ udoc.nAccept or 0 }}</div>
|
||||
@@ -186,12 +133,6 @@
|
||||
<div class="numbox__text">{{ _('Solutions Liked') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="balancer__body">
|
||||
<div class="numbox">
|
||||
<div class="numbox__num medium">{{ udoc.nProblems or 0 }}</div>
|
||||
<div class="numbox__text">{{ _('Upload Problem') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user