diff --git a/README.md b/README.md index cf9f34a..0947a8f 100755 --- a/README.md +++ b/README.md @@ -5,65 +5,8 @@ Silverstripe Blogger A fresh take on blogging in Silverstripe set out to tackle the issue of a cluttered Site Tree. +## Documentation index -## Requirements -``` -silverstripe/cms: ~3.1 -``` - -## Suggested Modules -``` -silverstripe/widgets: * -silverstripe/comments: * -``` - - -## Installation - -``` -composer require micmania1/silverstripe-blog:1.0.* -``` - - -## Features -* Blog Posts extend SiteTree so no Page functionality is lost by using DataObject's. -* Blog Posts can be listed in the SiteTree **OR** in a GridField within the blog, removing clutter for large blogs. -* Filter blog posts by category -* Filter blog posts by tag -* Full blog Archive by Year, month or day -* 4 widgets included (category listing, tag listing, archive & recent posts). -* Publish Date - Set a blog post to publish in the future. -* Custom GridField components for quickly adding new objects. -* RSS Feed of the blog - - -## Screenshots -*Easily manage and add new blog posts through a GridField.* -![](screenshots/blog-post-management.png) - -*Quickly add new tags and categories.* -![](screenshots/blogpost-add-tags-categories.png) - - -## Usage -Because the blog is part of the SiteTree the usage is the same as any other page. - -By default, blog posts are filtered out of the SiteTree to avoid clutter and instead put in a GridField inside of the blog. If you wish to display the blog posts within the site tree you can do so using Silverstripe config. - -**YAML** -``` -BlogPost: - show_in_sitetree: true -``` - -**PHP** -``` -update("BlogPost", "show_in_sitetree", true); -``` - -Doing this will remove the GridField & result in a normal behaving SiteTree. - - -## Theme -You can download a blog sub-theme of Silverstripe's default 'Simple' theme: https://github.com/micmania1/simple_blog + * [Features](docs/en/features.md) + * [Setup](docs/en/setup.md) + * [Roles](docs/en/roles.md) diff --git a/code/extensions/BlogFilter.php b/code/extensions/BlogFilter.php index cb97a73..67b62f0 100644 --- a/code/extensions/BlogFilter.php +++ b/code/extensions/BlogFilter.php @@ -29,7 +29,7 @@ class BlogFilter extends Lumberjack { // Get the current stage. $stage = Versioned::current_stage(); if($stage == "Stage") $stage = ""; - else $stage = "_" . Convert::raw2sql($stage); + elseif($stage) $stage = "_{$stage}"; // Filter published posts $dataQuery = $staged->dataQuery() @@ -40,28 +40,50 @@ class BlogFilter extends Lumberjack { return $staged; } - - - /** - * Augments (@link Hierarchy::liveChildren()} - * - * @param $staged DataList - * @param $showAll boolean - **/ public function liveChildren($showAll = false, $onlyDeletedFromStage = false) { $staged = parent::liveChildren($showAll, $onlyDeletedFromStage); if(!$this->shouldFilter() - && in_array(get_class($this->owner), ClassInfo::subClassesFor("Blog")) + && $this->owner instanceof Blog && !Permission::check("VIEW_DRAFT_CONTENT") ) { // Filter publish posts $dataQuery = $staged->dataQuery() - ->innerJoin("BlogPost", '"BlogPost_Live"."ID" = "SiteTree"_"Live"."ID"') - ->where('"PublishDate" < \'' . Convert::raw2sql(SS_Datetime::now()) . '\''); + ->innerJoin("BlogPost", '"BlogPost_Live"."ID" = "SiteTree_Live"."ID"') + ->where('"BlogPost"."PublishDate" < \'' . Convert::raw2sql(SS_Datetime::now()->getValue()) . '\''); $staged = $staged->setDataQuery($dataQuery); } return $staged; } -} \ No newline at end of file + public function updateCMSFields(FieldList $fields) { + $excluded = $this->owner->getExcludedSiteTreeClassNames(); + if(!empty($excluded)) { + $pages = SiteTree::get()->filter(array( + 'ParentID' => $this->owner->ID, + 'ClassName' => $excluded + )); + $gridField = new BlogFilter_GridField( + "ChildPages", + $this->getLumberjackTitle(), + $pages, + $this->getLumberjackGridFieldConfig() + ); + + $tab = new Tab('ChildPages', $this->getLumberjackTitle(), $gridField); + $fields->insertAfter($tab, 'Main'); + } + } + +} + + +/** + * Enables children of non-editable pages to be edited + */ +class BlogFilter_GridField extends GridField { + public function transform(FormTransformation $trans) { + // Don't allow parent object transformations to propegate automatically to child records + return $this; + } +} diff --git a/code/model/Blog.php b/code/model/Blog.php index 7dbfd46..fe81ea6 100644 --- a/code/model/Blog.php +++ b/code/model/Blog.php @@ -5,39 +5,79 @@ * * @package silverstripe * @subpackage blog + * + * @method HasManyList Tags() List of tags in this blog + * @method HasManyList Categories() List of categories in this blog + * @method ManyManyList Editors() List of editors + * @method ManyManyList Writers() List of writers + * @method ManyManyList Contributors() List of contributors * * @author Michael Strong **/ -class Blog extends Page { +class Blog extends Page implements PermissionProvider { + + /** + * Permission for user management + * + * @var string + */ + const MANAGE_USERS = 'BLOG_MANAGE_USERS'; + + /** + * If true, users assigned as editor, writer, or contributor will be automatically + * granted CMS_ACCESS_CMSMain permission. If false, only users with this permission + * already may be assigned. + * + * @var boolean + * @config + */ + private static $grant_user_access = true; + + /** + * Permission to either require, or grant to users assigned to work on this blog + * + * @var string + * @config + */ + private static $grant_user_permission = 'CMS_ACCESS_CMSMain'; + + /** + * Group code to assign newly granted users toh + * + * @var string + * @config + */ + private static $grant_user_group = 'blog-users'; private static $db = array( "PostsPerPage" => "Int", ); - private static $has_many = array( "Tags" => "BlogTag", "Categories" => "BlogCategory", ); + private static $many_many = array( + 'Editors' => 'Member', + 'Writers' => 'Member', + 'Contributors' => 'Member', + ); private static $allowed_children = array( "BlogPost", ); - private static $extensions = array( "BlogFilter", ); - private static $defaults = array( "ProvideComments" => false, ); private static $description = 'Adds a blog to your website.'; - public function getCMSFields() { $self =& $this; $this->beforeUpdateCMSFields(function($fields) use ($self) { @@ -65,13 +105,144 @@ class Blog extends Page { $categories, $tags )); - }); $fields = parent::getCMSFields(); return $fields; } + /** + * Check if this member is an editor of the blog + * + * @param Member $member + * @return boolean + */ + public function isEditor($member) { + $isEditor = $this->isMemberOf($member, $this->Editors()); + $this->extend('updateIsEditor', $isEditor, $member); + return $isEditor; + } + + /** + * Check if this member is a writer of the blog + * + * @param Member $member + * @return boolean + */ + public function isWriter($member) { + $isWriter = $this->isMemberOf($member, $this->Writers()); + $this->extend('updateIsWriter', $isWriter, $member); + return $isWriter; + } + + /** + * Check if this member is a contributor of the blog + * + * @param Member $member + * @return boolean + */ + public function isContributor($member) { + $isContributor = $this->isMemberOf($member, $this->Contributors()); + $this->extend('updateIsContributor', $isContributor, $member); + return $isContributor; + } + + /** + * Determine if the given member belongs to the given subrelation + * + * @param Member $member + * @param DataList $list Relation to check + * @return boolean + */ + protected function isMemberOf($member, $list) { + if(!$member || !$member->exists()) return false; + + if($list instanceof UnsavedRelationList) { + return in_array($member->ID, $list->getIDList()); + } + + return $list->byID($member->ID) !== null; + } + + + + public function canEdit($member = null) { + $member = $member ?: Member::currentUser(); + if(is_numeric($member)) $member = Member::get()->byID($member); + + // Allow editors to edit this page + if($this->isEditor($member)) return true; + + return parent::canEdit($member); + } + + /** + * Determine if this user can edit the editors list + * + * @param Member $member + * @return boolean + */ + public function canEditEditors($member = null) { + $member = $member ?: Member::currentUser(); + + $extended = $this->extendedCan('canEditEditors', $member); + if($extended !== null) return $extended; + + // Check permission + return Permission::checkMember($member, self::MANAGE_USERS); + } + + /** + * Determine if this user can edit writers list + * + * @param Member $member + * @return boolean + */ + public function canEditWriters($member = null) { + $member = $member ?: Member::currentUser(); + if(is_numeric($member)) $member = Member::get()->byID($member); + + $extended = $this->extendedCan('canEditWriters', $member); + if($extended !== null) return $extended; + + // Editors can edit writers + if($this->isEditor($member)) return true; + + // Check permission + return Permission::checkMember($member, self::MANAGE_USERS); + } + + /** + * Determines if this user can edit the contributors list + * + * @param type $member + * @return boolean + */ + public function canEditContributors($member = null) { + $member = $member ?: Member::currentUser(); + if(is_numeric($member)) $member = Member::get()->byID($member); + + $extended = $this->extendedCan('canEditContributors', $member); + if($extended !== null) return $extended; + + // Editors can edit writers + if($this->isEditor($member)) return true; + + // Check permission + return Permission::checkMember($member, self::MANAGE_USERS); + } + + public function canAddChildren($member = null) { + $member = $member ?: Member::currentUser(); + if(is_numeric($member)) $member = Member::get()->byID($member); + + // Editors, Writers and Contributors can add children + if($this->isEditor($member) || $this->isWriter($member) || $this->isContributor($member)) { + return true; + } + + return parent::canAddChildren($member); + } public function getSettingsFields() { @@ -79,11 +250,44 @@ class Blog extends Page { $fields->addFieldToTab("Root.Settings", NumericField::create("PostsPerPage", _t("Blog.PostsPerPage", "Posts Per Page")) ); + + // Roles and Permissions + $members = $this->getCandidateUsers()->map()->toArray(); + + // Editors + $editorField = ListboxField::create('Editors', 'Editors', $members) + ->setMultiple(true) + ->setDescription('Editors are able to manage this blog and its posts'); + if(!$this->canEditEditors()) { + $editorField = $editorField->performDisabledTransformation(); + } + + // Writers + $writerField = ListboxField::create('Writers', 'Writers', $members) + ->setMultiple(true) + ->setDescription('Writers are able to write and publish posts'); + if(!$this->canEditWriters()) { + $writerField = $writerField->performDisabledTransformation(); + } + + // Contributors + $contributorField = ListboxField::create('Contributors', 'Contributors', $members) + ->setMultiple(true) + ->setDescription('Contributors are able to write, but not publish, posts'); + if(!$this->canEditContributors()) { + $contributorField = $contributorField->performDisabledTransformation(); + } + + $fields->addFieldsToTab('Root.Users', array( + $editorField, + $writerField, + $contributorField + )); + return $fields; } - /** * Return blog posts * @@ -103,7 +307,7 @@ class Blog extends Page { * * @param $year int * @param $month int - * @param $dat int + * @param $day int * * @return DataList **/ @@ -147,6 +351,86 @@ class Blog extends Page { return GridFieldConfig_BlogPost::create(); } + public function providePermissions() { + return array( + Blog::MANAGE_USERS => array( + 'name' => _t( + 'Blog.PERMISSION_MANAGE_USERS_DESCRIPTION', + 'Manage users for individual blogs' + ), + 'help' => _t( + 'Blog.PERMISSION_MANAGE_USERS_HELP', + 'Allow assignment of Editors, Writers, or Contributors to blogs' + ), + 'category' => _t('Blog.PERMISSIONS_CATEGORY', 'Blog permissions'), + 'sort' => 100 + ) + ); + } + + /** + * Gets the list of user candidates to be assigned to assist with this blog + * + * @return SS_List + */ + protected function getCandidateUsers() { + if($this->config()->grant_user_access) { + // If we are allowed to grant CMS access, all users are candidates + return Member::get(); + } else { + // If access cannot be granted, limit users to those who can access the CMS + // This is useful for more secure sites + $permission = $this->config()->grant_user_permission; + return Permission::get_members_by_permission($permission); + } + } + + /** + * Gets or creates the group used to assign CMS access + * + * @return Group + */ + protected function getUserGroup() { + $code = $this->config()->grant_user_group; + $group = Group::get()->filter('Code', $code)->first(); + if($group) return $group; + + // Create new group + $group = new Group(); + $group->Title = 'Blog users'; + $group->Code = $code; + $group->write(); + + // Add permission + $permission = new Permission(); + $permission->Code = $this->config()->grant_user_permission; + $group->Permissions()->add($permission); + + return $group; + } + + protected function onBeforeWrite() { + parent::onBeforeWrite(); + $this->assignGroup(); + } + + /** + * Assign users as necessary to the blog group + */ + protected function assignGroup() { + // Ensure that any user granted editor, writer, or contributor have CMS_ACCESS_CMSMain access + if(!$this->config()->grant_user_access) return; + + // Generate or retrieve the group + $group = $this->getUserGroup(); + foreach(array($this->Editors(), $this->Writers(), $this->Contributors()) as $userlist) { + foreach($userlist as $user) { + // Ensure user exists in the group + if(!$user->inGroup($group)) $user->Groups()->add($group); + } + } + } + } diff --git a/code/model/BlogPost.php b/code/model/BlogPost.php index 1c9ade1..c9acdb6 100644 --- a/code/model/BlogPost.php +++ b/code/model/BlogPost.php @@ -6,12 +6,17 @@ * @package silverstripe * @subpackage blog * + * @method ManyManyList Categories() + * @method ManyManyList Tags() + * @method ManyManyList Authors() + * * @author Michael Strong **/ class BlogPost extends Page { private static $db = array( "PublishDate" => "SS_Datetime", + "AuthorNames" => "Varchar(1024)" ); private static $has_one = array( @@ -21,6 +26,7 @@ class BlogPost extends Page { private static $many_many = array( "Categories" => "BlogCategory", "Tags" => "BlogTag", + "Authors" => "Member", ); private static $defaults = array( @@ -60,6 +66,23 @@ class BlogPost extends Page { private static $show_in_sitetree = false; + /** + * Determine if the given member is an author of this post + * + * @param Member $member + * @return boolean + */ + protected function isAuthor($member) { + if(!$member || !$member->exists()) return false; + + $list = $this->Authors(); + if($list instanceof UnsavedRelationList) { + return in_array($member->ID, $list->getIDList()); + } + + return $list->byID($member->ID) !== null; + } + public function getCMSFields() { Requirements::css(BLOGGER_DIR . '/css/cms.css'); @@ -87,6 +110,24 @@ class BlogPost extends Page { 'URLSegment', )); + // Author field + $authorField = ListboxField::create( + "Authors", + _t("BlogPost.Authors", "Authors"), + Member::get()->map()->toArray() + )->setMultiple(true); + + $authorNames = TextField::create( + "AuthorNames", + _t("BlogPost.AdditionalCredits", "Additional Credits"), + null, + 1024 + )->setDescription('Comma separated list of names'); + if(!$this->canEditAuthors()) { + $authorField = $authorField->performDisabledTransformation(); + $authorNames = $authorNames->performDisabledTransformation(); + } + // Build up our sidebar $options = BlogAdminSidebar::create( $publishDate = DatetimeField::create("PublishDate", _t("BlogPost.PublishDate", "Publish Date")), @@ -100,7 +141,9 @@ class BlogPost extends Page { "Tags", _t("BlogPost.Tags", "Tags"), $self->Parent()->Tags()->map()->toArray() - )->setMultiple(true) + )->setMultiple(true), + $authorField, + $authorNames )->setTitle('Post Options'); $publishDate->getDateField()->setConfig("showcalendar", true); @@ -116,14 +159,17 @@ class BlogPost extends Page { return $fields; } - - - /** - * If no publish date is set, set the date to now. - **/ protected function onBeforeWrite() { parent::onBeforeWrite(); - if(!$this->PublishDate) $this->setCastedField("PublishDate", time()); + + // If no publish date is set, set the date to now. + if(!$this->PublishDate) $this->PublishDate = SS_Datetime::now()->getValue(); + + // If creating a new entry, assign the current member as an author + // This allows writers and contributors to then edit their new post + if(!$this->exists() && ($member = Member::currentUser())) { + $this->Authors()->add($member); + } } @@ -133,7 +179,7 @@ class BlogPost extends Page { **/ public function onBeforePublish() { if ($this->dbObject('PublishDate')->InPast() && !$this->isPublished()) { - $this->setCastedField("PublishDate", time()); + $this->PublishDate = SS_Datetime::now()->getValue(); $this->write(); } } @@ -159,6 +205,81 @@ class BlogPost extends Page { return true; } + public function canEdit($member = null) { + $member = $member ?: Member::currentUser(); + if(is_numeric($member)) $member = Member::get()->byID($member); + + // Inherit permission + if(parent::canEdit($member)) return true; + + // Check if assigned to a blog + $parent = $this->Parent(); + if(!$parent || !$parent->exists() || !($parent instanceof Blog)) return false; + + // Editors have full control + if($parent->isEditor($member)) return true; + + // Only writers or contributors can edit + if(!$parent->isWriter($member) && !$parent->isContributor($member)) return false; + + // And only if they are also authors + return $this->isAuthor($member); + } + + /** + * Determine if this user can edit the authors list + * + * @param Member $member + * @return boolean + */ + public function canEditAuthors($member = null) { + $member = $member ?: Member::currentUser(); + if(is_numeric($member)) $member = Member::get()->byID($member); + + $extended = $this->extendedCan('canEditAuthors', $member); + if($extended !== null) return $extended; + + // Check blog roles + $parent = $this->Parent(); + if($parent instanceof Blog && $parent->exists()) { + // Editors can do anything + if($parent->isEditor($member)) return true; + + // Writers who are also authors can edit authors + if($parent->isWriter($member) && $this->isAuthor($member)) return true; + } + + // Check permission + return Permission::checkMember($member, Blog::MANAGE_USERS); + } + + public function canPublish($member = null) { + $member = $member ?: Member::currentUser(); + if(is_numeric($member)) $member = Member::get()->byID($member); + + if(Permission::checkMember($member, "ADMIN")) return true; + + // Standard mechanism for accepting permission changes from extensions + $extended = $this->extendedCan('canPublish', $member); + if($extended !== null) return $extended; + + // Check blog roles + $parent = $this->Parent(); + if($parent instanceof Blog && $parent->exists()) { + // Editors can do anything + if($parent->isEditor($member)) return true; + + // Writers who are also authors can edit authors + if($parent->isWriter($member) && $this->isAuthor($member)) return true; + + // Contributors can ONLY publish this page if they somehow have global publish permissions + // In this case defer to old canEdit implementation + if($parent->isContributor($member)) return parent::canEdit($member); + } + + // Normal case - fail over to canEdit() + return $this->canEdit($member); + } /** @@ -183,7 +304,6 @@ class BlogPost extends Page { **/ public function getMonthlyArchiveLink($type = "day") { $date = $this->dbObject("PublishDate"); - $year = $date->format("Y"); if($type != "year") { if($type == "day") { return Controller::join_links( diff --git a/docs/_manifest_exclude b/docs/_manifest_exclude new file mode 100644 index 0000000..e69de29 diff --git a/screenshots/blog-post-management.png b/docs/en/_images/blog-post-management.png similarity index 100% rename from screenshots/blog-post-management.png rename to docs/en/_images/blog-post-management.png diff --git a/screenshots/blogpost-add-tags-categories.png b/docs/en/_images/blogpost-add-tags-categories.png similarity index 100% rename from screenshots/blogpost-add-tags-categories.png rename to docs/en/_images/blogpost-add-tags-categories.png diff --git a/docs/en/features.md b/docs/en/features.md new file mode 100644 index 0000000..d572786 --- /dev/null +++ b/docs/en/features.md @@ -0,0 +1,20 @@ +# Features + +* Blog Posts extend SiteTree so no Page functionality is lost by using DataObject's. +* Blog Posts can be listed in the SiteTree **OR** in a GridField within the blog, removing clutter for large blogs. +* Filter blog posts by category +* Filter blog posts by tag +* Full blog Archive by Year, month or day +* 4 widgets included (category listing, tag listing, archive & recent posts). +* Publish Date - Set a blog post to publish in the future. +* Custom GridField components for quickly adding new objects. +* RSS Feed of the blog + + +## Screenshots + +*Easily manage and add new blog posts through a GridField.* +![](_images/blog-post-management.png) + +*Quickly add new tags and categories.* +![](_images/blogpost-add-tags-categories.png) diff --git a/docs/en/roles.md b/docs/en/roles.md new file mode 100644 index 0000000..e714d70 --- /dev/null +++ b/docs/en/roles.md @@ -0,0 +1,43 @@ +# Roles + +Blog authoring and management can be delegated to users at up to three different levels. Users assigned to a blog +using one of the below methods will be automatically assigned to the "Blog users" group and granted basic CMS access. + +Note: If it's necessary to restrict access to non-blog pages to any of the below users, ensure that +the "Who can edit pages on this site?" option under Settings is changed from "Anyone who can log-in to the CMS" +to a specific selection of groups. + +## Editor + +An editor has control over specific Blogs, and their respective BlogPost subpages. Short of being able to assign +other editors to a Blog, they are able to handle most changes to their assigned section. + +Editors have these permissions: + + * Update or Publish any BlogPost in their Blog + * Update or Publish their Blog + * Assign/Unassign writers to their Blog + * Assign/Unassign contributors to their Blog + * Assign/Unassign any member as an author of a particular BlogPost + +## Writer + +A writer is able to handle most tasks involving writing and publishing BlogPosts. While they +are not able to edit a Blog directly, they are able to add new BlogPost entries within a Blog. +They can't edit BlogPosts, however, that they are not been assigned to or have authored themselves. + +Writers have these permissions: + + * Update or Publish any BlogPost they have authored (or are assigned as author of) + * Assign/Unassign any member as an author of a particular BlogPost they have authored + (or are assigned as author of) + +## Contributor + +Contributors have the ability to create or edit BlogPosts, but are unable to publish without +authorisation of an editor. They are also unable to assign other contributing authors to +any of their BlogPosts. + +Contributors have these permissions: + + * Update or edit any BlogPost they have authored (or are assigned as author of) diff --git a/docs/en/setup.md b/docs/en/setup.md new file mode 100644 index 0000000..37117bc --- /dev/null +++ b/docs/en/setup.md @@ -0,0 +1,36 @@ +# Setup + +## Requirements + +``` +silverstripe/cms: ~3.1 +``` + +## Suggested Modules + +``` +silverstripe/widgets: * +silverstripe/comments: * +``` + +## Installation + +``` +composer require silverstripe/blog 2.0.x-dev +``` + +## Usage + +Because the blog is part of the SiteTree the usage is the same as any other page. + +By default, blog posts are filtered out of the SiteTree to avoid clutter and instead put in a GridField inside +of the blog. If you wish to display the blog posts within the site tree you can do so using Silverstripe config. + +In mysite/_config/settings.yml + +```yaml +BlogPost: + show_in_sitetree: true +``` + +Doing this will remove the GridField & result in a normal behaving SiteTree. diff --git a/templates/Includes/EntryMeta.ss b/templates/Includes/EntryMeta.ss index b2467aa..df4dde2 100644 --- a/templates/Includes/EntryMeta.ss +++ b/templates/Includes/EntryMeta.ss @@ -22,4 +22,14 @@ <%t Blog.Posted "Posted" %> $PublishDate.ago + + <% if $Authors || $AuthorNames %> + <%t Blog.By "by" %> + <% if $Authors %><% loop $Authors %> + $Name.XML<% if not $Last || $Up.AuthorNames %>,<% end_if %> + <% end_loop %><% end_if %> + <% if $AuthorNames %> + $AuthorNames + <% end_if %> + <% end_if %>

diff --git a/tests/BlogPostFilterTest.php b/tests/BlogPostFilterTest.php index 8ef694d..d66236f 100755 --- a/tests/BlogPostFilterTest.php +++ b/tests/BlogPostFilterTest.php @@ -18,11 +18,13 @@ class BlogPostFilterTest extends SapphireTest { $member = Member::currentUser(); if($member) $member->logout(); - $count = BlogPost::get()->count(); + $blog = $this->objFromFixture('Blog', 'firstblog'); + + $count = $blog->AllChildren()->Count(); $this->assertEquals(3, $count, "Filtered blog posts"); SS_Datetime::set_mock_now("2020-01-01 00:00:00"); - $count = BlogPost::get()->count(); + $count = $blog->AllChildren()->Count(); $this->assertEquals(5, $count, "Unfiltered blog posts"); } diff --git a/tests/BlogTest.php b/tests/BlogTest.php index b26c037..a9e32f1 100755 --- a/tests/BlogTest.php +++ b/tests/BlogTest.php @@ -98,4 +98,65 @@ class BlogTest extends SapphireTest { } + public function testRoles() { + $blog = $this->objFromFixture('Blog', 'fourthblog'); + $blog2 = $this->objFromFixture('Blog', 'firstblog'); + $postA = $this->objFromFixture('BlogPost', 'post-a'); + $postB = $this->objFromFixture('BlogPost', 'post-b'); + $postC = $this->objFromFixture('BlogPost', 'post-c'); + $editor = $this->objFromFixture('Member', 'blogeditor'); + $writer = $this->objFromFixture('Member', 'writer'); + $contributor = $this->objFromFixture('Member', 'contributor'); + $visitor = $this->objFromFixture('Member', 'visitor'); + + // Check that editors have all permissions on their own blog + $this->assertTrue($blog->canEdit($editor)); + Debug::dump($blog2->Editors()->count()); + $this->assertFalse($blog2->canEdit($editor)); + $this->assertTrue($blog->canAddChildren($editor)); + $this->assertFalse($blog2->canAddChildren($editor)); + $this->assertTrue($postA->canEdit($editor)); + $this->assertTrue($postB->canEdit($editor)); + $this->assertTrue($postC->canEdit($editor)); + $this->assertTrue($postA->canPublish($editor)); + $this->assertTrue($postB->canPublish($editor)); + $this->assertTrue($postC->canPublish($editor)); + + // check rights of writers + $this->assertFalse($blog->canEdit($writer)); + $this->assertFalse($blog2->canEdit($writer)); + $this->assertTrue($blog->canAddChildren($writer)); + $this->assertFalse($blog2->canAddChildren($writer)); + $this->assertTrue($postA->canEdit($writer)); + $this->assertFalse($postB->canEdit($writer)); + $this->assertTrue($postC->canEdit($writer)); + $this->assertTrue($postA->canPublish($writer)); + $this->assertFalse($postB->canPublish($writer)); + $this->assertTrue($postC->canPublish($writer)); + + // Check rights of contributors + $this->assertFalse($blog->canEdit($contributor)); + $this->assertFalse($blog2->canEdit($contributor)); + $this->assertTrue($blog->canAddChildren($contributor)); + $this->assertFalse($blog2->canAddChildren($contributor)); + $this->assertTrue($postA->canEdit($contributor)); + $this->assertFalse($postB->canEdit($contributor)); + $this->assertTrue($postC->canEdit($contributor)); + $this->assertFalse($postA->canPublish($contributor)); + $this->assertFalse($postB->canPublish($contributor)); + $this->assertFalse($postC->canPublish($contributor)); + + // Check rights of non-cms user + $this->assertFalse($blog->canEdit($visitor)); + $this->assertFalse($blog2->canEdit($visitor)); + $this->assertFalse($blog->canAddChildren($visitor)); + $this->assertFalse($blog2->canAddChildren($visitor)); + $this->assertFalse($postA->canEdit($visitor)); + $this->assertFalse($postB->canEdit($visitor)); + $this->assertFalse($postC->canEdit($visitor)); + $this->assertFalse($postA->canPublish($visitor)); + $this->assertFalse($postB->canPublish($visitor)); + $this->assertFalse($postC->canPublish($visitor)); + } + } \ No newline at end of file diff --git a/tests/blog.yml b/tests/blog.yml index 60c3216..7defbc8 100755 --- a/tests/blog.yml +++ b/tests/blog.yml @@ -6,6 +6,9 @@ Group: Title: Administrators editors: Title: Editors + blog-users: + Title: Blog Users + Code: blog-users Permission: admins: @@ -14,6 +17,17 @@ Permission: editors: Code: CMS_ACCESS_CMSMain Group: =>Group.editors + blog-users: + Code: CMS_ACCESS_CMSMain + Group: =>Group.blog-users + + +SiteConfig: + default: + CanEditType: 'OnlyTheseUsers' + CanCreateTopLevelType: 'OnlyTheseUsers' + EditorGroups: =>Group.admins,=>Group.editors + CreateTopLevelGroups: =>Group.admins,=>Group.editors Member: admin: @@ -24,6 +38,21 @@ Member: FirstName: Test Surname: Editor Groups: =>Group.editors + blogeditor: + FirstName: Blog + Surname: Editor + Groups: =>Group.blog-users + writer: + FirstName: Blog + Surname: Writer + Groups: =>Group.blog-users + contributor: + FirstName: Blog + Surname: Contributor + Groups: =>Group.blog-users + visitor: + FirstName: Blog + Surname: Visitor Blog: firstblog: @@ -38,6 +67,11 @@ Blog: Title: 'Third Blog' CanEditType: 'OnlyTheseUsers' EditorGroups: =>Group.editors + fourthblog: + Title: 'Fourth Blog' + Editors: =>Member.blogeditor + Writers: =>Member.writer + Contributors: =>Member.contributor BlogTag: firsttag: @@ -91,9 +125,26 @@ BlogPost: PublishDate: '2015-01-01 00:00:00' Tags: =>BlogTag.firsttag Categories: =>BlogCategory.firstcategory + Parent: =>Blog.firstblog futurepost2: Title: 'Future Post 2' URLSegment: future-post-2 PublishDate: '2013-11-01 00:00:00' Tags: =>BlogTag.firsttag Categories: =>BlogCategory.firstcategory + Parent: =>Blog.firstblog + post-a: + Title: 'One Post' + PublishDate: '2012-01-09 15:00:00' + Parent: =>Blog.fourthblog + Authors: =>Member.writer,=>Member.contributor + post-b: + Title: 'Second Post' + PublishDate: '2012-01-09 15:00:00' + Parent: =>Blog.fourthblog + Authors: =>Member.blogeditor + post-c: + Title: 'Third Post' + PublishDate: '2012-01-09 15:00:00' + Parent: =>Blog.fourthblog + Authors: =>Member.blogeditor,=>Member.writer,=>Member.contributor