mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
修复discussion模块
This commit is contained in:
1 parent
2554cf660a
commit
33e277f28f
30 files changed
+2460
-187
No files matched your search
+1
-1
@@ -2,7 +2,7 @@ const fs = require('fs');
|
|||||||
const root = require('./root');
|
const root = require('./root');
|
||||||
|
|
||||||
async function build(type) {
|
async function build(type) {
|
||||||
if (!['development', 'production'].includes(type)) throw new Error('Unknown type: ' + type);
|
if (!['development', 'production'].includes(type)) throw new Error(`Unknown type: ${type}`);
|
||||||
try {
|
try {
|
||||||
fs.rmdirSync(root('.build'));
|
fs.rmdirSync(root('.build'));
|
||||||
} catch (e) { }
|
} catch (e) { }
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ process.stdin.on('data', async (input) => {
|
|||||||
|
|
||||||
global.Hydro = {
|
global.Hydro = {
|
||||||
handler: {},
|
handler: {},
|
||||||
template: {}
|
template: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
require('./lib/i18n');
|
require('./lib/i18n');
|
||||||
@@ -44,7 +44,7 @@ async function run() {
|
|||||||
for (const i in global.Hydro.handler) {
|
for (const i in global.Hydro.handler) {
|
||||||
await global.Hydro.handler[i].apply();
|
await global.Hydro.handler[i].apply();
|
||||||
}
|
}
|
||||||
const notfound = require(`./handler/notfound`);
|
const notfound = require('./handler/notfound');
|
||||||
await notfound.apply();
|
await notfound.apply();
|
||||||
server.start();
|
server.start();
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-6
@@ -225,6 +225,13 @@ class DiscussionNotFoundError extends NotFoundError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MessageNotFoundError extends NotFoundError {
|
||||||
|
constructor(mid) {
|
||||||
|
super('Message {0} not found.');
|
||||||
|
this.params = [mid];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
global.Hydro.error = module.exports = {
|
global.Hydro.error = module.exports = {
|
||||||
BadRequestError,
|
BadRequestError,
|
||||||
BlacklistedError,
|
BlacklistedError,
|
||||||
@@ -258,6 +265,7 @@ global.Hydro.error = module.exports = {
|
|||||||
DocumentNotFoundError,
|
DocumentNotFoundError,
|
||||||
DiscussionNotFoundError,
|
DiscussionNotFoundError,
|
||||||
RoleAlreadyExistError,
|
RoleAlreadyExistError,
|
||||||
|
MessageNotFoundError,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -314,12 +322,6 @@ class DiscussionNodeAlreadyExistError(ForbiddenError):
|
|||||||
return 'Discussion node {1} already exists.'
|
return 'Discussion node {1} already exists.'
|
||||||
|
|
||||||
|
|
||||||
class MessageNotFoundError(NotFoundError):
|
|
||||||
@property
|
|
||||||
def message(self):
|
|
||||||
return 'Message {0} not found.'
|
|
||||||
|
|
||||||
|
|
||||||
class TrainingRequirementNotSatisfiedError(ForbiddenError):
|
class TrainingRequirementNotSatisfiedError(ForbiddenError):
|
||||||
@property
|
@property
|
||||||
def message(self):
|
def message(self):
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ class DiscussionHandler extends Handler {
|
|||||||
if (did) {
|
if (did) {
|
||||||
this.ddoc = await discussion.get(did);
|
this.ddoc = await discussion.get(did);
|
||||||
if (!this.ddoc) throw new DiscussionNotFoundError(did);
|
if (!this.ddoc) throw new DiscussionNotFoundError(did);
|
||||||
type = this.ddoc.type;
|
type = this.ddoc.parentType;
|
||||||
docId = this.ddoc.parent;
|
docId = this.ddoc.parentId;
|
||||||
if (drid) {
|
if (drid) {
|
||||||
this.drdoc = await discussion.getReply(drid, did);
|
this.drdoc = await discussion.getReply(drid, did);
|
||||||
if (!this.drdoc) throw new DiscussionNotFoundError(drid);
|
if (!this.drdoc) throw new DiscussionNotFoundError(drid);
|
||||||
|
|||||||
+72
-79
@@ -1,13 +1,15 @@
|
|||||||
const {
|
const {
|
||||||
VerifyPasswordError, UserAlreadyExistError, InvalidTokenError,
|
VerifyPasswordError, UserAlreadyExistError, InvalidTokenError,
|
||||||
NotFoundError,
|
NotFoundError, MessageNotFoundError,
|
||||||
} = require('../error');
|
} = require('../error');
|
||||||
const options = require('../options');
|
const options = require('../options');
|
||||||
|
const bus = require('../service/bus');
|
||||||
const { Route, Handler } = require('../service/server');
|
const { Route, Handler } = require('../service/server');
|
||||||
const md5 = require('../lib/md5');
|
const md5 = require('../lib/md5');
|
||||||
const contest = require('../model/contest');
|
const contest = require('../model/contest');
|
||||||
const user = require('../model/user');
|
const user = require('../model/user');
|
||||||
const setting = require('../model/setting');
|
const setting = require('../model/setting');
|
||||||
|
const discussion = require('../model/discussion');
|
||||||
const token = require('../model/token');
|
const token = require('../model/token');
|
||||||
const training = require('../model/training');
|
const training = require('../model/training');
|
||||||
const {
|
const {
|
||||||
@@ -45,14 +47,13 @@ class HomeHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async discussion() {
|
async discussion() {
|
||||||
// TODO(masnn)
|
if (this.user.hasPerm(PERM_VIEW_DISCUSSION)) {
|
||||||
// if (this.user.hasPerm(PERM_VIEW_DISCUSSION)) {
|
const ddocs = await discussion.getMulti()
|
||||||
// const ddocs = await discussion.getMulti()
|
.limit(DISCUSSIONS_ON_MAIN)
|
||||||
// .limit(DISCUSSIONS_ON_MAIN)
|
.toArray();
|
||||||
// .toArray();
|
const vndict = await discussion.getListVnodes(ddocs, this);
|
||||||
// const vndict = await discussion.getListVnodes(map(discussion.node_id, ddocs));
|
return [ddocs, vndict];
|
||||||
// return [ddocs, vndict];
|
}
|
||||||
// }
|
|
||||||
return [[], {}];
|
return [[], {}];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,13 +165,72 @@ class UserChangemailWithCodeHandler extends Handler {
|
|||||||
const udoc = await user.getByEmail(tdoc.mail);
|
const udoc = await user.getByEmail(tdoc.mail);
|
||||||
if (udoc) throw new UserAlreadyExistError(tdoc.mail);
|
if (udoc) throw new UserAlreadyExistError(tdoc.mail);
|
||||||
// TODO(twd2): Ensure mail is unique.
|
// TODO(twd2): Ensure mail is unique.
|
||||||
await user.set_mail(this.user._id, tdoc.mail);
|
await user.setEmail(this.user._id, tdoc.mail);
|
||||||
await token.delete(code, token.TYPE_CHANGEMAIL);
|
await token.delete(code, token.TYPE_CHANGEMAIL);
|
||||||
this.response.body = {};
|
|
||||||
this.response.redirect = '/home/security';
|
this.response.redirect = '/home/security';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class HomeMessagesHandler extends Handler {
|
||||||
|
udoc(udict, key) { // eslint-disable-line class-methods-use-this
|
||||||
|
const udoc = udict[key];
|
||||||
|
if (!udoc) return;
|
||||||
|
const gravatar_url = misc.gravatar_url(udoc.gravatar);
|
||||||
|
if (udoc.gravatar) udict[key] = { ...udoc, gravatar_url, gravatar: '' };
|
||||||
|
}
|
||||||
|
|
||||||
|
async prepare() {
|
||||||
|
this.checkPerm(PERM_LOGGEDIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
async get() {
|
||||||
|
// TODO(iceboy): projection, pagination.
|
||||||
|
const mdocs = await message.getMulti(this.user._id).sort('_id', -1).limit(50).toArray();
|
||||||
|
const udict = await user.getList([
|
||||||
|
...mdocs.map((mdoc) => mdoc.from),
|
||||||
|
...mdocs.map((mdoc) => mdoc.to),
|
||||||
|
]);
|
||||||
|
// TODO(twd2): improve here:
|
||||||
|
for (const mdoc of mdocs) {
|
||||||
|
this.modify_udoc(udict, mdoc.from);
|
||||||
|
this.modify_udoc(udict, mdoc.to);
|
||||||
|
}
|
||||||
|
this.response.body = { messages: mdocs, udict };
|
||||||
|
this.response.template = 'home_message.html';
|
||||||
|
}
|
||||||
|
|
||||||
|
async postSendMessage({ uid, content }) {
|
||||||
|
const udoc = await user.getById(uid);
|
||||||
|
const mdoc = await message.add(this.user._id, udoc._id, content);
|
||||||
|
// TODO(twd2): improve here:
|
||||||
|
// projection
|
||||||
|
mdoc.from = this.user;
|
||||||
|
this.modify_udoc(mdoc, 'from');
|
||||||
|
mdoc.to = udoc;
|
||||||
|
this.modify_udoc(mdoc, 'to');
|
||||||
|
if (this.user._id !== uid) {
|
||||||
|
await bus.publish(`user_message-${uid}`, { type: 'new', data: mdoc });
|
||||||
|
}
|
||||||
|
this.back({ mdoc });
|
||||||
|
}
|
||||||
|
|
||||||
|
async postReplyMessage({ message_id, content }) {
|
||||||
|
const [mdoc, reply] = await message.addReply(message_id, this.user._id, content);
|
||||||
|
if (!mdoc) throw new MessageNotFoundError(message_id);
|
||||||
|
if (mdoc.from !== mdoc.to) {
|
||||||
|
const other = mdoc.from === this.user._id ? mdoc.from : mdoc.to;
|
||||||
|
await bus.publish(`user_message-${other}`, { type: 'reply', data: mdoc });
|
||||||
|
}
|
||||||
|
mdoc.reply = [reply];
|
||||||
|
this.back({ reply });
|
||||||
|
}
|
||||||
|
|
||||||
|
async postDeleteMessage({ message_id }) {
|
||||||
|
await message.delete(message_id, this.user._id);
|
||||||
|
this.back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function apply() {
|
async function apply() {
|
||||||
Route('/', module.exports.HomeHandler);
|
Route('/', module.exports.HomeHandler);
|
||||||
Route('/home/security', module.exports.HomeSecurityHandler);
|
Route('/home/security', module.exports.HomeSecurityHandler);
|
||||||
@@ -181,75 +241,8 @@ async function apply() {
|
|||||||
global.Hydro.handler.home = module.exports = {
|
global.Hydro.handler.home = module.exports = {
|
||||||
HomeHandler, HomeSecurityHandler, HomeSettingsHandler, UserChangemailWithCodeHandler, apply,
|
HomeHandler, HomeSecurityHandler, HomeSettingsHandler, UserChangemailWithCodeHandler, apply,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@app.route('/home/messages', 'home_messages', global_route=True)
|
|
||||||
class HomeMessagesHandler(base.OperationHandler):
|
|
||||||
def modify_udoc(this, udict, key):
|
|
||||||
udoc = udict.get(key)
|
|
||||||
if not udoc:
|
|
||||||
return
|
|
||||||
gravatar_url = misc.gravatar_url(udoc.get('gravatar'))
|
|
||||||
if 'gravatar' in udoc and udoc['gravatar']:
|
|
||||||
udict[key] = {**udoc,
|
|
||||||
'gravatar_url': gravatar_url,
|
|
||||||
'gravatar': ''}
|
|
||||||
|
|
||||||
@base.require_priv(builtin.PRIV_USER_PROFILE)
|
|
||||||
async def get(this):
|
|
||||||
# TODO(iceboy): projection, pagination.
|
|
||||||
mdocs = await message.get_multi(this.user['_id']).sort([('_id', -1)]).limit(50).to_list()
|
|
||||||
udict = await user.get_dict(
|
|
||||||
itertools.chain.from_iterable((mdoc['sender_uid'], mdoc['sendee_uid']) for mdoc in mdocs),
|
|
||||||
fields=user.PROJECTION_PUBLIC)
|
|
||||||
# TODO(twd2): improve here:
|
|
||||||
for mdoc in mdocs:
|
|
||||||
this.modify_udoc(udict, mdoc['sender_uid'])
|
|
||||||
this.modify_udoc(udict, mdoc['sendee_uid'])
|
|
||||||
this.json_or_render('home_messages.html', messages=mdocs, udict=udict)
|
|
||||||
|
|
||||||
@base.require_priv(builtin.PRIV_USER_PROFILE)
|
|
||||||
@base.require_csrf_token
|
|
||||||
@base.sanitize
|
|
||||||
async def post_send_message(this, *, uid: int, content: str):
|
|
||||||
udoc = await user.get_by_uid(uid, user.PROJECTION_PUBLIC)
|
|
||||||
if not udoc:
|
|
||||||
raise error.UserNotFoundError(uid)
|
|
||||||
mdoc = await message.add(this.user['_id'], udoc['_id'], content)
|
|
||||||
# TODO(twd2): improve here:
|
|
||||||
# projection
|
|
||||||
sender_udoc = await user.get_by_uid(this.user['_id'], user.PROJECTION_PUBLIC)
|
|
||||||
mdoc['sender_udoc'] = sender_udoc
|
|
||||||
this.modify_udoc(mdoc, 'sender_udoc')
|
|
||||||
mdoc['sendee_udoc'] = udoc
|
|
||||||
this.modify_udoc(mdoc, 'sendee_udoc')
|
|
||||||
if this.user['_id'] != uid:
|
|
||||||
await bus.publish('message_received-' + str(uid), {'type': 'new', 'data': mdoc})
|
|
||||||
this.json_or_redirect(this.url, mdoc=mdoc)
|
|
||||||
|
|
||||||
@base.require_priv(builtin.PRIV_USER_PROFILE)
|
|
||||||
@base.require_csrf_token
|
|
||||||
@base.sanitize
|
|
||||||
async def post_reply_message(this, *, message_id: objectid.ObjectId, content: str):
|
|
||||||
mdoc, reply = await message.add_reply(message_id, this.user['_id'], content)
|
|
||||||
if not mdoc:
|
|
||||||
return error.MessageNotFoundError(message_id)
|
|
||||||
if mdoc['sender_uid'] != mdoc['sendee_uid']:
|
|
||||||
if mdoc['sender_uid'] == this.user['_id']:
|
|
||||||
other_uid = mdoc['sendee_uid']
|
|
||||||
else:
|
|
||||||
other_uid = mdoc['sender_uid']
|
|
||||||
mdoc['reply'] = [reply]
|
|
||||||
await bus.publish('message_received-' + str(other_uid), {'type': 'reply', 'data': mdoc})
|
|
||||||
this.json_or_redirect(this.url, reply=reply)
|
|
||||||
|
|
||||||
@base.require_priv(builtin.PRIV_USER_PROFILE)
|
|
||||||
@base.require_csrf_token
|
|
||||||
@base.sanitize
|
|
||||||
async def post_delete_message(this, *, message_id: objectid.ObjectId):
|
|
||||||
await message.delete(message_id, this.user['_id'])
|
|
||||||
this.back();
|
|
||||||
|
|
||||||
|
|
||||||
@app.connection_route('/home/messages-conn', 'home_messages-conn', global_route=True)
|
@app.connection_route('/home/messages-conn', 'home_messages-conn', global_route=True)
|
||||||
class HomeMessagesConnection(base.Connection):
|
class HomeMessagesConnection(base.Connection):
|
||||||
@base.require_priv(builtin.PRIV_USER_PROFILE)
|
@base.require_priv(builtin.PRIV_USER_PROFILE)
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ class JudgeHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async get({ check = false }) {
|
async get({ check = false }) {
|
||||||
this.response.body = {};
|
|
||||||
if (check) return;
|
if (check) return;
|
||||||
const tasks = [];
|
const tasks = [];
|
||||||
let rid = await queue.get('judge', false);
|
let rid = await queue.get('judge', false);
|
||||||
@@ -122,17 +121,16 @@ class JudgeHandler extends Handler {
|
|||||||
tasks.push(task);
|
tasks.push(task);
|
||||||
rid = await queue.get('judge', false); // eslint-disable-line no-await-in-loop
|
rid = await queue.get('judge', false); // eslint-disable-line no-await-in-loop
|
||||||
}
|
}
|
||||||
|
this.response.body = { tasks };
|
||||||
}
|
}
|
||||||
|
|
||||||
async postNext() {
|
async postNext() {
|
||||||
await next(this.request.body);
|
await next(this.request.body);
|
||||||
this.response.body = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async postEnd() {
|
async postEnd() {
|
||||||
this.request.body.judger = this.user._id;
|
this.request.body.judger = this.user._id;
|
||||||
await end(this.request.body);
|
await end(this.request.body);
|
||||||
this.response.body = {};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class JudgeConnectionHandler extends ConnectionHandler {
|
class JudgeConnectionHandler extends ConnectionHandler {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class ManageEditHandler extends ManageHandler {
|
|||||||
await user.setById(0, {
|
await user.setById(0, {
|
||||||
uname, unameLower, gravatar, bio,
|
uname, unameLower, gravatar, bio,
|
||||||
});
|
});
|
||||||
this.back();
|
this.response.redirect = '/manage/dashboard';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ class ManageUserHandler extends ManageHandler {
|
|||||||
const uids = [];
|
const uids = [];
|
||||||
const rudocs = {};
|
const rudocs = {};
|
||||||
const [udocs, roles, system] = await Promise.all([
|
const [udocs, roles, system] = await Promise.all([
|
||||||
user.getMulti({ role: { $ne: 'default' } }).toArray(),
|
user.getMulti({ role: { $nin: ['default', 'guest'] } }).toArray(),
|
||||||
user.getRoles(),
|
user.getRoles(),
|
||||||
user.getById(0),
|
user.getById(0),
|
||||||
]);
|
]);
|
||||||
@@ -61,7 +61,7 @@ class ManageUserHandler extends ManageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async postSetUser({ uid, role }) {
|
async postSetUser({ uid, role }) {
|
||||||
await user.setById(uid, { role });
|
await user.setRole(uid, role);
|
||||||
this.back();
|
this.back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ const { NotFoundError } = require('../error');
|
|||||||
|
|
||||||
class NotFoundHandler extends Handler {
|
class NotFoundHandler extends Handler {
|
||||||
async prepare() {
|
async prepare() {
|
||||||
throw new NotFoundError();
|
throw new NotFoundError(); // eslint-disable-line class-methods-use-this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ class UserLoginHandler extends Handler {
|
|||||||
udoc.password = '';
|
udoc.password = '';
|
||||||
this.session.uid = udoc._id;
|
this.session.uid = udoc._id;
|
||||||
this.session.rememberme = rememberme;
|
this.session.rememberme = rememberme;
|
||||||
this.response.body = {};
|
|
||||||
const referer = this.request.headers.referer || '/';
|
const referer = this.request.headers.referer || '/';
|
||||||
this.response.redirect = referer.endsWith('/login') ? '/' : referer;
|
this.response.redirect = referer.endsWith('/login') ? '/' : referer;
|
||||||
}
|
}
|
||||||
@@ -42,7 +41,6 @@ class UserLogoutHandler extends Handler {
|
|||||||
|
|
||||||
async post() {
|
async post() {
|
||||||
this.session = { uid: 1 };
|
this.session = { uid: 1 };
|
||||||
this.response.body = {};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +64,6 @@ class UserRegisterHandler extends Handler {
|
|||||||
if (options.smtp.user) {
|
if (options.smtp.user) {
|
||||||
const m = await this.renderHTML('user_register_mail', { url: `/register/${t}` });
|
const m = await this.renderHTML('user_register_mail', { url: `/register/${t}` });
|
||||||
await sendMail(mail, 'Sign Up', 'user_register_mail', m);
|
await sendMail(mail, 'Sign Up', 'user_register_mail', m);
|
||||||
this.response.body = {};
|
|
||||||
this.response.template = 'user_register_mail_sent.html';
|
this.response.template = 'user_register_mail_sent.html';
|
||||||
} else {
|
} else {
|
||||||
this.response.redirect = `/register/${t[0]}`;
|
this.response.redirect = `/register/${t[0]}`;
|
||||||
@@ -98,7 +95,6 @@ class UserRegisterWithCodeHandler extends Handler {
|
|||||||
});
|
});
|
||||||
await token.delete(code, token.TYPE_REGISTRATION);
|
await token.delete(code, token.TYPE_REGISTRATION);
|
||||||
this.session.uid = uid;
|
this.session.uid = uid;
|
||||||
this.response.body = {};
|
|
||||||
this.response.redirect = '/';
|
this.response.redirect = '/';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,7 +119,6 @@ class UserLostPassHandler extends Handler {
|
|||||||
);
|
);
|
||||||
const m = await this.renderHTML('user_lostpass_mail', { url: `/lostpass/${tid}`, uname: udoc.uname });
|
const m = await this.renderHTML('user_lostpass_mail', { url: `/lostpass/${tid}`, uname: udoc.uname });
|
||||||
await sendMail(mail, 'Lost Password', 'user_lostpass_mail', m);
|
await sendMail(mail, 'Lost Password', 'user_lostpass_mail', m);
|
||||||
this.response.body = {};
|
|
||||||
this.response.template = 'user_lostpass_mail_sent.html';
|
this.response.template = 'user_lostpass_mail_sent.html';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,7 +169,7 @@ class UserSearchHandler extends Handler {
|
|||||||
}
|
}
|
||||||
for (const i in udocs) {
|
for (const i in udocs) {
|
||||||
if (udocs[i].gravatar) {
|
if (udocs[i].gravatar) {
|
||||||
udocs[i].gravatar_url = misc.gravatar_url[udocs[i].gravatar];
|
udocs[i].gravatar_url = misc.gravatar_url(udocs[i].gravatar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.response.body = udocs;
|
this.response.body = udocs;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ exports.udoc = {
|
|||||||
regat: new Date(),
|
regat: new Date(),
|
||||||
regip: '0.0.0.0',
|
regip: '0.0.0.0',
|
||||||
gravatar: '',
|
gravatar: '',
|
||||||
|
viewLang: 'zh_CN',
|
||||||
loginat: new Date(),
|
loginat: new Date(),
|
||||||
loginip: '0.0.0.0',
|
loginip: '0.0.0.0',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ export interface Udoc {
|
|||||||
nSubmit: number
|
nSubmit: number
|
||||||
nLike: number
|
nLike: number
|
||||||
perm: string
|
perm: string
|
||||||
|
viewLang: string
|
||||||
|
codeLang: string
|
||||||
|
codeTemplate: string
|
||||||
|
gravatar: string
|
||||||
hasPerm: Function
|
hasPerm: Function
|
||||||
checkPassword: Function
|
checkPassword: Function
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -1,8 +1,9 @@
|
|||||||
const md5 = require('./md5');
|
const md5 = require('./md5');
|
||||||
|
|
||||||
exports.gravatar_url = function gravatarUrl(email, size) {
|
exports.gravatar_url = function gravatarUrl(email, size = 32) {
|
||||||
return `//gravatar.loli.net/avatar/${md5((email || '').toString().trim().toLowerCase())}?d=mm&s=${size}`;
|
return `//gravatar.loli.net/avatar/${md5((email || '').toString().trim().toLowerCase())}?d=mm&s=${size}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.datetime_span = function datetimeSpan(dt, relative = true, format = '%Y-%m-%d %H:%M:%S') {
|
exports.datetime_span = function datetimeSpan(dt, relative = true, format = '%Y-%m-%d %H:%M:%S') {
|
||||||
if (!dt) return 'DATETIME_SPAN_ERROR';
|
if (!dt) return 'DATETIME_SPAN_ERROR';
|
||||||
if (dt.generationTime) dt = new Date(dt.generationTime * 1000);
|
if (dt.generationTime) dt = new Date(dt.generationTime * 1000);
|
||||||
@@ -13,6 +14,7 @@ exports.datetime_span = function datetimeSpan(dt, relative = true, format = '%Y-
|
|||||||
dt.format(format),
|
dt.format(format),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.paginate = function* paginate(page, numPages) {
|
exports.paginate = function* paginate(page, numPages) {
|
||||||
const radius = 2; let first; let
|
const radius = 2; let first; let
|
||||||
last;
|
last;
|
||||||
@@ -33,6 +35,7 @@ exports.paginate = function* paginate(page, numPages) {
|
|||||||
if (page < numPages) yield ['next', page + 1];
|
if (page < numPages) yield ['next', page + 1];
|
||||||
yield ['last', numPages];
|
yield ['last', numPages];
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.format_size = function formatSize(size, base = 1) {
|
exports.format_size = function formatSize(size, base = 1) {
|
||||||
size *= base;
|
size *= base;
|
||||||
const unit = 1024;
|
const unit = 1024;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const { ObjectID } = require('bson');
|
const { ObjectID } = require('bson');
|
||||||
|
const problem = require('./problem');
|
||||||
const { DocumentNotFoundError } = require('../error');
|
const { DocumentNotFoundError } = require('../error');
|
||||||
const db = require('../service/db.js');
|
const db = require('../service/db.js');
|
||||||
|
|
||||||
@@ -6,8 +7,8 @@ const coll = db.collection('discussion');
|
|||||||
const collReply = db.collection('discussion.reply');
|
const collReply = db.collection('discussion.reply');
|
||||||
const collStatus = db.collection('discussion.status');
|
const collStatus = db.collection('discussion.status');
|
||||||
|
|
||||||
function add(parentType, parentId, owner, title, content, ip = null, highlight = false) {
|
async function add(parentType, parentId, owner, title, content, ip = null, highlight = false) {
|
||||||
return coll.insertOne({
|
let res = await coll.insertOne({
|
||||||
owner,
|
owner,
|
||||||
title,
|
title,
|
||||||
content,
|
content,
|
||||||
@@ -18,6 +19,7 @@ function add(parentType, parentId, owner, title, content, ip = null, highlight =
|
|||||||
nReply: 0,
|
nReply: 0,
|
||||||
updateAt: new Date(),
|
updateAt: new Date(),
|
||||||
});
|
});
|
||||||
|
return res.insertedId;
|
||||||
}
|
}
|
||||||
|
|
||||||
function get(did) {
|
function get(did) {
|
||||||
@@ -128,6 +130,26 @@ function getStatus(did, uid) {
|
|||||||
return collStatus.findOne({ did, uid });
|
return collStatus.findOne({ did, uid });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getVnode(ddoc, handler) {
|
||||||
|
if (ddoc.parentType === 'problem') {
|
||||||
|
const pdoc = await problem.getById(ddoc.parentId);
|
||||||
|
if (!pdoc) return null;
|
||||||
|
if (pdoc.hidden && handler) handler.checkPerm(PERM_VIEW_PROBLEM_HIDDEN);
|
||||||
|
return { ...pdoc, parentType: ddoc.parentType, parentId: ddoc.parentId };
|
||||||
|
} if (ddoc.parentType === 'contest') {
|
||||||
|
const tdoc = await contest.get(ddoc.parentId);
|
||||||
|
return { ...tdoc, parentType: ddoc.parentType, parentId: ddoc.parentId };
|
||||||
|
} return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getListVnodes(ddocs, handler) {
|
||||||
|
const res = {};
|
||||||
|
for (const ddoc of ddocs) {
|
||||||
|
res[ddoc._id] = await getVnode(ddoc, handler);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
add,
|
add,
|
||||||
get,
|
get,
|
||||||
@@ -147,4 +169,6 @@ module.exports = {
|
|||||||
delTailReply,
|
delTailReply,
|
||||||
setStar,
|
setStar,
|
||||||
getStatus,
|
getStatus,
|
||||||
|
getVnode,
|
||||||
|
getListVnodes,
|
||||||
};
|
};
|
||||||
+3
-2
@@ -15,12 +15,13 @@ class USER {
|
|||||||
this.salt = user.salt;
|
this.salt = user.salt;
|
||||||
this.hash = user.hash;
|
this.hash = user.hash;
|
||||||
this.perm = user.perm;
|
this.perm = user.perm;
|
||||||
this.lang = user.language || 'zh_CN';
|
this.viewLang = user.language || 'zh_CN';
|
||||||
this.codeLang = user.codeLang || 'c';
|
this.codeLang = user.codeLang || 'c';
|
||||||
this.codeTemplate = user.codeTemplate || '';
|
this.codeTemplate = user.codeTemplate || '';
|
||||||
this.regat = user.regat;
|
this.regat = user.regat;
|
||||||
this.loginat = user.loginat;
|
this.loginat = user.loginat;
|
||||||
this.bio = user.bio || '';
|
this.bio = user.bio || '';
|
||||||
|
this.gravatar = user.gravatar || '';
|
||||||
this.nAccept = user.nAccept || 0;
|
this.nAccept = user.nAccept || 0;
|
||||||
this.nSubmit = user.nSubmit || 0;
|
this.nSubmit = user.nSubmit || 0;
|
||||||
}
|
}
|
||||||
@@ -144,7 +145,7 @@ async function getPrefixList(prefix, limit = 50) {
|
|||||||
async function setRole(uid, role) {
|
async function setRole(uid, role) {
|
||||||
const udoc = await getById(uid);
|
const udoc = await getById(uid);
|
||||||
return await Promise.all([
|
return await Promise.all([
|
||||||
coll.findOneAndUpdate({ _id: uid }, { role }),
|
coll.findOneAndUpdate({ _id: uid }, { $set: { role } }),
|
||||||
collRole.updateOne({ _id: udoc.role }, { $inc: { count: -1 } }),
|
collRole.updateOne({ _id: udoc.role }, { $inc: { count: -1 } }),
|
||||||
collRole.updateOne({ _id: role }, { $inc: { count: 1 } }),
|
collRole.updateOne({ _id: role }, { $inc: { count: 1 } }),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ let options = {
|
|||||||
CONTEST_PER_PAGE: 20,
|
CONTEST_PER_PAGE: 20,
|
||||||
TRAINING_PER_PAGE: 10,
|
TRAINING_PER_PAGE: 10,
|
||||||
DISCUSSION_PER_PAGE: 50,
|
DISCUSSION_PER_PAGE: 50,
|
||||||
|
REPLY_PER_PAGE: 50,
|
||||||
CONTESTS_ON_MAIN: 5,
|
CONTESTS_ON_MAIN: 5,
|
||||||
TRAININGS_ON_MAIN: 5,
|
TRAININGS_ON_MAIN: 5,
|
||||||
DISCUSSIONS_ON_MAIN: 20,
|
DISCUSSIONS_ON_MAIN: 20,
|
||||||
|
|||||||
@@ -113,7 +113,6 @@ class Handler {
|
|||||||
|
|
||||||
back(body) {
|
back(body) {
|
||||||
if (body) this.response.body = body;
|
if (body) this.response.body = body;
|
||||||
else if (this.preferJson) this.response.body = {};
|
|
||||||
this.response.redirect = this.request.headers.referer || '/';
|
this.response.redirect = this.request.headers.referer || '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,6 +128,7 @@ class Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async ___prepare() {
|
async ___prepare() {
|
||||||
|
this.response.body = {};
|
||||||
this.now = new Date();
|
this.now = new Date();
|
||||||
this._handler.sid = this.request.cookies.get('sid');
|
this._handler.sid = this.request.cookies.get('sid');
|
||||||
this._handler.save = this.request.cookies.get('save');
|
this._handler.save = this.request.cookies.get('save');
|
||||||
@@ -241,7 +241,7 @@ class Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const check = ['tid', 'rid', 'did', 'drid', 'drrid', 'psid', 'psrid'];
|
const check = ['tid', 'rid', 'did', 'drid', 'drrid', 'psid', 'psrid', 'docId'];
|
||||||
|
|
||||||
function Route(route, RouteHandler) {
|
function Route(route, RouteHandler) {
|
||||||
router.all(route, async (ctx) => {
|
router.all(route, async (ctx) => {
|
||||||
|
|||||||
+3
-4
@@ -401,8 +401,7 @@ Continue: 继续
|
|||||||
Role: 角色
|
Role: 角色
|
||||||
Select a role: 选择一个角色
|
Select a role: 选择一个角色
|
||||||
Add User: 添加用户
|
Add User: 添加用户
|
||||||
Add User to Domain: 添加用户到域
|
Remove Selected User: 将所选用户移出
|
||||||
Remove Selected User from Domain: 将所选用户移出域
|
|
||||||
Set Roles for Selected User: 设置所选用户的角色
|
Set Roles for Selected User: 设置所选用户的角色
|
||||||
Create Role: 创建角色
|
Create Role: 创建角色
|
||||||
Role name can only contains numbers, letters and underscores.: 角色名称只能包含数字、字母和下划线。
|
Role name can only contains numbers, letters and underscores.: 角色名称只能包含数字、字母和下划线。
|
||||||
@@ -511,8 +510,8 @@ You can create your own training plans and share with others.: 您可以创建
|
|||||||
Set Role: 设置角色
|
Set Role: 设置角色
|
||||||
Set Roles for selected users: 为所选用户设置角色
|
Set Roles for selected users: 为所选用户设置角色
|
||||||
Please select at least one user to perform this operation.: 请选择至少一个用户来进行操作。
|
Please select at least one user to perform this operation.: 请选择至少一个用户来进行操作。
|
||||||
Confirm removing the selected users from this domain?: 您确定将所选用户从此域中移除吗?
|
Confirm removing the selected users?: 您确定将所选用户移除吗?
|
||||||
Their account will not be deleted and they will be with the default role when visiting this domain.: 他们的账号不会被删除,并且之后将以 default 角色访问此域。
|
Their account will not be deleted and they will be with the default role.: 他们的账号不会被删除,并且之后将以 default 角色访问。
|
||||||
Selected users have been removed from the domain.: 所选用户已从此域中移除。
|
Selected users have been removed from the domain.: 所选用户已从此域中移除。
|
||||||
Role has been updated to {0} for selected users.: 所选用户角色已更新为 {0}。
|
Role has been updated to {0} for selected users.: 所选用户角色已更新为 {0}。
|
||||||
Role has been updated to {0}.: 角色已更新为 {0}。
|
Role has been updated to {0}.: 角色已更新为 {0}。
|
||||||
|
|||||||
+3
-4
@@ -387,8 +387,7 @@ User ID: 使用者 ID
|
|||||||
Role: 角色
|
Role: 角色
|
||||||
Select a role: 選擇一個角色
|
Select a role: 選擇一個角色
|
||||||
Add User: 新增使用者
|
Add User: 新增使用者
|
||||||
Add User to Domain: 新增使用者到域
|
Remove Selected User: 將所選使用者移出
|
||||||
Remove Selected User from Domain: 將所選使用者移出域
|
|
||||||
Set Roles for Selected User: 設定所選使用者的角色
|
Set Roles for Selected User: 設定所選使用者的角色
|
||||||
Create Role: 創建角色
|
Create Role: 創建角色
|
||||||
Role name can only contains numbers, letters and underscores.: 角色名稱只能包含數字、字母和下劃線。
|
Role name can only contains numbers, letters and underscores.: 角色名稱只能包含數字、字母和下劃線。
|
||||||
@@ -497,8 +496,8 @@ no_translation_warn: <blockquote class="warn">這部分內容正在翻譯。</bl
|
|||||||
Set Role: 設定角色
|
Set Role: 設定角色
|
||||||
Set Roles for selected users: 為所選使用者設定角色
|
Set Roles for selected users: 為所選使用者設定角色
|
||||||
Please select at least one user to perform this operation.: 請選擇至少一個使用者來進行操作。
|
Please select at least one user to perform this operation.: 請選擇至少一個使用者來進行操作。
|
||||||
Confirm removing the selected users from this domain?: 您確定將所選使用者從此域中移除嗎?
|
Confirm removing the selected users?: 您確定將所選使用者移除嗎?
|
||||||
Their account will not be deleted and they will be with the default role when visiting this domain.: 他們的賬號不會被刪除,並且之後將以 default 角色訪問此域。
|
Their account will not be deleted and they will be with the default role.: 他們的賬號不會被刪除,並且之後將以 default 角色訪問。
|
||||||
Selected users have been removed from the domain.: 所選使用者已從此域中移除。
|
Selected users have been removed from the domain.: 所選使用者已從此域中移除。
|
||||||
Role has been updated to {0} for selected users.: 所選使用者角色已更新為 {0}。
|
Role has been updated to {0} for selected users.: 所選使用者角色已更新為 {0}。
|
||||||
Role has been updated to {0}.: 角色已更新為 {0}。
|
Role has been updated to {0}.: 角色已更新為 {0}。
|
||||||
|
|||||||
@@ -46,8 +46,5 @@
|
|||||||
"locales/*",
|
"locales/*",
|
||||||
"templates/*"
|
"templates/*"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"judger": "hydro/development.js"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
{{ form_attr('select', args) }}
|
{{ form_attr('select', args) }}
|
||||||
>
|
>
|
||||||
{% for k, v in args.options %}
|
{% for k, v in args.options %}
|
||||||
<option value="{{ k }}"{% if value == k %} selected{% endif %}>
|
<option value="{{ k }}"{% if args.value == k %} selected{% endif %}>
|
||||||
{{ _(v) }}
|
{{ _(v) }}
|
||||||
</option>
|
</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
{% set page_name = "discussion_create" %}
|
||||||
{% extends "layout/basic.html" %}
|
{% extends "layout/basic.html" %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="medium-9 columns">
|
<div class="medium-9 columns">
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<div class="section__header">
|
<div class="section__header">
|
||||||
<h1 class="section__title">{{ _('Create Discussion in {0}').format(title) }}</h1>
|
<h1 class="section__title">{{ _('Create Discussion in {0}').format(vnode.title) }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="section__body">
|
<div class="section__body">
|
||||||
<form method="post">
|
<form method="post">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
{% set page_name = "discussion_detail" %}
|
||||||
{% extends "layout/basic.html" %}
|
{% extends "layout/basic.html" %}
|
||||||
{% import "components/comments.html" as comments with context %}
|
{% import "components/comments_discussion.html" as comments with context %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="medium-9 columns">
|
<div class="medium-9 columns">
|
||||||
@@ -68,7 +69,7 @@
|
|||||||
comment_delete_perm = perm.PERM_LOGGEDIN if ddoc.owner == handler.user._id else perm.PERM_DELETE_DISCUSSION_REPLY,
|
comment_delete_perm = perm.PERM_LOGGEDIN if ddoc.owner == handler.user._id else perm.PERM_DELETE_DISCUSSION_REPLY,
|
||||||
reply_post_perm = perm.PERM_REPLY_DISCUSSION,
|
reply_post_perm = perm.PERM_REPLY_DISCUSSION,
|
||||||
reply_edit_perm = perm.PERM_LOGGEDIN if ddoc.owner == handler.user._id else perm.PERM_EDIT_DISCUSSION_REPLY,
|
reply_edit_perm = perm.PERM_LOGGEDIN if ddoc.owner == handler.user._id else perm.PERM_EDIT_DISCUSSION_REPLY,
|
||||||
reply_delete_perm = perm.PERM_LOGGEDIN if ddoc.owner == handler.user._id else perm.PERM_DELETE_DISCUSSION_REPLY,
|
reply_delete_perm = perm.PERM_LOGGEDIN if ddoc.owner == handler.user._id else perm.PERM_DELETE_DISCUSSION_REPLY
|
||||||
) }}
|
) }}
|
||||||
{{ paginator.render(page, pcount) }}
|
{{ paginator.render(page, pcount) }}
|
||||||
{% if drcount == 0 %}
|
{% if drcount == 0 %}
|
||||||
@@ -80,7 +81,7 @@
|
|||||||
<div class="medium-3 columns">
|
<div class="medium-3 columns">
|
||||||
{% set udoc = udict[ddoc['owner']] %}
|
{% set udoc = udict[ddoc['owner']] %}
|
||||||
<div class="section side">
|
<div class="section side">
|
||||||
<div class="profile__bg user-profile-bg--{{ vj4.model.adaptor.setting.UserSetting(udoc).get_setting('background_img') }}"></div>
|
<div class="profile__bg user-profile-bg--1"></div>
|
||||||
<div class="section__body">
|
<div class="section__body">
|
||||||
<div class="media sidebar-user-profile">
|
<div class="media sidebar-user-profile">
|
||||||
<div class="media__left">
|
<div class="media__left">
|
||||||
|
|||||||
@@ -48,35 +48,20 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for role in roles %}
|
{% for role in roles %}
|
||||||
{% if role._id not in ['default', 'guest', 'root'] %}
|
{% set isBuiltin = role._id not in ['default', 'guest', 'root'] %}
|
||||||
<tr data-role="{{ role._id }}">
|
<tr{% if isBuiltin %} data-role="{{ role._id }}"{% endif %}>
|
||||||
<td class="col--checkbox">
|
<td class="col--checkbox">
|
||||||
<label class="compact checkbox">
|
<label class="compact checkbox">
|
||||||
<input type="checkbox" data-checkbox-group="role" data-checkbox-range>
|
<input type="checkbox" data-checkbox-group="role" {{ "data-checkbox-range" if isBuiltin else "disabled" }}>
|
||||||
</label>
|
</label>
|
||||||
</td>
|
</td>
|
||||||
<td class="col--id">
|
<td class="col--id">
|
||||||
{{ _('User-defined role') }}: {{ role._id }}
|
{{ _('Built-in') if isBuiltin else _('User-defined role') }}: {{ role._id }}
|
||||||
</td>
|
|
||||||
<td class="col--users">
|
|
||||||
{{ role.count }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% else %}
|
|
||||||
<tr>
|
|
||||||
<td class="col--checkbox">
|
|
||||||
<label class="compact checkbox">
|
|
||||||
<input type="checkbox" data-checkbox-group="role" disabled>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td class="col--id">
|
|
||||||
{{ _('Built-in') }}: {{ role._id }}
|
|
||||||
</td>
|
</td>
|
||||||
<td class="col--users">
|
<td class="col--users">
|
||||||
{{ role.count|default('--') }}
|
{{ role.count|default('--') }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
<div class="section__header">
|
<div class="section__header">
|
||||||
<h1 class="section__title">{{ _('{0}: Users').format(system.uname) }}</h1>
|
<h1 class="section__title">{{ _('{0}: Users').format(system.uname) }}</h1>
|
||||||
<div class="section__tools">
|
<div class="section__tools">
|
||||||
<button class="primary rounded button" name="add_user">{{ _('Add User to Domain') }}</button>
|
<button class="primary rounded button" name="add_user">{{ _('Add User') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ noscript_note.render() }}
|
{{ noscript_note.render() }}
|
||||||
@@ -71,13 +71,12 @@
|
|||||||
</th>
|
</th>
|
||||||
<th class="col--uid">{{ _('User ID') }}</th>
|
<th class="col--uid">{{ _('User ID') }}</th>
|
||||||
<th class="col--user">{{ _('Username') }}</th>
|
<th class="col--user">{{ _('Username') }}</th>
|
||||||
<th class="col--user">{{ _('Display Name') }}</th>
|
|
||||||
<th class="col--role">{{ _('Role') }}</th>
|
<th class="col--role">{{ _('Role') }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for role in roles %}
|
{% for role in roles %}
|
||||||
{% for rudoc in rudocs[role] %}
|
{% for rudoc in rudocs[role._id] %}
|
||||||
{% set is_disabled=(rudoc._id == handler.user._id) %}
|
{% set is_disabled=(rudoc._id == handler.user._id) %}
|
||||||
<tr data-uid="{{ rudoc._id }}">
|
<tr data-uid="{{ rudoc._id }}">
|
||||||
<td class="col--checkbox">
|
<td class="col--checkbox">
|
||||||
@@ -91,14 +90,11 @@
|
|||||||
<td class="col--user">
|
<td class="col--user">
|
||||||
{{ user.render_inline(udict[rudoc._id], badge=false) }}
|
{{ user.render_inline(udict[rudoc._id], badge=false) }}
|
||||||
</td>
|
</td>
|
||||||
<td class="col--name-alias">
|
|
||||||
{{ rudoc.displayName|default('') }}
|
|
||||||
</td>
|
|
||||||
<td class="col--role">
|
<td class="col--role">
|
||||||
{{ form.select({
|
{{ form.select({
|
||||||
options:rolesSelect,
|
options:rolesSelect,
|
||||||
name:'role',
|
name:'role',
|
||||||
value:rudoc['role'],
|
value:rudoc.role,
|
||||||
extra_class:'compact',
|
extra_class:'compact',
|
||||||
disabled:is_disabled
|
disabled:is_disabled
|
||||||
}) }}
|
}) }}
|
||||||
@@ -110,7 +106,7 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="section__body">
|
<div class="section__body">
|
||||||
<button class="rounded button" name="remove_selected">{{ _('Remove Selected User from Domain') }}</button>
|
<button class="rounded button" name="remove_selected">{{ _('Remove Selected User') }}</button>
|
||||||
<button class="rounded button" name="set_roles">{{ _('Set Roles for Selected User') }}</button>
|
<button class="rounded button" name="set_roles">{{ _('Set Roles for Selected User') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
<!--[if lte IE 8]>
|
<!--[if lte IE 8]>
|
||||||
<script type="text/javascript" src="{{ static_url('shim.js') }}"></script>
|
<script type="text/javascript" src="{{ static_url('shim.js') }}"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
<script type="text/javascript" src="{{ static_url('locale/{0}.js'.format(handler.user.lang)) }}"></script>
|
<script type="text/javascript" src="{{ static_url('locale/{0}.js'.format(handler.user.viewLang)) }}"></script>
|
||||||
<script type="text/javascript" src="{{ static_url('vj4.js') }}"></script>
|
<script type="text/javascript" src="{{ static_url('vj4.js') }}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
{{ form.form_checkbox({
|
{{ form.form_checkbox({
|
||||||
label:'Highlight',
|
label:'Highlight',
|
||||||
name:'highlight',
|
name:'highlight',
|
||||||
value:ddoc.highlight|default(false))
|
value:ddoc.highlight|default(false)
|
||||||
}) }}
|
}) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ form.form_text({
|
{{ form.form_text({
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<ol class="menu">
|
<ol class="menu">
|
||||||
{% if page_name == 'discussion_node' or page_name == 'discussion_detail' %}
|
{% if page_name == 'discussion_node' or page_name == 'discussion_detail' %}
|
||||||
{% if handler.hasPerm(perm.PERM_CREATE_DISCUSSION) %}
|
{% if handler.hasPerm(perm.PERM_CREATE_DISCUSSION) %}
|
||||||
<li class="menu__item"><a class="menu__link highlight" href="{{ reverse_url('discussion_create_document_as_node', doc_type=pdoc['doc_type'], doc_id=pdoc['_id']) }}">
|
<li class="menu__item"><a class="menu__link highlight" href="/discuss/problem/{{ pdoc._id }}/create">
|
||||||
<span class="icon icon-add"></span> {{ _('Create a Discussion') }}
|
<span class="icon icon-add"></span> {{ _('Create a Discussion') }}
|
||||||
</a></li>
|
</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
<li class="menu__seperator"></li>
|
<li class="menu__seperator"></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if handler.hasPerm(perm.PERM_VIEW_DISCUSSION) %}
|
{% if handler.hasPerm(perm.PERM_VIEW_DISCUSSION) %}
|
||||||
<li class="menu__item"><a class="menu__link{% if page_name == 'discussion_node' or page_name == 'discussion_detail' %} active{% endif %}" href="{{ reverse_url('discussion_node_document_as_node', doc_type=pdoc['doc_type'], doc_id=pdoc['_id']) }}">
|
<li class="menu__item"><a class="menu__link{% if page_name == 'discussion_node' or page_name == 'discussion_detail' %} active{% endif %}" href="/discuss/problem/{{ pdoc._id }}">
|
||||||
<span class="icon icon-comment--text"></span> {{ _('Discussions') }}
|
<span class="icon icon-comment--text"></span> {{ _('Discussions') }}
|
||||||
</a></li>
|
</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -89,15 +89,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="section__body typo">
|
<div class="section__body typo">
|
||||||
<dl class="large horizontal">
|
<dl class="large horizontal">
|
||||||
{% if pdoc['_id']|string|length < 10 %}
|
|
||||||
<dt>{{ _('ID') }}</dt>
|
<dt>{{ _('ID') }}</dt>
|
||||||
<dd>{{ pdoc['_id'] }}</dd>
|
<dd>{{ pdoc['pid'] }}</dd>
|
||||||
{% endif %}
|
|
||||||
{% if page_name != 'discussion_node' and page_name != 'discussion_detail' %}
|
{% if page_name != 'discussion_node' and page_name != 'discussion_detail' %}
|
||||||
{% if handler.hasPerm(perm.PERM_LOGGEDIN) %}
|
{% if handler.hasPerm(perm.PERM_LOGGEDIN) %}
|
||||||
<dt>{{ _('Submission') }}</dt>
|
<dt>{{ _('Submission') }}</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{% if pdoc['psdoc']['status'] %}
|
{% if pdoc.psdoc['status'] %}
|
||||||
<span class="icon record-status--icon {{ model.builtin.STATUS_CODES[pdoc['psdoc']['status']] }}"></span>
|
<span class="icon record-status--icon {{ model.builtin.STATUS_CODES[pdoc['psdoc']['status']] }}"></span>
|
||||||
<a href="/r/{{ pdoc['psdoc']['rid'] }}" class="record-status--text {{ model.builtin.STATUS_CODES[pdoc['psdoc']['status']] }}">
|
<a href="/r/{{ pdoc['psdoc']['rid'] }}" class="record-status--text {{ model.builtin.STATUS_CODES[pdoc['psdoc']['status']] }}">
|
||||||
{{ model.builtin.STATUS_TEXTS[pdoc['psdoc']['status']] }}
|
{{ model.builtin.STATUS_TEXTS[pdoc['psdoc']['status']] }}
|
||||||
@@ -115,7 +113,7 @@
|
|||||||
{% if pdoc['category'] %}
|
{% if pdoc['category'] %}
|
||||||
<span class="hasjs--hide" name="problem-sidebar__categories">
|
<span class="hasjs--hide" name="problem-sidebar__categories">
|
||||||
{% for category in pdoc['category'] %}
|
{% for category in pdoc['category'] %}
|
||||||
<a href="{{ reverse_url('problem_category', category=category) }}">{{ category }}</a>
|
<a href="/p?category={{ category }}">{{ category }}</a>
|
||||||
{% if loop.index < pdoc['category']|length %}
|
{% if loop.index < pdoc['category']|length %}
|
||||||
{% if category in vj4.model.builtin.PROBLEM_CATEGORIES %}
|
{% if category in vj4.model.builtin.PROBLEM_CATEGORIES %}
|
||||||
{{ _('problem-category-delim') }}
|
{{ _('problem-category-delim') }}
|
||||||
@@ -152,10 +150,8 @@
|
|||||||
<dt>{{ _('Be Copied') }}</dt>
|
<dt>{{ _('Be Copied') }}</dt>
|
||||||
<dd>{{ pdoc['num_be_copied'] }}</dd>
|
<dd>{{ pdoc['num_be_copied'] }}</dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if pdoc['owner'] != 0 %}
|
|
||||||
<dt>{{ _('Uploaded By') }}</dt>
|
<dt>{{ _('Uploaded By') }}</dt>
|
||||||
<dd>{{ user.render_inline(owner_udoc, badge=false) }}</dd>
|
<dd>{{ user.render_inline(owner_udoc, badge=false) }}</dd>
|
||||||
{% endif %}
|
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -168,7 +164,7 @@
|
|||||||
{% if tdocs %}
|
{% if tdocs %}
|
||||||
<p>{{ _('In following training plans') }}: </p>
|
<p>{{ _('In following training plans') }}: </p>
|
||||||
{% for tdoc in tdocs %}
|
{% for tdoc in tdocs %}
|
||||||
<p><a href="{{ reverse_url('training_detail', tid=tdoc._id) }}">{{ tdoc.title }}</a></p>
|
<p><a href="/t/{{ tdoc._id }}">{{ tdoc.title }}</a></p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if ctdocs %}
|
{% if ctdocs %}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ function renderItem(user) {
|
|||||||
return tpl`
|
return tpl`
|
||||||
<div class="media">
|
<div class="media">
|
||||||
<div class="media__left medium">
|
<div class="media__left medium">
|
||||||
<img class="small user-profile-avatar" src="${user.gravatar}" width="30" height="30">
|
<img class="small user-profile-avatar" src="${user.gravatar_url}" width="30" height="30">
|
||||||
</div>
|
</div>
|
||||||
<div class="media__body medium">
|
<div class="media__body medium">
|
||||||
<div class="user-select__uname">${user.uname}</div>
|
<div class="user-select__uname">${user.uname}</div>
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ const page = new NamedPage('domain_manage_user', () => {
|
|||||||
const role = addUserDialog.$dom.find('[name="role"]').val();
|
const role = addUserDialog.$dom.find('[name="role"]').val();
|
||||||
try {
|
try {
|
||||||
await request.post('', {
|
await request.post('', {
|
||||||
operation: 'add_user',
|
operation: 'set_user',
|
||||||
uid: user._id,
|
uid: user._id,
|
||||||
role,
|
role,
|
||||||
});
|
});
|
||||||
@@ -90,8 +90,8 @@ const page = new NamedPage('domain_manage_user', () => {
|
|||||||
const action = await new ConfirmDialog({
|
const action = await new ConfirmDialog({
|
||||||
$body: tpl`
|
$body: tpl`
|
||||||
<div class="typo">
|
<div class="typo">
|
||||||
<p>${i18n('Confirm removing the selected users from this domain?')}</p>
|
<p>${i18n('Confirm removing the selected users?')}</p>
|
||||||
<p>${i18n('Their account will not be deleted and they will be with the default role when visiting this domain.')}</p>
|
<p>${i18n('Their account will not be deleted and they will be with the default role.')}</p>
|
||||||
</div>`,
|
</div>`,
|
||||||
}).open();
|
}).open();
|
||||||
if (action !== 'yes') {
|
if (action !== 'yes') {
|
||||||
|
|||||||
Reference in new issue
Block a user