Accept admin API tokens for batch review and admin task updates
Batch review (including skipPeerReview) and POST /api/admin/tasks/:id required a browser session. Admin API tokens may now call them; other roles still need a password login.
This commit is contained in:
parent
91c799f7d3
commit
57ea62ef8c
3 changed files with 33 additions and 2 deletions
|
|
@ -1057,7 +1057,8 @@ export function createApp(ctx) {
|
|||
|
||||
// One click for a whole batch: every function of it that waits for a human.
|
||||
router.on('POST', '/api/batches/:id/review', async ({ req, params }) => {
|
||||
const user = auth(req, { role: 'reviewer', session: true });
|
||||
const user = auth(req, { role: 'reviewer' });
|
||||
if (user.via !== 'session' && !hasRole(user, 'admin')) throw new HttpError(403, 'this action needs a password login in the browser; only admin API tokens can do it');
|
||||
const body = await readJson(req, 16 * 1024);
|
||||
const attemptIds = Array.isArray(body.attemptIds) ? body.attemptIds.map((x) => intParam(x)) : null;
|
||||
const r = merger.reviewBatch(user, intParam(params.id), String(body.action ?? ''), body.comment ? String(body.comment) : null, { attemptIds, skipPeerReview: body.skipPeerReview === true });
|
||||
|
|
@ -1077,7 +1078,8 @@ export function createApp(ctx) {
|
|||
// --- maintainers and admins (browser session only)
|
||||
|
||||
router.on('POST', '/api/admin/tasks/:id', async ({ req, params }) => {
|
||||
auth(req, { role: 'maintainer', session: true });
|
||||
const user = auth(req, { role: 'maintainer' });
|
||||
if (user.via !== 'session' && !hasRole(user, 'admin')) throw new HttpError(403, 'this action needs a password login in the browser; only admin API tokens can do it');
|
||||
const body = await readJson(req, 4096);
|
||||
const t = tasks.get(intParam(params.id));
|
||||
if (body.priority !== undefined) store.run('UPDATE tasks SET priority = ? WHERE id = ?', Number(body.priority) | 0, t.id);
|
||||
|
|
|
|||
|
|
@ -115,6 +115,22 @@ test('admin batch self-review leaves peer review alone unless explicitly skipped
|
|||
assert.deepEqual(skipped.body.results, [{ attemptId: pending, state: 'approved' }]);
|
||||
});
|
||||
|
||||
test('batch review accepts admin API tokens but not tokens of other roles', async (t) => {
|
||||
const { store, accounts, user, attempt, post } = await fixture(t);
|
||||
const admin = user('admin');
|
||||
const maintainer = user('maintainer');
|
||||
const author = user('contributor');
|
||||
const batch = Number(store.run(`INSERT INTO batches (user_id, base_commit, files_json, state, created_at) VALUES (?, 'base', '{}', 'open', ?)`, author.id, now()).lastInsertRowid);
|
||||
const pending = attempt(author, 'peer_review', batch);
|
||||
const maintainerToken = accounts.createApiToken(maintainer.id, 'agent').token;
|
||||
assert.equal((await post(`/api/batches/${batch}/review`, { action: 'approve', skipPeerReview: true }, { token: maintainerToken })).status, 403);
|
||||
assert.equal(store.get('SELECT state FROM attempts WHERE id = ?', pending).state, 'peer_review');
|
||||
const adminToken = accounts.createApiToken(admin.id, 'agent').token;
|
||||
const result = await post(`/api/batches/${batch}/review`, { action: 'approve', attemptIds: [pending], skipPeerReview: true }, { token: adminToken });
|
||||
assert.equal(result.status, 200, JSON.stringify(result.body));
|
||||
assert.deepEqual(result.body.results, [{ attemptId: pending, state: 'approved' }]);
|
||||
});
|
||||
|
||||
test('identical resubmissions retain an explicit review waiver without inventing peer votes', async (t) => {
|
||||
const { store, user, attempt, post } = await fixture(t);
|
||||
const admin = user('admin');
|
||||
|
|
|
|||
|
|
@ -1389,6 +1389,19 @@ test('admin: a done task is reopened only with force, and then as open', async (
|
|||
ctx.store.run(`UPDATE tasks SET state = 'done' WHERE id = ?`, done.id);
|
||||
});
|
||||
|
||||
test('admin: task reopen accepts admin API tokens but not maintainer tokens', async () => {
|
||||
await ctx.accounts.createUser('rvadmintok', 'admin', PASSWORD);
|
||||
await ctx.accounts.createUser('rvmainttok', 'maintainer', PASSWORD);
|
||||
const done = ctx.store.get(`SELECT id FROM tasks WHERE state = 'done' LIMIT 1`);
|
||||
const maintToken = ctx.accounts.createApiToken(ctx.accounts.byName('rvmainttok').id, 'agent').token;
|
||||
assert.equal((await request('POST', `/api/admin/tasks/${done.id}`, { state: 'open', force: true }, { token: maintToken })).status, 403);
|
||||
assert.equal(ctx.store.get('SELECT state FROM tasks WHERE id = ?', done.id).state, 'done');
|
||||
const adminToken = ctx.accounts.createApiToken(ctx.accounts.byName('rvadmintok').id, 'agent').token;
|
||||
const forced = await request('POST', `/api/admin/tasks/${done.id}`, { state: 'open', force: true }, { token: adminToken });
|
||||
assert.equal(forced.body.state, 'open');
|
||||
ctx.store.run(`UPDATE tasks SET state = 'done' WHERE id = ?`, done.id);
|
||||
});
|
||||
|
||||
test('maintenance batches: maintainers only; merge when no compiled code changes, back otherwise', async () => {
|
||||
const contributor = await activeUser('mtcontrib');
|
||||
const maintainer = await activeUser('mtmaint', 'maintainer');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue