diff --git a/packages/hydrooj/src/handler/home.ts b/packages/hydrooj/src/handler/home.ts index 74eef13c7..fea6b8cf2 100644 --- a/packages/hydrooj/src/handler/home.ts +++ b/packages/hydrooj/src/handler/home.ts @@ -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); diff --git a/packages/ui-default/locales/en.yaml b/packages/ui-default/locales/en.yaml index f7c73a83f..f5cb64e69 100644 --- a/packages/ui-default/locales/en.yaml +++ b/packages/ui-default/locales/en.yaml @@ -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 Gravatar and it will be automatically updated here. diff --git a/packages/ui-default/locales/zh.yaml b/packages/ui-default/locales/zh.yaml index 89ed446ee..7a1078569 100644 --- a/packages/ui-default/locales/zh.yaml +++ b/packages/ui-default/locales/zh.yaml @@ -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.: 你也可以将头像上传到 Gravatar,本站的头像将自动更新。 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.: 作业已超过截止时间,您无法递交本题目。 diff --git a/packages/ui-default/pages/home_settings.page.ts b/packages/ui-default/pages/home_settings.page.ts new file mode 100644 index 000000000..d0069c986 --- /dev/null +++ b/packages/ui-default/pages/home_settings.page.ts @@ -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` + + `); + const $text = $(tpl``); + const $layout = $(` +
{{ _('You can also upload your avatar to Gravatar and it will be automatically updated here.')|safe }}
+