Skip to content
This repository was archived by the owner on Aug 30, 2021. It is now read-only.

Commit 89075cb

Browse files
authored
feat(articles): Article Admin feature (#807)
This feature introduces a breaking change, that restricts the User's that can create/edit/delete Articles to only those that have the `admin` Role. Fixed ESLint issues. Resolved merge conflicts, and moved new client Article Service `createOrUpdate` functionality to new Admin feature controller. Removed edit functionality from client-side Article controller.
1 parent 5817a48 commit 89075cb

20 files changed

+913
-469
lines changed

modules/articles/client/articles.client.module.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
'use strict';
33

44
app.registerModule('articles', ['core']);// The core module is required for special route handling; see /core/client/config/core.client.routes
5+
app.registerModule('articles.admin', ['core.admin']);
6+
app.registerModule('articles.admin.routes', ['core.admin.routes']);
57
app.registerModule('articles.services');
68
app.registerModule('articles.routes', ['ui.router', 'core.routes', 'articles.services']);
79
}(ApplicationConfiguration));
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
(function () {
2+
'use strict';
3+
4+
// Configuring the Articles Admin module
5+
angular
6+
.module('articles.admin')
7+
.run(menuConfig);
8+
9+
menuConfig.$inject = ['menuService'];
10+
11+
function menuConfig(Menus) {
12+
Menus.addSubMenuItem('topbar', 'admin', {
13+
title: 'Manage Articles',
14+
state: 'admin.articles.list'
15+
});
16+
}
17+
}());
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
(function () {
2+
'use strict';
3+
4+
angular
5+
.module('articles.admin.routes')
6+
.config(routeConfig);
7+
8+
routeConfig.$inject = ['$stateProvider'];
9+
10+
function routeConfig($stateProvider) {
11+
$stateProvider
12+
.state('admin.articles', {
13+
abstract: true,
14+
url: '/articles',
15+
template: '<ui-view/>'
16+
})
17+
.state('admin.articles.list', {
18+
url: '',
19+
templateUrl: 'modules/articles/client/views/admin/list-articles.client.view.html',
20+
controller: 'ArticlesListController',
21+
controllerAs: 'vm',
22+
data: {
23+
roles: ['admin']
24+
}
25+
})
26+
.state('admin.articles.create', {
27+
url: '/create',
28+
templateUrl: 'modules/articles/client/views/admin/form-article.client.view.html',
29+
controller: 'ArticlesController',
30+
controllerAs: 'vm',
31+
data: {
32+
roles: ['admin']
33+
},
34+
resolve: {
35+
articleResolve: newArticle
36+
}
37+
})
38+
.state('admin.articles.edit', {
39+
url: '/:articleId/edit',
40+
templateUrl: 'modules/articles/client/views/admin/form-article.client.view.html',
41+
controller: 'ArticlesController',
42+
controllerAs: 'vm',
43+
data: {
44+
roles: ['admin']
45+
},
46+
resolve: {
47+
articleResolve: getArticle
48+
}
49+
});
50+
}
51+
52+
getArticle.$inject = ['$stateParams', 'ArticlesService'];
53+
54+
function getArticle($stateParams, ArticlesService) {
55+
return ArticlesService.get({
56+
articleId: $stateParams.articleId
57+
}).$promise;
58+
}
59+
60+
newArticle.$inject = ['ArticlesService'];
61+
62+
function newArticle(ArticlesService) {
63+
return new ArticlesService();
64+
}
65+
}());

modules/articles/client/config/articles.client.menus.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,8 @@
1818
// Add the dropdown list item
1919
menuService.addSubMenuItem('topbar', 'articles', {
2020
title: 'List Articles',
21-
state: 'articles.list'
22-
});
23-
24-
// Add the dropdown create item
25-
menuService.addSubMenuItem('topbar', 'articles', {
26-
title: 'Create Article',
27-
state: 'articles.create',
28-
roles: ['user']
21+
state: 'articles.list',
22+
roles: ['*']
2923
});
3024
}
3125
}());

modules/articles/client/config/articles.client.routes.js

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,32 +23,6 @@
2323
pageTitle: 'Articles List'
2424
}
2525
})
26-
.state('articles.create', {
27-
url: '/create',
28-
templateUrl: 'modules/articles/client/views/form-article.client.view.html',
29-
controller: 'ArticlesController',
30-
controllerAs: 'vm',
31-
resolve: {
32-
articleResolve: newArticle
33-
},
34-
data: {
35-
roles: ['user', 'admin'],
36-
pageTitle: 'Articles Create'
37-
}
38-
})
39-
.state('articles.edit', {
40-
url: '/:articleId/edit',
41-
templateUrl: 'modules/articles/client/views/form-article.client.view.html',
42-
controller: 'ArticlesController',
43-
controllerAs: 'vm',
44-
resolve: {
45-
articleResolve: getArticle
46-
},
47-
data: {
48-
roles: ['user', 'admin'],
49-
pageTitle: 'Edit Article {{ articleResolve.title }}'
50-
}
51-
})
5226
.state('articles.view', {
5327
url: '/:articleId',
5428
templateUrl: 'modules/articles/client/views/view-article.client.view.html',
@@ -70,10 +44,4 @@
7044
articleId: $stateParams.articleId
7145
}).$promise;
7246
}
73-
74-
newArticle.$inject = ['ArticlesService'];
75-
76-
function newArticle(ArticlesService) {
77-
return new ArticlesService();
78-
}
7947
}());
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
(function () {
2+
'use strict';
3+
4+
angular
5+
.module('articles.admin')
6+
.controller('ArticlesController', ArticlesController);
7+
8+
ArticlesController.$inject = ['$scope', '$state', '$window', 'articleResolve', 'Authentication'];
9+
10+
function ArticlesController($scope, $state, $window, article, Authentication) {
11+
var vm = this;
12+
13+
vm.article = article;
14+
vm.authentication = Authentication;
15+
vm.error = null;
16+
vm.form = {};
17+
vm.remove = remove;
18+
vm.save = save;
19+
20+
// Remove existing Article
21+
function remove() {
22+
if ($window.confirm('Are you sure you want to delete?')) {
23+
vm.article.$remove($state.go('admin.articles.list'));
24+
}
25+
}
26+
27+
// Save Article
28+
function save(isValid) {
29+
if (!isValid) {
30+
$scope.$broadcast('show-errors-check-validity', 'vm.form.articleForm');
31+
return false;
32+
}
33+
34+
// Create a new article, or update the current instance
35+
vm.article.createOrUpdate()
36+
.then(successCallback)
37+
.catch(errorCallback);
38+
39+
function successCallback(res) {
40+
$state.go('admin.articles.list'); // should we send the User to the list or the updated Article's view?
41+
}
42+
43+
function errorCallback(res) {
44+
vm.error = res.data.message;
45+
}
46+
}
47+
}
48+
}());
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
(function () {
2+
'use strict';
3+
4+
angular
5+
.module('articles')
6+
.controller('ArticlesListController', ArticlesListController);
7+
8+
ArticlesListController.$inject = ['ArticlesService'];
9+
10+
function ArticlesListController(ArticlesService) {
11+
var vm = this;
12+
13+
vm.articles = ArticlesService.query();
14+
}
15+
}());

modules/articles/client/controllers/articles.client.controller.js

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,14 @@
55
.module('articles')
66
.controller('ArticlesController', ArticlesController);
77

8-
ArticlesController.$inject = ['$scope', '$state', 'articleResolve', '$window', 'Authentication'];
8+
ArticlesController.$inject = ['$scope', 'articleResolve', 'Authentication'];
99

10-
function ArticlesController($scope, $state, article, $window, Authentication) {
10+
function ArticlesController($scope, article, Authentication) {
1111
var vm = this;
1212

1313
vm.article = article;
1414
vm.authentication = Authentication;
1515
vm.error = null;
16-
vm.form = {};
17-
vm.remove = remove;
18-
vm.save = save;
1916

20-
// Remove existing Article
21-
function remove() {
22-
if ($window.confirm('Are you sure you want to delete?')) {
23-
vm.article.$remove($state.go('articles.list'));
24-
}
25-
}
26-
27-
// Save Article
28-
function save(isValid) {
29-
if (!isValid) {
30-
$scope.$broadcast('show-errors-check-validity', 'vm.form.articleForm');
31-
return false;
32-
}
33-
34-
// Create a new article, or update the current instance
35-
vm.article.createOrUpdate()
36-
.then(successCallback)
37-
.catch(errorCallback);
38-
39-
function successCallback(res) {
40-
$state.go('articles.view', {
41-
articleId: res._id
42-
});
43-
}
44-
45-
function errorCallback(res) {
46-
vm.error = res.data.message;
47-
}
48-
}
4917
}
5018
}());

modules/articles/client/views/form-article.client.view.html renamed to modules/articles/client/views/admin/form-article.client.view.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
<div class="page-header">
33
<h1>{{vm.article._id ? 'Edit Article' : 'New Article'}}</h1>
44
</div>
5+
<div class="pull-right">
6+
<a class="btn btn-primary" ng-click="vm.remove()">
7+
<i class="glyphicon glyphicon-trash"></i>
8+
</a>
9+
</div>
510
<div class="col-md-12">
611
<form name="vm.form.articleForm" class="form-horizontal" ng-submit="vm.save(vm.form.articleForm.$valid)" novalidate>
712
<fieldset>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<section>
2+
<div class="page-header">
3+
<h1>
4+
Articles
5+
<a class="btn btn-primary pull-right" data-ui-sref="admin.articles.create">
6+
<i class="glyphicon glyphicon-plus"></i>
7+
</a>
8+
</h1>
9+
</div>
10+
<div class="list-group">
11+
<a data-ng-repeat="article in vm.articles" data-ui-sref="admin.articles.edit({articleId: article._id})" class="list-group-item">
12+
<small class="list-group-item-text">
13+
Posted on
14+
<span data-ng-bind="article.created | date:'mediumDate'"></span>
15+
by
16+
<span ng-if="article.user" ng-bind="article.user.displayName"></span>
17+
<span ng-if="!article.user">Deleted User</span>
18+
</small>
19+
<h4 class="list-group-item-heading" data-ng-bind="article.title"></h4>
20+
<p class="list-group-item-text" data-ng-bind="article.content"></p>
21+
</a>
22+
</div>
23+
<div class="alert alert-warning text-center" data-ng-if="articles.$resolved && !articles.length">
24+
No articles yet, why don't you <a data-ui-sref="admin.articles.create">create one</a>?
25+
</div>
26+
</section>

modules/articles/client/views/list-articles.client.view.html

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,4 @@ <h4 class="list-group-item-heading" ng-bind="article.title"></h4>
1515
<p class="list-group-item-text" ng-bind="article.content"></p>
1616
</a>
1717
</div>
18-
<div class="alert alert-warning text-center" ng-if="vm.articles.$resolved && !vm.articles.length">
19-
No articles yet, why don't you <a ui-sref="articles.create">create one</a>?
20-
</div>
2118
</section>

modules/articles/client/views/view-article.client.view.html

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,6 @@
22
<div class="page-header">
33
<h1 ng-bind="vm.article.title"></h1>
44
</div>
5-
<div class="pull-right" ng-show="vm.article.isCurrentUserOwner">
6-
<a class="btn btn-primary" ui-sref="articles.edit({ articleId: vm.article._id })">
7-
<i class="glyphicon glyphicon-edit"></i>
8-
</a>
9-
<a class="btn btn-primary" ng-click="vm.remove()">
10-
<i class="glyphicon glyphicon-trash"></i>
11-
</a>
12-
</div>
135
<small>
146
<em class="text-muted">
157
Posted on

modules/articles/server/policies/articles.server.policy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ exports.invokeRolesPolicies = function () {
2525
roles: ['user'],
2626
allows: [{
2727
resources: '/api/articles',
28-
permissions: ['get', 'post']
28+
permissions: ['get']
2929
}, {
3030
resources: '/api/articles/:articleId',
3131
permissions: ['get']

0 commit comments

Comments
 (0)