Jump to content

Change article author via hook


Adriano Faria

Recommended Posts

Posted

HI there.

I have a plugin that mimics the Promote to Article feature from IP.Content. It works fine but someone requested to article author to be the same user who made the post or give the option to the user choose. So I added a select on article posting screen listing the post author and the loggedIn member:

Capturar.PNG.7886eaa697ea817ec80d092d56d

The author saved is always the loggedIn member. I've already tried:

	/**
	 * Process created object AFTER the object has been created
	 *
	 * @param	\IPS\Content\Comment|NULL	$comment	The first comment
	 * @param	array						$values		Values from form
	 * @return	void
	 */
	protected function processBeforeCreate( $values )
	{
		if ( isset( \IPS\Request::i()->pid ) AND \IPS\Request::i()->pid AND \IPS\cms\Databases\Dispatcher::i()->databaseId == \IPS\Settings::i()->ppa_db )
		{
			$this->member_id = $values['new_author'];
		}

		/* Run parent */
		parent::processBeforeCreate( $values );
	}

Also tried:

	public static function createItem( \IPS\Member $author, $ipAddress, \IPS\DateTime $time, \IPS\Node\Model $container = NULL, $hidden=NULL )
	{
		if ( isset( \IPS\Request::i()->pid ) and \IPS\Request::i()->pid AND \IPS\Request::i()->new_author != \IPS\Member::loggedIn()->member_id /*AND \IPS\Dispatcher::i()->application->directory == 'cms' AND \IPS\Dispatcher::i()->module->key == 'pages' AND \IPS\Dispatcher::i()->controller == 'page'*/ )
		{
			$author	= \IPS\Member::load( \IPS\Request::i()->new_author );
		}

		return parent::createItem( $author, $ipAddress, $time, $container, $hidden );
	}

Am I doing something wrong ?

Tks.

Posted

The createItem() override should be working. I'd start by dropping something like this in the top of that override to see what you're getting:

echo '<pre>';
print_r( \IPS\Request::i() );
exit;

 

Posted
32 minutes ago, Mark said:

The createItem() override should be working. I'd start by dropping something like this in the top of that override to see what you're getting:

Yes, already tried that. Both conditions are there:

Capturar.png

			if ( isset( \IPS\Request::i()->pid ) and \IPS\Request::i()->pid AND \IPS\Request::i()->new_author != \IPS\Member::loggedIn()->member_id )
			{
				$author	= \IPS\Member::load( \IPS\Request::i()->new_author );
			}

			return parent::createItem( $author, $ipAddress, $time, $container, $hidden );

pid is set and pid = 9 and new_author (2) is different than the loggedIn member (1).

Not sure why it doesn't work.

Also tried this:

			if ( isset( \IPS\Request::i()->pid ) and \IPS\Request::i()->pid AND \IPS\Request::i()->new_author != \IPS\Member::loggedIn()->member_id /*AND \IPS\Dispatcher::i()->application->directory == 'cms' AND \IPS\Dispatcher::i()->module->key == 'pages' AND \IPS\Dispatcher::i()->controller == 'page'*/ )
			{
				echo 'I am right here';exit;
				$author	= \IPS\Member::load( \IPS\Request::i()->new_author );
			}

			return parent::createItem( $author, $ipAddress, $time, $container, $hidden );

Capturar.thumb.PNG.2be23a9afa4a3505177d5

Something on my return?

Posted

The way you're doing it is mostly* right - I can only suggest further debugging. For example, instead of returning, print what is returned by createItem() and see if the value is set correctly there.

 

* The way you're doing it at the moment has a security vulnerability - I could, using web inspector, change the select box to pass the value of any random member ID and create it as them. You should change it so the select box passes a certain value for "logged in member" and a certain value for "author" and have your controller get the actual member based on that - don't allow the passing of an arbitrary ID.

Posted

hello

you need to return $this if you change it to have effect 

this is quick plugin i created for you 

//<?php

class hook118 extends _HOOK_CLASS_
{


	/**
     * Process create/edit form
     *
     * @param	array				$values	Values from form
     * @return	void
     */
	public function processForm( $values )
	{
        call_user_func_array( 'parent::processForm', func_get_args() );
        $this->member_id = 2;
        //die(var_dump($this));
		return $this;
	}

}

 

Posted
8 hours ago, Ali Majrashi said:

hello

you need to return $this if you change it to have effect 

this is quick plugin i created for you 


//<?php

class hook118 extends _HOOK_CLASS_
{


	/**
     * Process create/edit form
     *
     * @param	array				$values	Values from form
     * @return	void
     */
	public function processForm( $values )
	{
        call_user_func_array( 'parent::processForm', func_get_args() );
        $this->member_id = 2;
        //die(var_dump($this));
		return $this;
	}

}

 

What? That is not correct. As you can see from the function definition yourself, the return value is VOID.

Posted
2 hours ago, Kevin Carwile said:

What? That is not correct. As you can see from the function definition yourself, the return value is VOID.

that is one of the dark mystery in IPS4 

according to phpdoc.org

Quote

@return datatype description
@return datatype1|datatype2 description

The @return tag is used to document the return value of functions or methods. @returns is an alias for @return to support tag formats of other automatic documentors

The datatype should be a valid PHP type (int, string, bool, etc), a class name for the type of object returned, or simply "mixed". If you want to explicitly show multiple possible return types, list them pipe-delimited without spaces (e.g. "@return int|string"). If a class name is used as the datatype in the @return tag, phpDocumentor will automatically create a link to that class's documentation. In addition, if a function returns multiple possible values, separate them using the | character, and phpDocumentor will parse out any class names in the return value. phpDocumentor will display the optional description unmodified.

also return void is valid only if your method do not use the return key to return any thing

http://www.phpdoc.org/docs/latest/guides/types.html#keywords

<?php

/**
 * @return void
 */
function bar() {
    echo "bar";
}

so the processForm method accept $values and process them but if you hook into it you will also accept the $value to process them or return them to be processed by the parent method in this case i think we need to update our DocBlock

the reason i returned object here is to preserve the changed value of the memebr_id property so it will be processed by the parent method correctly you can hook into any other method as will and it will just work not only processForm 

maybe i misunderstood this can you clarify it for me? ?

Posted
//<?php

class hook118 extends _HOOK_CLASS_
{


	/**
     * Process create/edit form
     *
     * @param	array				$values	Values from form
     * @return	void
     */
	public function processForm( $values )
	{
		$this->changed['member_id'] = 2;
		parent::processForm($values);
	}

}

here with void return 

if you check the save() method in Records class you can see they check if the record is new or not to set the member but you can change it easily with altering the changed property you can also try this in any other process methods in the Records class 

Posted

the reason why it did not work for Adriano because in the processForm method in the Records class check if the record is new it set the member id to the loggedin user

if ( $this->_new )
		{
			/* Set the author ID on 'new' only */
			$this->member_id = (int) \IPS\Member::loggedIn()->member_id;
		}

so the value of the member_id will be reseted to loggedin user when you run the parent::method 

Posted

You're talking crazy. The processForm method return value is not used for anything. Returning a value has no effect. Any changes to properties of $this happen by reference and are immediate.

33 minutes ago, Ali Majrashi said:

the reason why it did not work for Adriano because in the processForm method in the Records class check if the record is new it set the member id to the loggedin user

Simply call parent::processForm( $values ) in your hook before setting the member_id on the object yourself to solve that problem.

Posted
7 hours ago, Kevin Carwile said:

You're talking crazy. The processForm method return value is not used for anything. Returning a value has no effect. Any changes to properties of $this happen by reference and are immediate.

Simply call parent::processForm( $values ) in your hook before setting the member_id on the object yourself to solve that problem.

my bad >_< i thought if we use the rturn key it should alwayes return valid data type but now it's clear thank you 

/**
     * Process create/edit form
     *
     * @param	array				$values	Values from form
     * @return	void
     */
	public function processForm( $values )
	{
		parent::processForm($values);
		$this->member_id = 2;

	}

and this also works fine thank you i need to get some sleep i knew that the member id will reset to logged-in member but i forget to run the parent::method before my code :p

Posted
3 hours ago, eden buganim said:

Wouldn't it be possible to hook onto the \IPS\Member::loggedIn() method, check for \IPS\Request::i()->new_author, load THAT user and return it?

That would allow any person to use the site as any other member just by adding a member id to the url. Including admin users and moderators.

Posted
6 hours ago, Kevin Carwile said:

That would allow any person to use the site as any other member just by adding a member id to the url. Including admin users and moderators.

I was thinking you could run through URL parameters (like module topic, method create/edit) and check who's actually logged in, then determine whether to send back a member object that is someone else. This should bring us back to the security issue of members being able to post in other members' names.

I recognize the potential problems which could derive from editing the loggedIn method, but the next option is completely overwriting the 'createFromForm' method, for a single line...

  • 1 month later...
Posted

Btw, doing another plugin, I discovered that the \IPS\cms\Records::processForm() was setting the current user as the record author:

		if ( $this->_new )
		{
			/* Set the author ID on 'new' only */
			$this->member_id = (int) \IPS\Member::loggedIn()->member_id;
		}

That's why it wasn't 'saving' my values. Working fine.

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...