Browse Source

Add user privilege manage

pull/6/head
Menci 8 years ago
parent
commit
1187b90093
  1. 4
      models/judge_state.js
  2. 14
      models/problem.js
  3. 48
      models/user.js
  4. 58
      models/user_privilege.js
  5. 12
      modules/problem.js
  6. 4
      modules/problem_tag.js
  7. 26
      modules/user.js
  8. 2
      views/problem.ejs
  9. 2
      views/problem_edit.ejs
  10. 2
      views/problems.ejs
  11. 2
      views/submission_content.ejs
  12. 51
      views/user_edit.ejs

4
models/judge_state.js

@ -102,7 +102,7 @@ class JudgeState extends Model {
async isAllowedSeeResultBy(user) {
await this.loadRelationships();
if (user && (user.is_admin || user.id === this.problem.user_id)) return true;
if (user && (await user.hasPrivilege('manage_problem') || user.id === this.problem.user_id)) return true;
else if (this.type === 0) return true;
else if (this.type === 1) {
let contest = await Contest.fromID(this.type_info);
@ -117,7 +117,7 @@ class JudgeState extends Model {
async isAllowedSeeCodeBy(user) {
await this.loadRelationships();
if (user && (user.is_admin || user.id === this.problem.user_id)) return true;
if (user && (await user.hasPrivilege('manage_problem') || user.id === this.problem.user_id)) return true;
else if (this.type === 0) return this.problem.is_public;
else if (this.type === 1) {
let contest = await Contest.fromID(this.type_info);

14
models/problem.js

@ -234,11 +234,21 @@ class Problem extends Model {
}
async isAllowedEditBy(user) {
return user && (user.is_admin || this.user_id === user.id);
if (!user) return false;
if (await user.hasPrivilege('manage_problem')) return true;
return this.user_id === user.id;
}
async isAllowedUseBy(user) {
return this.is_public || (user && (user.is_admin || this.user_id === user.id));
if (!user) return false;
if (await user.hasPrivilege('manage_problem')) return true;
return this.is_public || this.user_id === user.id;
}
async isAllowedManageBy(user) {
if (!user) return false;
if (await user.hasPrivilege('manage_problem')) return true;
return user.is_admin;
}
async updateTestdata(path) {

48
models/user.js

@ -82,6 +82,8 @@ class User extends Model {
}
async isAllowedEditBy(user) {
if (!user) return false;
if (await user.hasPrivilege('manage_user')) return true;
return user && (user.is_admin || this.id === user.id);
}
@ -179,6 +181,52 @@ class User extends Model {
this.information = await syzoj.utils.markdown(this.information);
}
async getPrivileges() {
let UserPrivilege = syzoj.model('user_privilege');
let privileges = await UserPrivilege.query(null, {
user_id: this.id
});
return privileges.map(x => x.privilege);
}
async setPrivileges(newPrivileges) {
let UserPrivilege = syzoj.model('user_privilege');
let oldPrivileges = await this.getPrivileges();
console.log(newPrivileges);
let delPrivileges = oldPrivileges.filter(x => !newPrivileges.includes(x));
let addPrivileges = newPrivileges.filter(x => !oldPrivileges.includes(x));
for (let privilege of delPrivileges) {
let obj = await UserPrivilege.findOne({ where: {
user_id: this.id,
privilege: privilege
} });
await obj.destroy();
}
for (let privilege of addPrivileges) {
let obj = await UserPrivilege.create({
user_id: this.id,
privilege: privilege
});
await obj.save();
}
}
async hasPrivilege(privilege) {
if (this.is_admin) return true;
let UserPrivilege = syzoj.model('user_privilege');
let x = await UserPrivilege.findOne({ where: { user_id: this.id, privilege: privilege } });
return !(!x);
}
getModel() { return model; }
}

58
models/user_privilege.js

@ -0,0 +1,58 @@
/*
* This file is part of SYZOJ.
*
* Copyright (c) 2016 Menci <huanghaorui301@gmail.com>
*
* SYZOJ is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* SYZOJ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with SYZOJ. If not, see <http://www.gnu.org/licenses/>.
*/
'use strict';
let Sequelize = require('sequelize');
let db = syzoj.db;
let model = db.define('user_privilege', {
user_id: { type: Sequelize.INTEGER, primaryKey: true },
privilege: {
type: Sequelize.STRING,
primaryKey: true
}
}, {
timestamps: false,
tableName: 'user_privilege',
indexes: [
{
fields: ['user_id']
},
{
fields: ['privilege']
}
]
});
let Model = require('./common');
class UserPrivilege extends Model {
static async create(val) {
return UserPrivilege.fromRecord(UserPrivilege.model.build(Object.assign({
user_id: 0,
privilege: ''
}, val)));
}
getModel() { return model; }
}
UserPrivilege.model = model;
module.exports = UserPrivilege;

12
modules/problem.js

@ -38,6 +38,7 @@ app.get('/problems', async (req, res) => {
});
res.render('problems', {
allowedManageTag: res.locals.user && await res.locals.user.hasPrivilege('manage_problem_tag'),
problems: problems,
paginate: paginate
});
@ -72,6 +73,7 @@ app.get('/problems/search', async (req, res) => {
});
res.render('problems', {
allowedManageTag: res.locals.user && await res.locals.user.hasPrivilege('manage_problem_tag'),
problems: problems,
paginate: paginate
});
@ -114,6 +116,7 @@ app.get('/problems/tag/:tagIDs', async (req, res) => {
});
res.render('problems', {
allowedManageTag: res.locals.user && await res.locals.user.hasPrivilege('manage_problem_tag'),
problems: problems,
tags: tags,
paginate: paginate
@ -137,6 +140,7 @@ app.get('/problem/:id', async (req, res) => {
}
problem.allowedEdit = await problem.isAllowedEditBy(res.locals.user);
problem.allowedManage = await problem.isAllowedManageBy(res.locals.user);
if (problem.is_public || problem.allowedEdit) {
await syzoj.utils.markdown(problem, [ 'description', 'input_format', 'output_format', 'example', 'limit_and_hint' ]);
@ -210,6 +214,8 @@ app.get('/problem/:id/edit', async (req, res) => {
problem.tags = await problem.getTags();
}
problem.allowedManage = await problem.isAllowedManageBy(res.locals.user);
res.render('problem_edit', {
problem: problem
});
@ -241,7 +247,7 @@ app.post('/problem/:id/edit', async (req, res) => {
if (!await problem.isAllowedUseBy(res.locals.user)) throw new ErrorMessage('您没有权限进行此操作。');
if (!await problem.isAllowedEditBy(res.locals.user)) throw new ErrorMessage('您没有权限进行此操作。');
if (res.locals.user.is_admin) {
if (await res.locals.user.hasPrivilege('manage_problem')) {
let customID = parseInt(req.body.id);
if (customID && customID !== id) {
if (await Problem.fromID(customID)) throw new ErrorMessage('ID 已被使用。');
@ -442,8 +448,8 @@ async function setPublic(req, res, is_public) {
let problem = await Problem.fromID(id);
if (!problem) throw new ErrorMessage('无此题目。');
let allowedEdit = await problem.isAllowedEditBy(res.locals.user);
if (!allowedEdit) throw new ErrorMessage('您没有权限进行此操作。');
let allowedManage = await problem.isAllowedManageBy(res.locals.user);
if (!allowedManage) throw new ErrorMessage('您没有权限进行此操作。');
problem.is_public = is_public;
await problem.save();

4
modules/problem_tag.js

@ -23,7 +23,7 @@ let ProblemTag = syzoj.model('problem_tag');
app.get('/problems/tag/:id/edit', async (req, res) => {
try {
if (!res.locals.user && !res.locals.user.is_admin) throw new ErrorMessage('您没有权限进行此操作。');
if (!res.locals.user || !await res.locals.user.hasPrivilege('manage_problem_tag')) throw new ErrorMessage('您没有权限进行此操作。');
let id = parseInt(req.params.id) || 0;
let tag = await ProblemTag.fromID(id);
@ -46,7 +46,7 @@ app.get('/problems/tag/:id/edit', async (req, res) => {
app.post('/problems/tag/:id/edit', async (req, res) => {
try {
if (!res.locals.user || !res.locals.user.is_admin) throw new ErrorMessage('您没有权限进行此操作。');
if (!res.locals.user || !await res.locals.user.hasPrivilege('manage_problem_tag')) throw new ErrorMessage('您没有权限进行此操作。');
let id = parseInt(req.params.id) || 0;
let tag = await ProblemTag.fromID(id);

26
modules/user.js

@ -117,6 +117,10 @@ app.get('/user/:id/edit', async (req, res) => {
throw new ErrorMessage('您没有权限进行此操作。');
}
user.privileges = await user.getPrivileges();
res.locals.user.allowedManage = await res.locals.user.hasPrivilege('manage_user');
res.render('user_edit', {
edited_user: user,
error_info: null
@ -139,15 +143,26 @@ app.post('/user/:id/edit', async (req, res) => {
if (!allowedEdit) throw new ErrorMessage('您没有权限进行此操作。');
if (req.body.old_password && req.body.new_password) {
if (user.password !== req.body.old_password && !res.locals.user.is_admin) throw new ErrorMessage('旧密码错误。');
if (user.password !== req.body.old_password && !await res.locals.user.hasPrivilege('manage_user')) throw new ErrorMessage('旧密码错误。');
user.password = req.body.new_password;
}
if (res.locals.user.is_admin) {
if (res.locals.user && await res.locals.user.hasPrivilege('manage_user')) {
if (!syzoj.utils.isValidUsername(req.body.username)) throw new ErrorMessage('无效的用户名。');
user.username = req.body.username;
}
if (res.locals.user && res.locals.user.is_admin) {
if (!req.body.privileges) {
req.body.privileges = [];
} else if (!Array.isArray(req.body.privileges)) {
req.body.privileges = [req.body.privileges];
}
let privileges = req.body.privileges;
await user.setPrivileges(privileges);
}
user.email = req.body.email;
user.information = req.body.information;
user.sex = req.body.sex;
@ -156,11 +171,18 @@ app.post('/user/:id/edit', async (req, res) => {
if (user.id === res.locals.user.id) res.locals.user = user;
user.privileges = await user.getPrivileges();
res.locals.user.allowedManage = await res.locals.user.hasPrivilege('manage_user');
res.render('user_edit', {
edited_user: user,
error_info: ''
});
} catch (e) {
console.log(e);
user.privileges = await user.getPrivileges();
res.locals.user.allowedManage = await res.locals.user.hasPrivilege('manage_user');
res.render('user_edit', {
edited_user: user,
error_info: e.message

2
views/problem.ejs

@ -66,7 +66,7 @@ if (contest) {
<a class="small ui button" href="<%= syzoj.utils.makeUrl(['problem', problem.id, 'edit']) %>">编辑</a>
<a class="small ui button" href="<%= syzoj.utils.makeUrl(['problem', problem.id, 'data']) %>">管理测试数据</a>
<% } %>
<% if (user && user.is_admin) { %>
<% if (problem.allowedManage) { %>
<% if (problem.is_public) { %>
<a class="small ui button" id="dis_public" href="<%= syzoj.utils.makeUrl(['problem', problem.id, 'dis_public']) %>">取消公开</a>
<% } else { %>

2
views/problem_edit.ejs

@ -13,7 +13,7 @@
</div>
<div class="ui bottom attached tab segment active" data-tab="edit">
<div class="field">
<% if (problem.new || user.is_admin) { %>
<% if (problem.new || problem.allowedManage) { %>
<label for="id">
<% if (problem.new) { %>
题目编号

2
views/problems.ejs

@ -62,7 +62,7 @@ if (typeof tags !== 'undefined') tagIDs = tags.map(x => x.id);
<label>显示分类标签</label>
</div>
<div style="margin-left: 10px; display: inline-block; ">
<% if (user && user.is_admin) { %>
<% if (allowedManageTag) { %>
<% if (typeof tags !== 'undefined' && tags.length === 1) { %>
<a style="margin-left: 10px; " href="<%= syzoj.utils.makeUrl(['problems', 'tag', tags[0].id, 'edit']) %>" class="ui labeled icon mini blue button"><i class="write icon"></i> 编辑标签</a>
<% } %>

2
views/submission_content.ejs

@ -98,7 +98,7 @@ else problemUrl = syzoj.utils.makeUrl(['problem', judge.problem_id]);
<% } else if (judge.result.spj_compiler_output) { %>
<h3 class="ui header">Special Judge 编译信息</h3>
<div class="ui existing segment"><pre style="margin-top: 0; margin-bottom: 0; "><code><%- syzoj.utils.ansiToHTML(judge.result.spj_compiler_output) %></code></pre></div>
<% } else if (judge.allowedSeeResult) { %>
<% } else if (judge.allowedSeeResult && judge.result.subtasks && (judge.result.subtasks.length !== 1 || judge.result.subtasks[0].case_num)) { %>
<div class="ui styled fluid accordion" id="subtasks_list">
<% let subtask_count = 0; %>
<% for (let subtask_cases of (judge.result.subtasks || [])) { %>

51
views/user_edit.ejs

@ -8,10 +8,10 @@
<p id="error_info"><%= error_info %></p>
<% } %>
</div>
<form class="ui form" action="<%= syzoj.utils.makeUrl(['user', edited_user.id, 'edit']) %>" method="post" onsubmit="return check()">
<form id="form" class="ui form" action="<%= syzoj.utils.makeUrl(['user', edited_user.id, 'edit']) %>" method="post" onsubmit="return check()">
<div class="field">
<label for="username">用户名</label>
<input type="text" id="username" name="username" value="<%= edited_user.username %>"<% if (!user.is_admin) { %> readonly<% } %>>
<input type="text" id="username" name="username" value="<%= edited_user.username %>"<% if (!user.allowedManage) { %> readonly<% } %>>
</div>
<div class="field">
<label for="sex">性别</label>
@ -30,7 +30,7 @@
<textarea class="font-content" rows="5" id="information" name="information"><%= edited_user.information %></textarea>
</div>
<div class="field">
<label class="ui header">修改密码</label>
<label class="ui header">密码</label>
<input type="password" placeholder="原密码(留空则不修改)" name="old_password" id="old_password">
</div>
<div class="two fields" id="new_password_field">
@ -41,8 +41,32 @@
<input type="password" placeholder="确认密码" id="password2">
</div>
</div>
<button type="submit" class="ui button">修改</button>
<a href="<%= syzoj.utils.makeUrl(['user', edited_user.id]) %>" class="ui blue button">返回个人资料</a>
<%
let allowedManagePrivilege = user && user.is_admin;
%>
<div class="inline field">
<label class="ui header">权限</label>
<div class="ui toggle disabled checkbox" style="margin-right: 20px; ">
<input disabled="disabled" type="checkbox" <% if (edited_user.is_admin) { %> checked<% } %>>
<label>全站管理员</label>
</div>
<div class="ui toggle <% if (!allowedManagePrivilege) { %>disabled <% } %>checkbox checkbox_privilege" data-name="manage_problem" style="margin-right: 20px; ">
<input <% if (!allowedManagePrivilege) { %>disabled="disabled" <% } %>type="checkbox"<% if (edited_user.privileges.includes('manage_problem')) { %> checked<% } %>>
<label>管理题目</label>
</div>
<div class="ui toggle <% if (!allowedManagePrivilege) { %>disabled <% } %>checkbox checkbox_privilege" data-name="manage_problem_tag" style="margin-right: 20px; ">
<input <% if (!allowedManagePrivilege) { %>disabled="disabled" <% } %>type="checkbox"<% if (edited_user.privileges.includes('manage_problem_tag')) { %> checked<% } %>>
<label>管理题目标签</label>
</div>
<div class="ui toggle <% if (!allowedManagePrivilege) { %>disabled <% } %>checkbox checkbox_privilege" data-name="manage_user">
<input <% if (!allowedManagePrivilege) { %>disabled="disabled" <% } %>type="checkbox"<% if (edited_user.privileges.includes('manage_user')) { %> checked<% } %>>
<label>管理用户</label>
</div>
</div>
<div style="text-align: center; ">
<button type="submit" class="ui button">修改</button>
<a href="<%= syzoj.utils.makeUrl(['user', edited_user.id]) %>" class="ui blue button">返回个人资料</a>
</div>
</form>
</div>
</div>
@ -61,13 +85,28 @@ function check() {
$("#error").removeClass("success");
$("#error").removeClass("error");
$("#error").addClass("error");
$("#error_info").html("两次输入的密码不一致");
$("#error_info").html("两次输入的密码不一致");
$("#error").show();
return false;
}
make_md5(old_password);
make_md5(password1);
make_md5(password2);
<% if (allowedManagePrivilege) { %>
$('.checkbox_privilege').each(function () {
if ($(this).checkbox('is checked')) {
var name = $(this).data('name');
var elem = document.createElement('input');
elem.type = 'hidden';
elem.value = name;
elem.name = 'privileges';
document.getElementById('form').appendChild(elem);
}
});
<% } %>
return true;
}
</script>

Loading…
Cancel
Save