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

Commit

Permalink
feat(articles): Article Admin feature
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mleanos committed Feb 13, 2016
1 parent a069531 commit 32f373c
Show file tree
Hide file tree
Showing 19 changed files with 927 additions and 432 deletions.
2 changes: 2 additions & 0 deletions modules/articles/client/articles.client.module.js
Expand Up @@ -2,6 +2,8 @@
'use strict';

app.registerModule('articles');
app.registerModule('articles.admin', ['core.admin']);
app.registerModule('articles.admin.routes', ['core.admin.routes']);
app.registerModule('articles.services');
app.registerModule('articles.routes', ['ui.router', 'articles.services']);
})(ApplicationConfiguration);
17 changes: 17 additions & 0 deletions modules/articles/client/config/articles-admin.client.config.js
@@ -0,0 +1,17 @@
(function () {
'use strict';

// Configuring the Articles Admin module
angular
.module('articles.admin')
.run(menuConfig);

menuConfig.$inject = ['Menus'];

function menuConfig(Menus) {
Menus.addSubMenuItem('topbar', 'admin', {
title: 'Manage Articles',
state: 'admin.articles.list'
});
}
})();
65 changes: 65 additions & 0 deletions modules/articles/client/config/articles-admin.client.routes.js
@@ -0,0 +1,65 @@
(function () {
'use strict';

angular
.module('articles.admin.routes')
.config(routeConfig);

routeConfig.$inject = ['$stateProvider'];

function routeConfig($stateProvider) {
$stateProvider
.state('admin.articles', {
abstract: true,
url: '/articles',
template: '<ui-view/>'
})
.state('admin.articles.list', {
url: '',
templateUrl: 'modules/articles/client/views/admin/list-articles.client.view.html',
controller: 'ArticlesListController',
controllerAs: 'vm',
data: {
roles: ['admin']
}
})
.state('admin.articles.create', {
url: '/create',
templateUrl: 'modules/articles/client/views/admin/form-article.client.view.html',
controller: 'ArticlesController',
controllerAs: 'vm',
data: {
roles: ['admin']
},
resolve: {
articleResolve: newArticle
}
})
.state('admin.articles.edit', {
url: '/:articleId/edit',
templateUrl: 'modules/articles/client/views/admin/form-article.client.view.html',
controller: 'ArticlesController',
controllerAs: 'vm',
data: {
roles: ['admin']
},
resolve: {
articleResolve: getArticle
}
});
}

getArticle.$inject = ['$stateParams', 'ArticlesService'];

function getArticle($stateParams, ArticlesService) {
return ArticlesService.get({
articleId: $stateParams.articleId
}).$promise;
}

newArticle.$inject = ['ArticlesService'];

function newArticle(ArticlesService) {
return new ArticlesService();
}
})();
10 changes: 2 additions & 8 deletions modules/articles/client/config/articles.client.config.js
Expand Up @@ -18,14 +18,8 @@
// Add the dropdown list item
Menus.addSubMenuItem('topbar', 'articles', {
title: 'List Articles',
state: 'articles.list'
});

// Add the dropdown create item
Menus.addSubMenuItem('topbar', 'articles', {
title: 'Create Article',
state: 'articles.create',
roles: ['user']
state: 'articles.list',
roles: ['*']
});
}
})();
32 changes: 0 additions & 32 deletions modules/articles/client/config/articles.client.routes.js
Expand Up @@ -23,32 +23,6 @@
pageTitle: 'Articles List'
}
})
.state('articles.create', {
url: '/create',
templateUrl: 'modules/articles/client/views/form-article.client.view.html',
controller: 'ArticlesController',
controllerAs: 'vm',
resolve: {
articleResolve: newArticle
},
data: {
roles: ['user', 'admin'],
pageTitle : 'Articles Create'
}
})
.state('articles.edit', {
url: '/:articleId/edit',
templateUrl: 'modules/articles/client/views/form-article.client.view.html',
controller: 'ArticlesController',
controllerAs: 'vm',
resolve: {
articleResolve: getArticle
},
data: {
roles: ['user', 'admin'],
pageTitle: 'Edit Article {{ articleResolve.title }}'
}
})
.state('articles.view', {
url: '/:articleId',
templateUrl: 'modules/articles/client/views/view-article.client.view.html',
Expand All @@ -70,10 +44,4 @@
articleId: $stateParams.articleId
}).$promise;
}

newArticle.$inject = ['ArticlesService'];

function newArticle(ArticlesService) {
return new ArticlesService();
}
})();
@@ -0,0 +1,50 @@
(function () {
'use strict';

angular
.module('articles.admin')
.controller('ArticlesController', ArticlesController);

ArticlesController.$inject = ['$scope', '$state', 'articleResolve', 'Authentication'];

function ArticlesController($scope, $state, article, Authentication) {
var vm = this;

vm.article = article;
vm.authentication = Authentication;
vm.error = null;
vm.form = {};
vm.remove = remove;
vm.save = save;

// Remove existing Article
function remove() {
if (confirm('Are you sure you want to delete?')) {
vm.article.$remove($state.go('admin.articles.list'));
}
}

// Save Article
function save(isValid) {
if (!isValid) {
$scope.$broadcast('show-errors-check-validity', 'vm.form.articleForm');
return false;
}

// TODO: move create/update logic to service
if (vm.article._id) {
vm.article.$update(successCallback, errorCallback);
} else {
vm.article.$save(successCallback, errorCallback);
}

function successCallback(res) {
$state.go('admin.articles.list'); // should we send the User to the list or the updated Article's view?
}

function errorCallback(res) {
vm.error = res.data.message;
}
}
}
})();
@@ -0,0 +1,15 @@
(function () {
'use strict';

angular
.module('articles')
.controller('ArticlesListController', ArticlesListController);

ArticlesListController.$inject = ['ArticlesService'];

function ArticlesListController(ArticlesService) {
var vm = this;

vm.articles = ArticlesService.query();
}
})();
Expand Up @@ -2,6 +2,11 @@
<div class="page-header">
<h1>{{vm.article._id ? 'Edit Article' : 'New Article'}}</h1>
</div>
<div class="pull-right">
<a class="btn btn-primary" ng-click="vm.remove()">
<i class="glyphicon glyphicon-trash"></i>
</a>
</div>
<div class="col-md-12">
<form name="vm.form.articleForm" class="form-horizontal" ng-submit="vm.save(vm.form.articleForm.$valid)" novalidate>
<fieldset>
Expand Down
26 changes: 26 additions & 0 deletions modules/articles/client/views/admin/list-articles.client.view.html
@@ -0,0 +1,26 @@
<section>
<div class="page-header">
<h1>
Articles
<a class="btn btn-primary pull-right" data-ui-sref="admin.articles.create">
<i class="glyphicon glyphicon-plus"></i>
</a>
</h1>
</div>
<div class="list-group">
<a data-ng-repeat="article in vm.articles" data-ui-sref="admin.articles.edit({articleId: article._id})" class="list-group-item">
<small class="list-group-item-text">
Posted on
<span data-ng-bind="article.created | date:'mediumDate'"></span>
by
<span ng-if="article.user" ng-bind="article.user.displayName"></span>
<span ng-if="!article.user">Deleted User</span>
</small>
<h4 class="list-group-item-heading" data-ng-bind="article.title"></h4>
<p class="list-group-item-text" data-ng-bind="article.content"></p>
</a>
</div>
<div class="alert alert-warning text-center" data-ng-if="articles.$resolved && !articles.length">
No articles yet, why don't you <a data-ui-sref="admin.articles.create">create one</a>?
</div>
</section>
3 changes: 0 additions & 3 deletions modules/articles/client/views/list-articles.client.view.html
Expand Up @@ -15,7 +15,4 @@ <h4 class="list-group-item-heading" ng-bind="article.title"></h4>
<p class="list-group-item-text" ng-bind="article.content"></p>
</a>
</div>
<div class="alert alert-warning text-center" ng-if="vm.articles.$resolved && !vm.articles.length">
No articles yet, why don't you <a ui-sref="articles.create">create one</a>?
</div>
</section>
8 changes: 0 additions & 8 deletions modules/articles/client/views/view-article.client.view.html
Expand Up @@ -2,14 +2,6 @@
<div class="page-header">
<h1 ng-bind="vm.article.title"></h1>
</div>
<div class="pull-right" ng-show="vm.article.isCurrentUserOwner">
<a class="btn btn-primary" ui-sref="articles.edit({ articleId: vm.article._id })">
<i class="glyphicon glyphicon-edit"></i>
</a>
<a class="btn btn-primary" ng-click="vm.remove()">
<i class="glyphicon glyphicon-trash"></i>
</a>
</div>
<small>
<em class="text-muted">
Posted on
Expand Down
2 changes: 1 addition & 1 deletion modules/articles/server/policies/articles.server.policy.js
Expand Up @@ -25,7 +25,7 @@ exports.invokeRolesPolicies = function () {
roles: ['user'],
allows: [{
resources: '/api/articles',
permissions: ['get', 'post']
permissions: ['get']
}, {
resources: '/api/articles/:articleId',
permissions: ['get']
Expand Down

0 comments on commit 32f373c

Please sign in to comment.