Skip to content

Commit c0bc75d

Browse files
committed
frontend work
1 parent 2dccaa7 commit c0bc75d

File tree

7 files changed

+199
-0
lines changed

7 files changed

+199
-0
lines changed

app/models/user.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export default class User extends Model {
1414
@attr avatar;
1515
@attr url;
1616
@attr kind;
17+
@attr admin;
1718

1819
async stats() {
1920
return await customAction(this, { method: 'GET', path: 'stats' });

app/router.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ Router.map(function () {
3030
this.route('following');
3131
this.route('pending-invites');
3232
});
33+
this.route('admin', function () {
34+
this.route('rate-limits');
35+
});
3336
this.route('settings', function () {
3437
this.route('appearance');
3538
this.route('email-notifications');

app/routes/admin/index.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { inject as service } from '@ember/service';
2+
3+
import AuthenticatedRoute from './../-authenticated-route';
4+
5+
export default class AdminRoute extends AuthenticatedRoute {
6+
@service router;
7+
@service session;
8+
9+
async beforeModel(transition) {
10+
// wait for the `loadUserTask.perform()` of either the `application` route,
11+
// or the `session.login()` call
12+
let result = await this.session.loadUserTask.last;
13+
14+
if (!result.currentUser) {
15+
this.session.savedTransition = transition;
16+
this.router.replaceWith('catch-all', {
17+
transition,
18+
loginNeeded: true,
19+
title: 'This page requires admin authentication',
20+
});
21+
} else if (!result.currentUser.admin) {
22+
this.session.savedTransition = transition;
23+
this.router.replaceWith('catch-all', {
24+
transition,
25+
loginNeeded: false,
26+
title: 'This page requires admin authentication',
27+
});
28+
}
29+
}
30+
31+
redirect() {
32+
this.router.replaceWith('admin.rate-limits');
33+
}
34+
}

app/routes/admin/rate-limits.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { inject as service } from '@ember/service';
2+
3+
import AuthenticatedRoute from './../-authenticated-route';
4+
5+
export default class RateLimitsAdminRoute extends AuthenticatedRoute {
6+
@service router;
7+
@service session;
8+
9+
async beforeModel(transition) {
10+
// wait for the `loadUserTask.perform()` of either the `application` route,
11+
// or the `session.login()` call
12+
let result = await this.session.loadUserTask.last;
13+
14+
if (!result.currentUser) {
15+
this.session.savedTransition = transition;
16+
this.router.replaceWith('catch-all', {
17+
transition,
18+
loginNeeded: true,
19+
title: 'This page requires admin authentication',
20+
});
21+
} else if (!result.currentUser.admin) {
22+
this.session.savedTransition = transition;
23+
this.router.replaceWith('catch-all', {
24+
transition,
25+
loginNeeded: false,
26+
title: 'This page requires admin authentication',
27+
});
28+
}
29+
}
30+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
.rate-limit {}
2+
3+
.page {
4+
display: grid;
5+
gap: 16px;
6+
7+
@media (--min-m) {
8+
grid-template:
9+
"menu content" auto /
10+
200px auto;
11+
}
12+
}
13+
14+
.content {
15+
h2:first-child {
16+
margin-top: 4px;
17+
}
18+
}

app/templates/admin/rate-limits.hbs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{{page-title 'Admin Actions'}}
2+
3+
<PageHeader @title="Admin Actions" data-test-heading />
4+
5+
<div local-class="page" ...attributes>
6+
<SideMenu as |menu|>
7+
<menu.Item @link={{link "admin.rate-limits"}}>Increase Rate Limit</menu.Item>
8+
<menu.Item>More actions coming soon</menu.Item>
9+
</SideMenu>
10+
11+
<div local-class="content">
12+
<div local-class='rate-limit'>
13+
<h2>Increase Rate Limit</h2>
14+
<label>email address:</label>
15+
</div>
16+
</div>
17+
18+
</div>

tests/acceptance/admin-test.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { currentURL } from '@ember/test-helpers';
2+
import { module, test } from 'qunit';
3+
4+
import { setupApplicationTest } from 'cargo/tests/helpers';
5+
6+
import { visit } from '../helpers/visit-ignoring-abort';
7+
8+
module('Acceptance | Admin', function (hooks) {
9+
setupApplicationTest(hooks);
10+
11+
test('shows "page requires admin authentication" error when not logged in', async function (assert) {
12+
await visit('/admin');
13+
assert.equal(currentURL(), '/admin');
14+
assert.dom('[data-test-title]').hasText('This page requires admin authentication');
15+
assert.dom('[data-test-login]').exists();
16+
});
17+
18+
test('shows "page requires admin authentication" error when logged in but not as an admin', async function (assert) {
19+
let user = this.server.create('user', {
20+
login: 'johnnydee',
21+
name: 'John Doe',
22+
email: 'john@doe.com',
23+
avatar: 'https://avatars2.githubusercontent.com/u/1234567?v=4',
24+
admin: false,
25+
});
26+
27+
this.authenticateAs(user);
28+
29+
await visit('/admin');
30+
assert.equal(currentURL(), '/admin');
31+
assert.dom('[data-test-title]').hasText('This page requires admin authentication');
32+
assert.dom('[data-test-login]').doesNotExist();
33+
});
34+
35+
test('shows admin actions when logged in as an admin', async function (assert) {
36+
let user = this.server.create('user', {
37+
login: 'johnnydee',
38+
name: 'John Doe',
39+
email: 'john@doe.com',
40+
avatar: 'https://avatars2.githubusercontent.com/u/1234567?v=4',
41+
admin: true,
42+
});
43+
44+
this.authenticateAs(user);
45+
46+
await visit('/admin');
47+
// Rate limits is the default action.
48+
assert.equal(currentURL(), '/admin/rate-limits');
49+
assert.dom('[data-test-heading]').hasText('Admin Actions');
50+
assert.dom('[data-test-login]').doesNotExist();
51+
});
52+
53+
module('Rate limits', function () {
54+
test('shows "page requires admin authentication" error when not logged in', async function (assert) {
55+
await visit('/admin/rate-limits');
56+
assert.equal(currentURL(), '/admin/rate-limits');
57+
assert.dom('[data-test-title]').hasText('This page requires admin authentication');
58+
assert.dom('[data-test-login]').exists();
59+
});
60+
61+
test('shows "page requires admin authentication" error when logged in but not as an admin', async function (assert) {
62+
let user = this.server.create('user', {
63+
login: 'johnnydee',
64+
name: 'John Doe',
65+
email: 'john@doe.com',
66+
avatar: 'https://avatars2.githubusercontent.com/u/1234567?v=4',
67+
admin: false,
68+
});
69+
70+
this.authenticateAs(user);
71+
72+
await visit('/admin/rate-limits');
73+
assert.equal(currentURL(), '/admin/rate-limits');
74+
assert.dom('[data-test-title]').hasText('This page requires admin authentication');
75+
assert.dom('[data-test-login]').doesNotExist();
76+
});
77+
});
78+
79+
test('shows rate limit actions when logged in as an admin', async function (assert) {
80+
let user = this.server.create('user', {
81+
login: 'johnnydee',
82+
name: 'John Doe',
83+
email: 'john@doe.com',
84+
avatar: 'https://avatars2.githubusercontent.com/u/1234567?v=4',
85+
admin: true,
86+
});
87+
88+
this.authenticateAs(user);
89+
90+
await visit('/admin/rate-limits');
91+
assert.equal(currentURL(), '/admin/rate-limits');
92+
assert.dom('[data-test-heading]').hasText('Admin Actions');
93+
assert.dom('[data-test-login]').doesNotExist();
94+
});
95+
});

0 commit comments

Comments
 (0)