mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
ui: avatar uploader
This commit is contained in:
1 parent
dc7f2a877e
commit
9672436151
5 files changed
+106
No files matched your search
@@ -1,3 +1,4 @@
|
||||
import path from 'path';
|
||||
import yaml from 'js-yaml';
|
||||
import { ObjectID } from 'mongodb';
|
||||
import { camelCase } from '@hydrooj/utils/lib/utils';
|
||||
@@ -20,6 +21,7 @@ import domain from '../model/domain';
|
||||
import message from '../model/message';
|
||||
import ProblemModel from '../model/problem';
|
||||
import * as setting from '../model/setting';
|
||||
import storage from '../model/storage';
|
||||
import * as system from '../model/system';
|
||||
import token from '../model/token';
|
||||
import * as training from '../model/training';
|
||||
@@ -288,6 +290,23 @@ class HomeSettingsHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
class HomeAvatarHandler extends Handler {
|
||||
@param('avatar', Types.String, true)
|
||||
async post(domainId: string, input: string) {
|
||||
if (input) await user.setById(this.user._id, { avatar: input });
|
||||
else if (this.request.files.file) {
|
||||
const file = this.request.files.file;
|
||||
if (file.size > 8 * 1024 * 1024) throw new ValidationError('file');
|
||||
const ext = path.extname(file.originalFilename);
|
||||
if (!['.jpg', '.jpeg', '.png'].includes(ext)) throw new ValidationError('file');
|
||||
await storage.put(`user/${this.user._id}/.avatar${ext}`, file.filepath, this.user._id);
|
||||
// TODO: cached avatar
|
||||
await user.setById(this.user._id, { avatar: `url:/file/${this.user._id}/.avatar${ext}` });
|
||||
} else throw new ValidationError('avatar');
|
||||
this.back();
|
||||
}
|
||||
}
|
||||
|
||||
class UserChangemailWithCodeHandler extends Handler {
|
||||
@param('code', Types.String)
|
||||
async get(domainId: string, code: string) {
|
||||
@@ -444,6 +463,7 @@ export async function apply(ctx: Context) {
|
||||
ctx.Route('home_security', '/home/security', HomeSecurityHandler, PRIV.PRIV_USER_PROFILE);
|
||||
ctx.Route('user_changemail_with_code', '/home/changeMail/:code', UserChangemailWithCodeHandler, PRIV.PRIV_USER_PROFILE);
|
||||
ctx.Route('home_settings', '/home/settings/:category', HomeSettingsHandler, PRIV.PRIV_USER_PROFILE);
|
||||
ctx.Route('home_avatar', '/home/avatar', HomeAvatarHandler, PRIV.PRIV_USER_PROFILE);
|
||||
ctx.Route('home_domain', '/home/domain', HomeDomainHandler, PRIV.PRIV_USER_PROFILE);
|
||||
ctx.Route('home_domain_create', '/home/domain/create', HomeDomainCreateHandler, PRIV.PRIV_CREATE_DOMAIN);
|
||||
if (system.get('server.message')) ctx.Route('home_messages', '/home/messages', HomeMessagesHandler, PRIV.PRIV_USER_PROFILE);
|
||||
|
||||
@@ -63,3 +63,4 @@ user_logout: Logout
|
||||
user_lostpass: Lost Password
|
||||
user_register: Register
|
||||
wiki_help: Help
|
||||
You can also upload your avatar to Gravatar and it will be automatically updated here.: You can also upload your avatar to <a href="https://gravatar.com/">Gravatar</a> and it will be automatically updated here.
|
||||
@@ -960,6 +960,7 @@ Write Your Comment: 发表您的评论
|
||||
Write Your Solution: 发表您的题解
|
||||
Year: 年
|
||||
You are not allowed to join the domain. The link is either invalid or expired.: 您无法加入该域,链接无效或已过期。
|
||||
You can also upload your avatar to Gravatar and it will be automatically updated here.: 你也可以将头像上传到 <a href="https://gravatar.com/">Gravatar</a>,本站的头像将自动更新。
|
||||
You can create your own training plans and share with others.: 您可以创建您自己的训练计划并且与他人分享。
|
||||
You cannot submit for this problem because the contest is ended. You can click "Open in Problem Set" to view this problem in normal mode.: 该比赛已结束,您无法在比赛模式下递交该题目。您可以点击“在题库中打开”以普通模式查看和递交本题。
|
||||
You cannot submit for this problem because the homework's deadline is due.: 作业已超过截止时间,您无法递交本题目。
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import $ from 'jquery';
|
||||
import Notification from 'vj/components/notification';
|
||||
import { NamedPage } from 'vj/misc/Page';
|
||||
import {
|
||||
delay, i18n, request, tpl,
|
||||
} from 'vj/utils';
|
||||
|
||||
export default new NamedPage('home_account', () => {
|
||||
document.getElementsByName('avatar')[0].parentNode.parentNode.parentElement.remove();
|
||||
const $type = $(tpl`
|
||||
<select id="type" class="select">
|
||||
<option value="gravatar">${i18n('Gravatar')}</option>
|
||||
<option value="github">${i18n('Github')}</option>
|
||||
<option value="qq">${i18n('QQ')}</option>
|
||||
<option value="upload">${i18n('Upload')}</option>
|
||||
</select>
|
||||
`);
|
||||
const $text = $(tpl`<input type="text" class="textbox" placeholder="${i18n('Avatar URL')}">`);
|
||||
const $layout = $(`
|
||||
<div class="row">
|
||||
${[['type', 3], ['text', 6], ['btn', 3]].map(([i, w]) => `
|
||||
<div class="medium-${w} columns form__item">
|
||||
<div name="form_item_${i}"></div>
|
||||
</div>
|
||||
`).join(' ')}
|
||||
</div>
|
||||
`);
|
||||
const $file: JQuery<HTMLInputElement> = $('<input type="file" style="display:none" accept=".jpg,.jpeg,.png">');
|
||||
const $confirm = $(tpl`<button class="button rounded primary">${i18n('Confirm')}</button>`);
|
||||
$('button.change-avatar').on('click', () => {
|
||||
$('.changeAvatar').append($layout);
|
||||
$('[name="form_item_type"]').append($type);
|
||||
$('[name="form_item_text"]').append($text);
|
||||
$('[name="form_item_text"]').append($file);
|
||||
$('[name="form_item_btn"]').append($confirm);
|
||||
$('button.change-avatar').hide();
|
||||
$type.trigger('change');
|
||||
});
|
||||
$type.on('change', () => {
|
||||
if ($type.val() === 'upload') {
|
||||
$text.hide();
|
||||
$file.show();
|
||||
} else {
|
||||
$text.show();
|
||||
$file.hide();
|
||||
const placeholder = $type.val() === 'gravatar'
|
||||
? 'Email address'
|
||||
: $type.val() === 'github'
|
||||
? 'Github username'
|
||||
: 'QQ ID';
|
||||
$text.attr('placeholder', i18n(placeholder));
|
||||
}
|
||||
});
|
||||
$confirm.on('click', async () => {
|
||||
if ($type.val() === 'upload') {
|
||||
const formData = new FormData();
|
||||
formData.append('file', $file[0].files[0]);
|
||||
await request.postFile('/home/avatar', formData);
|
||||
Notification.success(i18n('Upload success.'));
|
||||
} else {
|
||||
await request.post('/home/avatar', {
|
||||
avatar: `${$type.val()}:${$text.val()}`,
|
||||
});
|
||||
Notification.success(i18n('Updated.'));
|
||||
}
|
||||
await delay(800);
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,20 @@
|
||||
{% extends "layout/home_base.html" %}
|
||||
{% block home_content %}
|
||||
{% if category == "account" %}
|
||||
<div class="section" id="upload_avatar" data-heading-extract-to="#menu-item-home_account" style="nojs--hide">
|
||||
<div class="section__header">
|
||||
<h1 class="section__title" id="avatar" data-heading>{{ _('Avatar') }}</h1>
|
||||
</div>
|
||||
<div class="section__body typo">
|
||||
<p>{{ _('You can also upload your avatar to Gravatar and it will be automatically updated here.')|safe }}</p>
|
||||
</div>
|
||||
<div class="section__body">
|
||||
<img width="128px" height="128px" src="{{ avatarUrl(current.avatar, 128) }}" alt="{{ current.uname }}">
|
||||
<div class="changeAvatar"></div>
|
||||
<button class="change-avatar button rounded primary">{{ _('Change avatar') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="section" data-heading-extract-to="#menu-item-home_{{ category }}">
|
||||
{% include "partials/setting.html" %}
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user