mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 22:43:30 +03:00
✨ Contributor Role (#948)
refs https://github.com/TryGhost/Ghost/issues/9314 * added save button for contributor * hide tag filter & redirect to posts.index if post is published * update editor controller test to need session service
This commit is contained in:
parent
f0501e8997
commit
13ceee3e9f
@ -81,6 +81,7 @@ export default Controller.extend({
|
|||||||
notifications: service(),
|
notifications: service(),
|
||||||
router: service(),
|
router: service(),
|
||||||
slugGenerator: service(),
|
slugGenerator: service(),
|
||||||
|
session: service(),
|
||||||
ui: service(),
|
ui: service(),
|
||||||
|
|
||||||
/* public properties -----------------------------------------------------*/
|
/* public properties -----------------------------------------------------*/
|
||||||
|
@ -58,7 +58,7 @@ export default Controller.extend({
|
|||||||
deleteUserActionIsVisible: computed('currentUser', 'canAssignRoles', 'user', function () {
|
deleteUserActionIsVisible: computed('currentUser', 'canAssignRoles', 'user', function () {
|
||||||
if ((this.get('canAssignRoles') && this.get('isNotOwnProfile') && !this.get('user.isOwner'))
|
if ((this.get('canAssignRoles') && this.get('isNotOwnProfile') && !this.get('user.isOwner'))
|
||||||
|| (this.get('currentUser.isEditor') && (this.get('isNotOwnProfile')
|
|| (this.get('currentUser.isEditor') && (this.get('isNotOwnProfile')
|
||||||
|| this.get('user.isAuthor')))) {
|
|| this.get('user.isAuthorOrContributor')))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
@ -3,7 +3,7 @@ import Mixin from '@ember/object/mixin';
|
|||||||
export default Mixin.create({
|
export default Mixin.create({
|
||||||
transitionAuthor() {
|
transitionAuthor() {
|
||||||
return (user) => {
|
return (user) => {
|
||||||
if (user.get('isAuthor')) {
|
if (user.get('isAuthorOrContributor')) {
|
||||||
return this.transitionTo('team.user', user);
|
return this.transitionTo('team.user', user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import Model from 'ember-data/model';
|
|||||||
import ValidationEngine from 'ghost-admin/mixins/validation-engine';
|
import ValidationEngine from 'ghost-admin/mixins/validation-engine';
|
||||||
import attr from 'ember-data/attr';
|
import attr from 'ember-data/attr';
|
||||||
import {computed} from '@ember/object';
|
import {computed} from '@ember/object';
|
||||||
import {equal} from '@ember/object/computed';
|
import {equal, or} from '@ember/object/computed';
|
||||||
import {hasMany} from 'ember-data/relationships';
|
import {hasMany} from 'ember-data/relationships';
|
||||||
import {inject as service} from '@ember/service';
|
import {inject as service} from '@ember/service';
|
||||||
import {task} from 'ember-concurrency';
|
import {task} from 'ember-concurrency';
|
||||||
@ -46,11 +46,15 @@ export default Model.extend(ValidationEngine, {
|
|||||||
|
|
||||||
// TODO: Once client-side permissions are in place,
|
// TODO: Once client-side permissions are in place,
|
||||||
// remove the hard role check.
|
// remove the hard role check.
|
||||||
|
isContributor: equal('role.name', 'Contributor'),
|
||||||
isAuthor: equal('role.name', 'Author'),
|
isAuthor: equal('role.name', 'Author'),
|
||||||
isEditor: equal('role.name', 'Editor'),
|
isEditor: equal('role.name', 'Editor'),
|
||||||
isAdmin: equal('role.name', 'Administrator'),
|
isAdmin: equal('role.name', 'Administrator'),
|
||||||
isOwner: equal('role.name', 'Owner'),
|
isOwner: equal('role.name', 'Owner'),
|
||||||
|
|
||||||
|
// This is used in enough places that it's useful to throw it here
|
||||||
|
isAuthorOrContributor: or('isAuthor', 'isContributor'),
|
||||||
|
|
||||||
isLoggedIn: computed('id', 'session.user.id', function () {
|
isLoggedIn: computed('id', 'session.user.id', function () {
|
||||||
return this.get('id') === this.get('session.user.id');
|
return this.get('id') === this.get('session.user.id');
|
||||||
}),
|
}),
|
||||||
|
@ -119,7 +119,7 @@ export default Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
|
|||||||
loadServerNotifications(isDelayed) {
|
loadServerNotifications(isDelayed) {
|
||||||
if (this.get('session.isAuthenticated')) {
|
if (this.get('session.isAuthenticated')) {
|
||||||
this.get('session.user').then((user) => {
|
this.get('session.user').then((user) => {
|
||||||
if (!user.get('isAuthor') && !user.get('isEditor')) {
|
if (!user.get('isAuthorOrContributor') && !user.get('isEditor')) {
|
||||||
this.store.findAll('notification', {reload: true}).then((serverNotifications) => {
|
this.store.findAll('notification', {reload: true}).then((serverNotifications) => {
|
||||||
serverNotifications.forEach((notification) => {
|
serverNotifications.forEach((notification) => {
|
||||||
if (notification.get('top') || notification.get('custom')) {
|
if (notification.get('top') || notification.get('custom')) {
|
||||||
|
@ -20,7 +20,12 @@ export default AuthenticatedRoute.extend({
|
|||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
return this.get('session.user').then((user) => {
|
return this.get('session.user').then((user) => {
|
||||||
if (user.get('isAuthor') && !post.isAuthoredByUser(user)) {
|
if (user.get('isAuthorOrContributor') && !post.isAuthoredByUser(user)) {
|
||||||
|
return this.replaceWith('posts.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the post is not a draft and user is contributor, redirect to index
|
||||||
|
if (user.get('isContributor') && !post.get('isDraft')) {
|
||||||
return this.replaceWith('posts.index');
|
return this.replaceWith('posts.index');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -45,6 +45,10 @@ export default AuthenticatedRoute.extend(InfinityRoute, {
|
|||||||
if (user.get('isAuthor')) {
|
if (user.get('isAuthor')) {
|
||||||
// authors can only view their own posts
|
// authors can only view their own posts
|
||||||
filterParams.author = user.get('slug');
|
filterParams.author = user.get('slug');
|
||||||
|
} else if (user.get('isContributor')) {
|
||||||
|
// Contributors can only view their own draft posts
|
||||||
|
filterParams.author = user.get('slug');
|
||||||
|
queryParams.status = 'draft';
|
||||||
} else if (params.author) {
|
} else if (params.author) {
|
||||||
filterParams.author = params.author;
|
filterParams.author = params.author;
|
||||||
}
|
}
|
||||||
@ -78,7 +82,7 @@ export default AuthenticatedRoute.extend(InfinityRoute, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.get('session.user').then((user) => {
|
this.get('session.user').then((user) => {
|
||||||
if (!user.get('isAuthor') && !controller._hasLoadedAuthors) {
|
if (!user.get('isAuthorOrContributor') && !controller._hasLoadedAuthors) {
|
||||||
this.get('store').query('user', {limit: 'all'}).then(() => {
|
this.get('store').query('user', {limit: 'all'}).then(() => {
|
||||||
controller._hasLoadedAuthors = true;
|
controller._hasLoadedAuthors = true;
|
||||||
});
|
});
|
||||||
|
@ -29,7 +29,7 @@ export default AuthenticatedRoute.extend(styleBody, CurrentUserSettings, Infinit
|
|||||||
};
|
};
|
||||||
|
|
||||||
// authors do not have permission to hit the invites or suspended users endpoint
|
// authors do not have permission to hit the invites or suspended users endpoint
|
||||||
if (!user.get('isAuthor')) {
|
if (!user.get('isAuthorOrContributor')) {
|
||||||
modelPromises.invites = this.store.query('invite', {limit: 'all'})
|
modelPromises.invites = this.store.query('invite', {limit: 'all'})
|
||||||
.then(() => this.store.filter('invite', invite => !invite.get('isNew')));
|
.then(() => this.store.filter('invite', invite => !invite.get('isNew')));
|
||||||
|
|
||||||
|
@ -17,12 +17,12 @@ export default AuthenticatedRoute.extend(styleBody, CurrentUserSettings, {
|
|||||||
|
|
||||||
return this.get('session.user').then((currentUser) => {
|
return this.get('session.user').then((currentUser) => {
|
||||||
let isOwnProfile = user.get('id') === currentUser.get('id');
|
let isOwnProfile = user.get('id') === currentUser.get('id');
|
||||||
let isAuthor = currentUser.get('isAuthor');
|
let isAuthorOrContributor = currentUser.get('isAuthorOrContributor');
|
||||||
let isEditor = currentUser.get('isEditor');
|
let isEditor = currentUser.get('isEditor');
|
||||||
|
|
||||||
if (isAuthor && !isOwnProfile) {
|
if (isAuthorOrContributor && !isOwnProfile) {
|
||||||
this.transitionTo('team.user', currentUser);
|
this.transitionTo('team.user', currentUser);
|
||||||
} else if (isEditor && !isOwnProfile && !user.get('isAuthor')) {
|
} else if (isEditor && !isOwnProfile && !user.get('isAuthorOrContributor')) {
|
||||||
this.transitionTo('team');
|
this.transitionTo('team');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -55,6 +55,11 @@
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contributor-save-button {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
.post-settings {
|
.post-settings {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
@ -65,10 +65,12 @@
|
|||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{#unless session.user.isContributor}}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="tag-input">Tags</label>
|
<label for="tag-input">Tags</label>
|
||||||
{{gh-psm-tags-input post=post triggerId="tag-input"}}
|
{{gh-psm-tags-input post=post triggerId="tag-input"}}
|
||||||
</div>
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
|
||||||
{{#gh-form-group errors=post.errors hasValidated=post.hasValidated property="customExcerpt"}}
|
{{#gh-form-group errors=post.errors hasValidated=post.hasValidated property="customExcerpt"}}
|
||||||
<label for="custom-excerpt">Excerpt</label>
|
<label for="custom-excerpt">Excerpt</label>
|
||||||
@ -83,7 +85,7 @@
|
|||||||
{{gh-error-message errors=post.errors property="customExcerpt" data-test-error="custom-excerpt"}}
|
{{gh-error-message errors=post.errors property="customExcerpt" data-test-error="custom-excerpt"}}
|
||||||
{{/gh-form-group}}
|
{{/gh-form-group}}
|
||||||
|
|
||||||
{{#unless session.user.isAuthor}}
|
{{#unless session.user.isAuthorOrContributor}}
|
||||||
<div class="form-group for-select">
|
<div class="form-group for-select">
|
||||||
<label for="author-list">Author</label>
|
<label for="author-list">Author</label>
|
||||||
<span class="gh-input-icon gh-icon-user">
|
<span class="gh-input-icon gh-icon-user">
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
triggerComponent=triggerComponent
|
triggerComponent=triggerComponent
|
||||||
triggerId=triggerId
|
triggerId=triggerId
|
||||||
verticalPosition=verticalPosition
|
verticalPosition=verticalPosition
|
||||||
|
data-test-token-input=true
|
||||||
as |option term|
|
as |option term|
|
||||||
}}
|
}}
|
||||||
{{#if option.__isSuggestion__}}
|
{{#if option.__isSuggestion__}}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
{{#if user.isLocked}}
|
{{#if user.isLocked}}
|
||||||
<span class="gh-badge author">Locked</span>
|
<span class="gh-badge author">Locked</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#unless session.user.isAuthor}}
|
{{#unless session.user.isAuthorOrContributor}}
|
||||||
{{#each user.roles as |role|}}
|
{{#each user.roles as |role|}}
|
||||||
<span class="gh-badge {{role.lowerCaseName}}" data-test-role-name>{{role.name}}</span>
|
<span class="gh-badge {{role.lowerCaseName}}" data-test-role-name>{{role.name}}</span>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
@ -19,11 +19,19 @@
|
|||||||
{{/gh-scheduled-post-countdown}}
|
{{/gh-scheduled-post-countdown}}
|
||||||
<section class="view-actions">
|
<section class="view-actions">
|
||||||
{{#unless post.isNew}}
|
{{#unless post.isNew}}
|
||||||
{{gh-publishmenu
|
{{#if session.user.isContributor}}
|
||||||
post=post
|
{{gh-task-button "Save"
|
||||||
saveTask=save
|
task=save
|
||||||
setSaveType=(action "setSaveType")
|
runningText="Saving"
|
||||||
onOpen=(action "cancelAutosave")}}
|
class="gh-btn gh-btn-blue gh-btn-icon contributor-save-button"
|
||||||
|
data-test-contributor-save=true}}
|
||||||
|
{{else}}
|
||||||
|
{{gh-publishmenu
|
||||||
|
post=post
|
||||||
|
saveTask=save
|
||||||
|
setSaveType=(action "setSaveType")
|
||||||
|
onOpen=(action "cancelAutosave")}}
|
||||||
|
{{/if}}
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
|
|
||||||
<button type="button" class="post-settings" title="Settings" {{action "openSettingsMenu" target=ui}} data-test-psm-trigger>
|
<button type="button" class="post-settings" title="Settings" {{action "openSettingsMenu" target=ui}} data-test-psm-trigger>
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
{{type.name}}
|
{{type.name}}
|
||||||
{{/power-select}}
|
{{/power-select}}
|
||||||
|
|
||||||
{{#unless session.user.isAuthor}}
|
{{#unless session.user.isAuthorOrContributor}}
|
||||||
{{#power-select
|
{{#power-select
|
||||||
placeholder="All authors"
|
placeholder="All authors"
|
||||||
selected=selectedAuthor
|
selected=selectedAuthor
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
</header>
|
</header>
|
||||||
<div class="gh-contentfilter">
|
<div class="gh-contentfilter">
|
||||||
<div class="gh-contentfilter-left">
|
<div class="gh-contentfilter-left">
|
||||||
|
{{#unless session.user.isContributor}}
|
||||||
{{#power-select
|
{{#power-select
|
||||||
selected=selectedType
|
selected=selectedType
|
||||||
options=availableTypes
|
options=availableTypes
|
||||||
@ -22,8 +23,9 @@
|
|||||||
}}
|
}}
|
||||||
{{type.name}}
|
{{type.name}}
|
||||||
{{/power-select}}
|
{{/power-select}}
|
||||||
|
{{/unless}}
|
||||||
|
|
||||||
{{#unless session.user.isAuthor}}
|
{{#unless session.user.isAuthorOrContributor}}
|
||||||
{{#power-select
|
{{#power-select
|
||||||
selected=selectedAuthor
|
selected=selectedAuthor
|
||||||
options=availableAuthors
|
options=availableAuthors
|
||||||
@ -42,6 +44,7 @@
|
|||||||
{{/power-select}}
|
{{/power-select}}
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
|
|
||||||
|
{{#unless session.user.isContributor}}
|
||||||
{{#power-select
|
{{#power-select
|
||||||
selected=selectedTag
|
selected=selectedTag
|
||||||
options=availableTags
|
options=availableTags
|
||||||
@ -59,6 +62,7 @@
|
|||||||
}}
|
}}
|
||||||
{{tag.name}}
|
{{tag.name}}
|
||||||
{{/power-select}}
|
{{/power-select}}
|
||||||
|
{{/unless}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gh-contentfilter-right">
|
<div class="gh-contentfilter-right">
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<header class="gh-canvas-header">
|
<header class="gh-canvas-header">
|
||||||
<h2 class="gh-canvas-title" data-test-screen-title>Team members</h2>
|
<h2 class="gh-canvas-title" data-test-screen-title>Team members</h2>
|
||||||
{{!-- Do not show Invite user button to authors --}}
|
{{!-- Do not show Invite user button to authors --}}
|
||||||
{{#unless session.user.isAuthor}}
|
{{#unless session.user.isAuthorOrContributor}}
|
||||||
<section class="view-actions">
|
<section class="view-actions">
|
||||||
<button class="gh-btn gh-btn-green" {{action "toggleInviteUserModal"}} ><span>Invite People</span></button>
|
<button class="gh-btn gh-btn-green" {{action "toggleInviteUserModal"}} ><span>Invite People</span></button>
|
||||||
</section>
|
</section>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<header class="gh-canvas-header">
|
<header class="gh-canvas-header">
|
||||||
<h2 class="gh-canvas-title" data-test-screen-title>Team members</h2>
|
<h2 class="gh-canvas-title" data-test-screen-title>Team members</h2>
|
||||||
{{!-- Do not show Invite user button to authors --}}
|
{{!-- Do not show Invite user button to authors --}}
|
||||||
{{#unless session.user.isAuthor}}
|
{{#unless session.user.isAuthorOrContributor}}
|
||||||
<section class="view-actions">
|
<section class="view-actions">
|
||||||
<button class="gh-btn gh-btn-green" {{action "toggleInviteUserModal"}} ><span>Invite People</span></button>
|
<button class="gh-btn gh-btn-green" {{action "toggleInviteUserModal"}} ><span>Invite People</span></button>
|
||||||
</section>
|
</section>
|
||||||
@ -18,7 +18,7 @@
|
|||||||
<section class="gh-team">
|
<section class="gh-team">
|
||||||
|
|
||||||
{{!-- Show invited users to everyone except authors --}}
|
{{!-- Show invited users to everyone except authors --}}
|
||||||
{{#unless session.user.isAuthor}}
|
{{#unless session.user.isAuthorOrContributor}}
|
||||||
{{#if invites}}
|
{{#if invites}}
|
||||||
<section class="apps-grid-container gh-invited-users" data-test-invited-users>
|
<section class="apps-grid-container gh-invited-users" data-test-invited-users>
|
||||||
<span class="apps-grid-title">Invited users</span>
|
<span class="apps-grid-title">Invited users</span>
|
||||||
@ -75,8 +75,8 @@
|
|||||||
<section class="apps-grid-container gh-active-users" data-test-active-users>
|
<section class="apps-grid-container gh-active-users" data-test-active-users>
|
||||||
<span class="apps-grid-title">Active users</span>
|
<span class="apps-grid-title">Active users</span>
|
||||||
<div class="apps-grid">
|
<div class="apps-grid">
|
||||||
{{!-- For authors only show their own user --}}
|
{{!-- For authors/contributors only show their own user --}}
|
||||||
{{#if session.user.isAuthor}}
|
{{#if session.user.isAuthorOrContributor}}
|
||||||
{{#with session.user as |user|}}
|
{{#with session.user as |user|}}
|
||||||
{{#gh-user-active user=user as |component|}}
|
{{#gh-user-active user=user as |component|}}
|
||||||
{{gh-user-list-item user=user component=component}}
|
{{gh-user-list-item user=user component=component}}
|
||||||
@ -100,7 +100,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
{{!-- Don't show if we have no suspended users or logged in as an author --}}
|
{{!-- Don't show if we have no suspended users or logged in as an author --}}
|
||||||
{{#if (and suspendedUsers (not session.user.isAuthor))}}
|
{{#if (and suspendedUsers (not session.user.isAuthorOrContributor))}}
|
||||||
<section class="apps-grid-container gh-active-users" data-test-suspended-users>
|
<section class="apps-grid-container gh-active-users" data-test-suspended-users>
|
||||||
<span class="apps-grid-title">Suspended users</span>
|
<span class="apps-grid-title">Suspended users</span>
|
||||||
<div class="apps-grid">
|
<div class="apps-grid">
|
||||||
|
@ -158,4 +158,42 @@ describe('Acceptance: Content', function () {
|
|||||||
expect(find(`[data-test-post-id="${authorPost.id}"]`), 'author post').to.exist;
|
expect(find(`[data-test-post-id="${authorPost.id}"]`), 'author post').to.exist;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('as contributor', function () {
|
||||||
|
let contributor, contributorPost;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
let contributorRole = server.create('role', {name: 'Contributor'});
|
||||||
|
contributor = server.create('user', {roles: [contributorRole]});
|
||||||
|
let adminRole = server.create('role', {name: 'Administrator'});
|
||||||
|
let admin = server.create('user', {roles: [adminRole]});
|
||||||
|
|
||||||
|
// Create posts
|
||||||
|
contributorPost = server.create('post', {authorId: contributor.id, status: 'draft', title: 'Contributor Post Draft'});
|
||||||
|
server.create('post', {authorId: contributor.id, status: 'published', title: 'Contributor Published Post'});
|
||||||
|
server.create('post', {authorId: admin.id, status: 'scheduled', title: 'Admin Post'});
|
||||||
|
|
||||||
|
return authenticateSession(application);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('only fetches the contributor\'s draft posts', async function () {
|
||||||
|
await visit('/');
|
||||||
|
|
||||||
|
// Ensure the type, tag, and author selectors don't exist
|
||||||
|
expect(find('[data-test-type-select]'), 'type selector').to.not.exist;
|
||||||
|
expect(find('[data-test-tag-select]'), 'tag selector').to.not.exist;
|
||||||
|
expect(find('[data-test-author-select]'), 'author selector').to.not.exist;
|
||||||
|
|
||||||
|
// Trigger a sort request
|
||||||
|
await selectChoose('[data-test-order-select]', 'Oldest');
|
||||||
|
|
||||||
|
// API request includes author filter
|
||||||
|
let [lastRequest] = server.pretender.handledRequests.slice(-1);
|
||||||
|
expect(lastRequest.queryParams.filter).to.equal(`author:${contributor.slug}`);
|
||||||
|
|
||||||
|
// only contributor's post is shown
|
||||||
|
expect(find('[data-test-post-id]').length, 'post count').to.equal(1);
|
||||||
|
expect(find(`[data-test-post-id="${contributorPost.id}"]`), 'author post').to.exist;
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -28,6 +28,17 @@ describe('Acceptance: Editor', function () {
|
|||||||
expect(currentURL(), 'currentURL').to.equal('/signin');
|
expect(currentURL(), 'currentURL').to.equal('/signin');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not redirect to team page when authenticated as contributor', async function () {
|
||||||
|
let role = server.create('role', {name: 'Contributor'});
|
||||||
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
server.create('post');
|
||||||
|
|
||||||
|
authenticateSession(application);
|
||||||
|
await visit('/editor/1');
|
||||||
|
|
||||||
|
expect(currentURL(), 'currentURL').to.equal('/editor/1');
|
||||||
|
});
|
||||||
|
|
||||||
it('does not redirect to team page when authenticated as author', async function () {
|
it('does not redirect to team page when authenticated as author', async function () {
|
||||||
let role = server.create('role', {name: 'Author'});
|
let role = server.create('role', {name: 'Author'});
|
||||||
server.create('user', {roles: [role], slug: 'test-user'});
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
@ -61,6 +72,45 @@ describe('Acceptance: Editor', function () {
|
|||||||
expect(currentURL()).to.equal('/editor/1');
|
expect(currentURL()).to.equal('/editor/1');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when logged in as contributor', function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
let role = server.create('role', {name: 'Contributor'});
|
||||||
|
server.create('user', {roles: [role]});
|
||||||
|
server.loadFixtures('settings');
|
||||||
|
|
||||||
|
return authenticateSession(application);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders a save button instead of a publish menu & hides tags input', async function () {
|
||||||
|
server.createList('post', 2);
|
||||||
|
|
||||||
|
// post id 1 is a draft, checking for draft behaviour now
|
||||||
|
await visit('/editor/1');
|
||||||
|
|
||||||
|
expect(currentURL(), 'currentURL').to.equal('/editor/1');
|
||||||
|
|
||||||
|
// Expect publish menu to not exist
|
||||||
|
expect(
|
||||||
|
find('[data-test-publishmenu-trigger]'),
|
||||||
|
'publish menu trigger'
|
||||||
|
).to.not.exist;
|
||||||
|
|
||||||
|
// Open post settings menu
|
||||||
|
await click('[data-test-psm-trigger]');
|
||||||
|
|
||||||
|
// Check to make sure that tags input doesn't exist
|
||||||
|
expect(
|
||||||
|
find('[data-test-token-input]'),
|
||||||
|
'tags input'
|
||||||
|
).to.not.exist;
|
||||||
|
|
||||||
|
// post id 2 is published, we should be redirected to index
|
||||||
|
await visit('/editor/2');
|
||||||
|
|
||||||
|
expect(currentURL(), 'currentURL').to.equal('/');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('when logged in', function () {
|
describe('when logged in', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
let role = server.create('role', {name: 'Administrator'});
|
let role = server.create('role', {name: 'Administrator'});
|
||||||
|
@ -28,6 +28,16 @@ describe('Acceptance: Settings - Apps - AMP', function () {
|
|||||||
expect(currentURL(), 'currentURL').to.equal('/signin');
|
expect(currentURL(), 'currentURL').to.equal('/signin');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('redirects to team page when authenticated as contributor', async function () {
|
||||||
|
let role = server.create('role', {name: 'Contributor'});
|
||||||
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
|
||||||
|
authenticateSession(application);
|
||||||
|
await visit('/settings/apps/amp');
|
||||||
|
|
||||||
|
expect(currentURL(), 'currentURL').to.equal('/team/test-user');
|
||||||
|
});
|
||||||
|
|
||||||
it('redirects to team page when authenticated as author', async function () {
|
it('redirects to team page when authenticated as author', async function () {
|
||||||
let role = server.create('role', {name: 'Author'});
|
let role = server.create('role', {name: 'Author'});
|
||||||
server.create('user', {roles: [role], slug: 'test-user'});
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
@ -27,6 +27,16 @@ describe('Acceptance: Settings - Apps', function () {
|
|||||||
expect(currentURL(), 'currentURL').to.equal('/signin');
|
expect(currentURL(), 'currentURL').to.equal('/signin');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('redirects to team page when authenticated as contributor', async function () {
|
||||||
|
let role = server.create('role', {name: 'Contributor'});
|
||||||
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
|
||||||
|
authenticateSession(application);
|
||||||
|
await visit('/settings/apps');
|
||||||
|
|
||||||
|
expect(currentURL(), 'currentURL').to.equal('/team/test-user');
|
||||||
|
});
|
||||||
|
|
||||||
it('redirects to team page when authenticated as author', async function () {
|
it('redirects to team page when authenticated as author', async function () {
|
||||||
let role = server.create('role', {name: 'Author'});
|
let role = server.create('role', {name: 'Author'});
|
||||||
server.create('user', {roles: [role], slug: 'test-user'});
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
@ -29,6 +29,16 @@ describe('Acceptance: Settings - Code-Injection', function () {
|
|||||||
expect(currentURL(), 'currentURL').to.equal('/signin');
|
expect(currentURL(), 'currentURL').to.equal('/signin');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('redirects to team page when authenticated as contributor', async function () {
|
||||||
|
let role = server.create('role', {name: 'Contributor'});
|
||||||
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
|
||||||
|
authenticateSession(application);
|
||||||
|
await visit('/settings/code-injection');
|
||||||
|
|
||||||
|
expect(currentURL(), 'currentURL').to.equal('/team/test-user');
|
||||||
|
});
|
||||||
|
|
||||||
it('redirects to team page when authenticated as author', async function () {
|
it('redirects to team page when authenticated as author', async function () {
|
||||||
let role = server.create('role', {name: 'Author'});
|
let role = server.create('role', {name: 'Author'});
|
||||||
server.create('user', {roles: [role], slug: 'test-user'});
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
@ -26,6 +26,16 @@ describe('Acceptance: Settings - Design', function () {
|
|||||||
expect(currentURL(), 'currentURL').to.equal('/signin');
|
expect(currentURL(), 'currentURL').to.equal('/signin');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('redirects to team page when authenticated as contributor', async function () {
|
||||||
|
let role = server.create('role', {name: 'Contributor'});
|
||||||
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
|
||||||
|
authenticateSession(application);
|
||||||
|
await visit('/settings/design');
|
||||||
|
|
||||||
|
expect(currentURL(), 'currentURL').to.equal('/team/test-user');
|
||||||
|
});
|
||||||
|
|
||||||
it('redirects to team page when authenticated as author', async function () {
|
it('redirects to team page when authenticated as author', async function () {
|
||||||
let role = server.create('role', {name: 'Author'});
|
let role = server.create('role', {name: 'Author'});
|
||||||
server.create('user', {roles: [role], slug: 'test-user'});
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
@ -27,6 +27,16 @@ describe('Acceptance: Settings - General', function () {
|
|||||||
expect(currentURL(), 'currentURL').to.equal('/signin');
|
expect(currentURL(), 'currentURL').to.equal('/signin');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('redirects to team page when authenticated as contributor', async function () {
|
||||||
|
let role = server.create('role', {name: 'Contributor'});
|
||||||
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
|
||||||
|
authenticateSession(application);
|
||||||
|
await visit('/settings/general');
|
||||||
|
|
||||||
|
expect(currentURL(), 'currentURL').to.equal('/team/test-user');
|
||||||
|
});
|
||||||
|
|
||||||
it('redirects to team page when authenticated as author', async function () {
|
it('redirects to team page when authenticated as author', async function () {
|
||||||
let role = server.create('role', {name: 'Author'});
|
let role = server.create('role', {name: 'Author'});
|
||||||
server.create('user', {roles: [role], slug: 'test-user'});
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
@ -25,6 +25,16 @@ describe('Acceptance: Settings - Labs', function () {
|
|||||||
expect(currentURL(), 'currentURL').to.equal('/signin');
|
expect(currentURL(), 'currentURL').to.equal('/signin');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('redirects to team page when authenticated as contributor', async function () {
|
||||||
|
let role = server.create('role', {name: 'Contributor'});
|
||||||
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
|
||||||
|
authenticateSession(application);
|
||||||
|
await visit('/settings/labs');
|
||||||
|
|
||||||
|
expect(currentURL(), 'currentURL').to.equal('/team/test-user');
|
||||||
|
});
|
||||||
|
|
||||||
it('redirects to team page when authenticated as author', async function () {
|
it('redirects to team page when authenticated as author', async function () {
|
||||||
let role = server.create('role', {name: 'Author'});
|
let role = server.create('role', {name: 'Author'});
|
||||||
server.create('user', {roles: [role], slug: 'test-user'});
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
@ -24,6 +24,16 @@ describe('Acceptance: Settings - Apps - Slack', function () {
|
|||||||
expect(currentURL(), 'currentURL').to.equal('/signin');
|
expect(currentURL(), 'currentURL').to.equal('/signin');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('redirects to team page when authenticated as contributor', async function () {
|
||||||
|
let role = server.create('role', {name: 'Contributor'});
|
||||||
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
|
||||||
|
authenticateSession(application);
|
||||||
|
await visit('/settings/apps/slack');
|
||||||
|
|
||||||
|
expect(currentURL(), 'currentURL').to.equal('/team/test-user');
|
||||||
|
});
|
||||||
|
|
||||||
it('redirects to team page when authenticated as author', async function () {
|
it('redirects to team page when authenticated as author', async function () {
|
||||||
let role = server.create('role', {name: 'Author'});
|
let role = server.create('role', {name: 'Author'});
|
||||||
server.create('user', {roles: [role], slug: 'test-user'});
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
@ -56,6 +56,16 @@ describe('Acceptance: Settings - Tags', function () {
|
|||||||
expect(currentURL()).to.equal('/signin');
|
expect(currentURL()).to.equal('/signin');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('redirects to team page when authenticated as contributor', async function () {
|
||||||
|
let role = server.create('role', {name: 'Contributor'});
|
||||||
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
|
||||||
|
authenticateSession(application);
|
||||||
|
await visit('/settings/design');
|
||||||
|
|
||||||
|
expect(currentURL(), 'currentURL').to.equal('/team/test-user');
|
||||||
|
});
|
||||||
|
|
||||||
it('redirects to team page when authenticated as author', async function () {
|
it('redirects to team page when authenticated as author', async function () {
|
||||||
let role = server.create('role', {name: 'Author'});
|
let role = server.create('role', {name: 'Author'});
|
||||||
server.create('user', {roles: [role], slug: 'test-user'});
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
@ -23,6 +23,16 @@ describe('Acceptance: Settings - Apps - Unsplash', function () {
|
|||||||
expect(currentURL(), 'currentURL').to.equal('/signin');
|
expect(currentURL(), 'currentURL').to.equal('/signin');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('redirects to team page when authenticated as contributor', async function () {
|
||||||
|
let role = server.create('role', {name: 'Contributor'});
|
||||||
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
|
||||||
|
authenticateSession(application);
|
||||||
|
await visit('/settings/apps/unsplash');
|
||||||
|
|
||||||
|
expect(currentURL(), 'currentURL').to.equal('/team/test-user');
|
||||||
|
});
|
||||||
|
|
||||||
it('redirects to team page when authenticated as author', async function () {
|
it('redirects to team page when authenticated as author', async function () {
|
||||||
let role = server.create('role', {name: 'Author'});
|
let role = server.create('role', {name: 'Author'});
|
||||||
server.create('user', {roles: [role], slug: 'test-user'});
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
@ -46,6 +46,18 @@ describe('Acceptance: Subscribers', function () {
|
|||||||
.to.equal(0);
|
.to.equal(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('redirects contributors to posts', async function () {
|
||||||
|
let role = server.create('role', {name: 'Contributor'});
|
||||||
|
server.create('user', {roles: [role]});
|
||||||
|
|
||||||
|
authenticateSession(application);
|
||||||
|
await visit('/subscribers');
|
||||||
|
|
||||||
|
expect(currentURL()).to.equal('/');
|
||||||
|
expect(find('.gh-nav-main a:contains("Subscribers")').length, 'sidebar link is visible')
|
||||||
|
.to.equal(0);
|
||||||
|
});
|
||||||
|
|
||||||
describe('an admin', function () {
|
describe('an admin', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
let role = server.create('role', {name: 'Administrator'});
|
let role = server.create('role', {name: 'Administrator'});
|
||||||
|
@ -27,6 +27,18 @@ describe('Acceptance: Team', function () {
|
|||||||
expect(currentURL()).to.equal('/signin');
|
expect(currentURL()).to.equal('/signin');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('redirects correctly when authenticated as contributor', async function () {
|
||||||
|
let role = server.create('role', {name: 'Contributor'});
|
||||||
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
|
||||||
|
server.create('user', {slug: 'no-access'});
|
||||||
|
|
||||||
|
authenticateSession(application);
|
||||||
|
await visit('/team/no-access');
|
||||||
|
|
||||||
|
expect(currentURL(), 'currentURL').to.equal('/team/test-user');
|
||||||
|
});
|
||||||
|
|
||||||
it('redirects correctly when authenticated as author', async function () {
|
it('redirects correctly when authenticated as author', async function () {
|
||||||
let role = server.create('role', {name: 'Author'});
|
let role = server.create('role', {name: 'Author'});
|
||||||
server.create('user', {roles: [role], slug: 'test-user'});
|
server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
@ -15,6 +15,7 @@ describe('Unit: Controller: editor', function () {
|
|||||||
'service:notifications',
|
'service:notifications',
|
||||||
// 'service:router',
|
// 'service:router',
|
||||||
'service:slugGenerator',
|
'service:slugGenerator',
|
||||||
|
'service:session',
|
||||||
'service:ui'
|
'service:ui'
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
@ -37,7 +37,7 @@ describe('Unit: Helper: gh-user-can-admin', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Editor and Author roles', function () {
|
describe('Editor, Author & Contributor roles', function () {
|
||||||
let user = {
|
let user = {
|
||||||
get(role) {
|
get(role) {
|
||||||
if (role === 'isOwner') {
|
if (role === 'isOwner') {
|
||||||
|
@ -61,6 +61,21 @@ describe('Unit: Model: user', function () {
|
|||||||
expect(model.get('role.name')).to.equal('Editor');
|
expect(model.get('role.name')).to.equal('Editor');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('isContributor property is correct', function () {
|
||||||
|
let model = this.subject();
|
||||||
|
|
||||||
|
run(() => {
|
||||||
|
let role = this.store().push({data: {id: 1, type: 'role', attributes: {name: 'Contributor'}}});
|
||||||
|
model.set('role', role);
|
||||||
|
});
|
||||||
|
expect(model.get('isContributor')).to.be.ok;
|
||||||
|
expect(model.get('isAuthorOrContributor')).to.be.ok;
|
||||||
|
expect(model.get('isAuthor')).to.not.be.ok;
|
||||||
|
expect(model.get('isEditor')).to.not.be.ok;
|
||||||
|
expect(model.get('isAdmin')).to.not.be.ok;
|
||||||
|
expect(model.get('isOwner')).to.not.be.ok;
|
||||||
|
});
|
||||||
|
|
||||||
it('isAuthor property is correct', function () {
|
it('isAuthor property is correct', function () {
|
||||||
let model = this.subject();
|
let model = this.subject();
|
||||||
|
|
||||||
@ -69,6 +84,8 @@ describe('Unit: Model: user', function () {
|
|||||||
model.set('role', role);
|
model.set('role', role);
|
||||||
});
|
});
|
||||||
expect(model.get('isAuthor')).to.be.ok;
|
expect(model.get('isAuthor')).to.be.ok;
|
||||||
|
expect(model.get('isContributor')).to.not.be.ok;
|
||||||
|
expect(model.get('isAuthorOrContributor')).to.be.ok;
|
||||||
expect(model.get('isEditor')).to.not.be.ok;
|
expect(model.get('isEditor')).to.not.be.ok;
|
||||||
expect(model.get('isAdmin')).to.not.be.ok;
|
expect(model.get('isAdmin')).to.not.be.ok;
|
||||||
expect(model.get('isOwner')).to.not.be.ok;
|
expect(model.get('isOwner')).to.not.be.ok;
|
||||||
@ -83,6 +100,8 @@ describe('Unit: Model: user', function () {
|
|||||||
});
|
});
|
||||||
expect(model.get('isEditor')).to.be.ok;
|
expect(model.get('isEditor')).to.be.ok;
|
||||||
expect(model.get('isAuthor')).to.not.be.ok;
|
expect(model.get('isAuthor')).to.not.be.ok;
|
||||||
|
expect(model.get('isContributor')).to.not.be.ok;
|
||||||
|
expect(model.get('isAuthorOrContributor')).to.not.be.ok;
|
||||||
expect(model.get('isAdmin')).to.not.be.ok;
|
expect(model.get('isAdmin')).to.not.be.ok;
|
||||||
expect(model.get('isOwner')).to.not.be.ok;
|
expect(model.get('isOwner')).to.not.be.ok;
|
||||||
});
|
});
|
||||||
@ -96,6 +115,8 @@ describe('Unit: Model: user', function () {
|
|||||||
});
|
});
|
||||||
expect(model.get('isAdmin')).to.be.ok;
|
expect(model.get('isAdmin')).to.be.ok;
|
||||||
expect(model.get('isAuthor')).to.not.be.ok;
|
expect(model.get('isAuthor')).to.not.be.ok;
|
||||||
|
expect(model.get('isContributor')).to.not.be.ok;
|
||||||
|
expect(model.get('isAuthorOrContributor')).to.not.be.ok;
|
||||||
expect(model.get('isEditor')).to.not.be.ok;
|
expect(model.get('isEditor')).to.not.be.ok;
|
||||||
expect(model.get('isOwner')).to.not.be.ok;
|
expect(model.get('isOwner')).to.not.be.ok;
|
||||||
});
|
});
|
||||||
@ -109,6 +130,8 @@ describe('Unit: Model: user', function () {
|
|||||||
});
|
});
|
||||||
expect(model.get('isOwner')).to.be.ok;
|
expect(model.get('isOwner')).to.be.ok;
|
||||||
expect(model.get('isAuthor')).to.not.be.ok;
|
expect(model.get('isAuthor')).to.not.be.ok;
|
||||||
|
expect(model.get('isContributor')).to.not.be.ok;
|
||||||
|
expect(model.get('isAuthorOrContributor')).to.not.be.ok;
|
||||||
expect(model.get('isAdmin')).to.not.be.ok;
|
expect(model.get('isAdmin')).to.not.be.ok;
|
||||||
expect(model.get('isEditor')).to.not.be.ok;
|
expect(model.get('isEditor')).to.not.be.ok;
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user