Jump to content

Restricting permissions on a specific page


jmart
 Share

Recommended Posts

I am new to PW.

For top level pages like Home, About, Contact, etc., and on specific pages like /contact/thank-you, I want to restrict my client from deleting or moving those pages. This is so that I can preserve the site structure and keep my client from breaking the site. I still want my client to be able to edit the pages, just not delete or move them. For a page under the top level, e.g. /about/mission-statement, the client can do whatever he/she wants. It would also be great to specify that a certain page cannot be edited or deleted except by the super user.

Without creating and maintaing separate templates for these top level pages (assuming that they are basic pages that use the same fields), what is a good a method to restrict the client? Can I create a module with a hook? Or is there an inherent core or contributed module that can handle this? Or do I need to create separate templates?

Also, is there a way to restrict clients from deleting pages that have children?

Link to comment
Share on other sites

From reading about Page Edit Per User, it doesn't sound exactly like what I need.

Let me bullet point my requirements:

  • Client can create/edit/delete/move a "Basic Page" template
  • Superuser can flag a specific "Basic Page" page (or any other page type) as:
    • Either editable or not
    • Either moveable or not
    • Either deletable or not
  • Reasoning
    • Client can create all the basic page he wants
    • But there are some pages he just can't do certain things to like:
      • I don't want him deleting a top level about page because it would ruin
        • the design
        • the site structure
        • URL structure
        • Section specific CSS styling, code, php includes, etc.
      • I don't want him moving a page from the top level for the same reasons
      • I don't want him editing a certain page that I did a lot of custom layout for
      • I don't want him deleting a page that a lot of code is dependent on that page existing
  • I don't necessarily want to build separate template files for top level pages
  • I don't want to assign which pages a client has CRUD rights to because he should be allowed to CRUD new child pages at will.
  • I would be happy with any solution, whether it can be done using an admin panel or if I have to hard code certain page id(s) as being restricted.
Link to comment
Share on other sites

Without creating and maintaing separate templates for these top level pages (assuming that they are basic pages that use the same fields), what is a good a method to restrict the client?

Templates are the recommend way to manage access. While you can accomplish almost anything with this access control, sometimes you can find a more specific way better for your own needs by using PW's access control hooks. The most common being: Page::editable and Page::viewable. However, if you really are talking about only 4 section pages, I would save yourself the trouble and use the built-in recommend method with access control templates. Locking the section pages for edits (like Soma mentioned) is also a good way to keep them from modifying them outside of template access control. If the user doesn't have page-lock permission, then they won't be able to unlock the locked pages. If you ultimately decide you want the fine-grained control of access control hooks, let us know and we can post an example or two to get you started. 

Link to comment
Share on other sites

Hi Ryan and Soma and Dave, thanks for getting back to me.

In the Edit Template for Basic Page under Access, I see the following permissions:

  • View Pages
  • Edit Pages
  • Create Pages
  • Add Children

Ideally it would be great if there were two other permissions:

  • Delete Pages
  • Move Pages

I would think that "Delete Pages" would already be there. Perhaps I'm missing a setting somewhere.

Locking the template seems to lock the client out of edits. But I want to allow him to edit the page, just not delete the page.

But barring a new release of PW with my wishlist of new permissions, perhaps I could write a module where at least I could hard code these permissions for certain page ids. Restricting Deletion while allowing Edits would be crucial. Restricting a page so that it cannot be moved is a "nice to have".

A lot of my requirements are on a page by page basis where it would be nice to mark a certain basic page as "un-deletable" or "un-moveable" while keeping the same template for other pages where the client would have free reign.

If you could help get me started, I would appreciate it.

  • Like 1
Link to comment
Share on other sites

Still not seeing it built into core.

Please tell me how I can setup a role called "client" who:

  • can edit a page of template "top-level-page"
  • cannot delete a page of template "top-level-page"
  • but can edit and delete pages of template "basic-page", "faq", "event", etc.
Link to comment
Share on other sites

have.more then 1 role a user may

diffrent permissions a role.may have

diffrent templates.a role.may be in

much.have u learnt. ready u are

Hi WillyC, I try to answer in your language:

once.need feature.this i

will.do u said

much.will learn. ready i then

:).great

  • Like 1
Link to comment
Share on other sites

can edit a page of template "top-level-page"
cannot delete a page of template "top-level-page"

Create a role called "top-level-editor" (or whatever you prefer). Give that role edit permission, but not delete permission. If you want the role to be able to sort children of these top level pages, then you'll want to assign page-sort permission to the role as well. Assign that role to the template used by your top level page(s). 

but can edit and delete pages of template "basic-page", "faq", "event", etc.

Create another role. We'll just call it "editor". Give that role edit, delete, move and sort permission. Assign that role to the templates indicated, but not the templates where you assigned top-level-editor. 

Don't forget to assign both of these roles "top-level-editor" and "editor" to your user(s) that you want to have this access. I think this was the part WillyC was trying to communicate. 

  • Like 3
Link to comment
Share on other sites

Thanks Ryan, Willy, et al...

I'm sorry if I'm beating a dead horse here. But setting up extra roles and templates just so that I can mark certain pages as un-deletable or un-editable or un-moveable seems like overkill. The reason being is if we start using PW, we will be using it on about 5-10 sites a month. We do a lot of business. And we just need to do this once per site for a few pages.

Perhaps it would be easier if I could hardcode certain page ids as un-deletable or un-editable or un-moveable using a module. I don't know enough about the hook system. But the logic is:

$do_not_delete_array = array(101,150,151);

if(in_array($page->id,$do_not_delete_array)){

//display error - We're sorry. This page can not be deleted

return false;

}else{

//process a normal delete

}

Link to comment
Share on other sites

Hi jmart,

You could go with an autoload module that hooks into Pages::___delete()

I'd write the array with the id's in /site/config.php

This is just an example - not tested. Maybe there exists more elegant solutions?

//... in your autoload module

public function init() {
  $this->pages->addHookBefore('delete', $this, 'checkDelete');
}

public funciton checkDelete($event) {
  $page = $event->arguments[0];
  $id = $page->id;
  if (in_array($id, $this->config->doNotDeleteArray)) {
    throw new WireException("Sorry but you can't delete this page!");
  }
}
  • Like 1
Link to comment
Share on other sites

See also this thread with hooks for page access rights: http://processwire.com/talk/topic/371-page-specific-permissions

There's a PagePermission.module that has all the permission hooks set for reference you might look in there.

All permission hook:

$this->addHook('Page::editable', $this, 'editable'); 
$this->addHook('Page::publishable', $this, 'publishable'); 
$this->addHook('Page::viewable', $this, 'viewable'); 
$this->addHook('Page::listable', $this, 'listable'); 
$this->addHook('Page::deleteable', $this, 'deleteable'); 
$this->addHook('Page::addable', $this, 'addable'); 
$this->addHook('Page::moveable', $this, 'moveable'); 
$this->addHook('Page::sortable', $this, 'sortable');

So most simple and basic delete module would be an autoload module as Wanze mentioned.

//...

public function init() {
    $this->addHook('Page::deleteable', $this, 'deleteable');
}
public function deleteable(HookEvent $event){
    $page = $event->object;
    if($page->id == 1001) {
        $event->return = false;
    }
}

So if on page with id 1001, there would be no delete function. $event->return should either be false or true and you can do all sorts of checks, for roles, users, permission, shoe sizes...

  • Like 4
Link to comment
Share on other sites

  • 1 year later...
hi,

i just want to get deeper in one thing here.

what if i want that a certain user is for example not able to see a Page ?

in my example we have some editors who should only be able to see their part of content (for security reasons)

also they should not be able to edit the content of others

(which should be set and done if they cannot even see the others content)

example:

susi: content -> news -> security

sarah : content -> news -> banking

mark : content -> news -> online-help

all these editors put their content pages into :

content->news->"their part"->article 1 , article 2 ,article 3 and so on

i hope someone is going to read this :)

could really need an answer.

edit:

on the other hand letting the user start in a subdirectory after login would solve the issue aswell (in this case)

Link to comment
Share on other sites

okay i found a way to more or less execute this.

if i hook myself before

ProcessPageList ___execute and overwrite id into the id the user should only see.

public function ___execute() {

		$langID = (int) $this->wire('input')->get->lang; 
		if($langID) $this->wire('user')->language = $this->languages->get($langID);

                //overwriting $_GET['id'] with the id i will put into his useraccount
		if(!$this->id) $this->id = isset($_GET['id']) ? (int) $_GET['id'] : 0; 
		$this->openPage = $this->input->get->open ? $this->pages->get((int) $this->input->get->open) : new NullPage();
		$this->page = $this->pages->get("id=" . ($this->id ? $this->id : 1) . ", status<" . Page::statusMax); 

		if(!$this->page) throw new Wire404Exception("Unable to load page {$this->id}"); 
		if(!$this->page->listable()) throw new WirePermissionException("You don't have access to list page {$this->page->url}"); 
		$this->page->setOutputFormatting(false); 

		// ensure that we use the page's title is always consistent in the admin (i.e. 'Pages' not 'Page List')
		$p = wire('page'); 
		if($p->name == 'list' && $p->process == $this) $p->title = $p->parent->title; 

		return $this->render();

	}	
 

i would have the opportunity to get somewhat of an result what i want.

what wont be solved is a szenario i do not have, but could happen.
for example:

susi should be able to edit not only: susi: content -> news -> security

but also content -> history

but now to something diffrent i will run into somewhat of an error.

if i overwrite id to lock the user into a childpage i am not able to use "open" anymore.

this is what i get when i use id on my "new" root and open for a child of this id:

http://myadress.com/processwire/page/?id=1054&open=1055

esezxt.png

someone halp  ? :-\

P.s.: sorry if its hard to read

  • Like 1
Link to comment
Share on other sites

There is a plugin for at least restrict the edits per user. Not sure if you can hide the rest, too: 

http://modules.processwire.com/modules/page-edit-per-role/

or https://processwire.com/talk/topic/2141-module-page-edit-per-user/

or http://modules.processwire.com/modules/custom-page-roles/

You probably have to read the description of them or try them and then decide which one fits our needs the best.

  • Like 1
Link to comment
Share on other sites

sooooo,

maybe this is overkill or totally Wrong but i got it to work.

offcourse in a module as it should :)

if someone needs this feel free to use:

<?php
/**
 * Created by PhpStorm.
 * User: Blackeye1987
 * Date: 04.08.14
 * Time: 10:09
 */

class CustomStartpoint extends WireData implements Module, ConfigurableModule {

	public static function getModuleInfo() {

		return array(

			'title' => 'CustomStartpoint',
			'version' => 100,
			'summary' => "Access Startpoint for Users *needs (type:page | single page or boolean | Input field type PageListSelect+) set to user template* *Consider Taking in Account using ALSO ryancramers PageEditPerUser.module for extended User Control -> https://github.com/ryancramerdesign/PageEditPerUser/",
			'href' => '',
			'singular' => true,
			'autoload' => true,
		);
	}

	public static function getModuleConfigInputfields(array $data){
		$inputfields = new InputfieldWrapper();

		$field = wire('modules')->get('InputfieldSelect');
		$field->attr('name', 'startpoint_field');
		$field->label = __('Starting Point');

		$uT = wire('templates')->get('user');
		$fL = $uT->fields;

		foreach($fL as $f){
			$field->addOption($f->name,$f->name);
		}

		//set your named custom field for the startingpoint of the user
		$field->attr('value', isset($data['startpoint_field']) ? $data['startpoint_field'] : '');
		$inputfields->add($field);

		return $inputfields;
	}

	public function init() {

		$this->addHookBefore('ProcessPageList::execute', $this, 'startpoint');
	}

	public function startpoint($event){
		$page = $event->arguments[0];
		//startpoint page
		$sp_p = $this->get('startpoint_field');
		$id = $this->user->get($sp_p)->id;

		//if no page is set run normally
		if(!$this->user->get($sp_p)){
	            return;
		}

		if(!isset($_GET['id'])){
			$_GET['id'] = $id;
		}

		//if user tries to overwrite id, still edit needs to be allowed
		//--can be handled through ryans module!
		//do not allow them to edit the pages and you are done
		if($_GET['id'] != $id && !strpos($_SERVER['REQUEST_URI'],'/page/edit/') > 0){
			$this->message(__('You are not allowed here'));
			return;
		}

		//bugfix pw ?
		//open needs to be removed because:
		//if open is a childid of id, id will be opened twice (why ?)
		unset($_GET['open']);
		$_GET['id'] = $id;
		if(strpos($_SERVER['REQUEST_URI'],'open=') > 0){
			$this->session->redirect(substr($_SERVER['REQUEST_URI'],0,strpos($_SERVER['REQUEST_URI'],'open=')));
		}
		return;
	}

}

readme:

1: Create new Field :

type: Page

Details (Single Page or boolean)

Input: Select Parent (Home is fine because as admin you set this Value)

Input: Input field type PageListSelect

2. Assign to UserTemplate

3. Set Startingpoint for the User who needs the Startingpoint

4. Login with User who should now have a Startingpoint

5. Wish me Luck no one will kill me for this Code :D

if anyone wants to proof read the code or has any questions or suggested improvements, just reply.

  • Like 2
Link to comment
Share on other sites

in the beginning me neither got the idea when i edited a page, so i tried it ! 

on the other hand i want everyone to know, i didn't made any security checks because other modules do this already.

i could have integrated them, but i think the original content would be better in use (in case of updates aswell)

so what you should use is:

somas HideSettings.module (couldn't find it as module but in the forum)

ryans PageEditPerUser.module (url : https://github.com/ryancramerdesign/PageEditPerUser/)

with those 3 in combination everything should be set and done and the user shouldn't be able to "fool around"

  • Like 2
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...