Adriano Faria Posted November 16, 2015 Posted November 16, 2015 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: 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.
Mark Posted November 16, 2015 Posted November 16, 2015 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;
Adriano Faria Posted November 16, 2015 Author Posted November 16, 2015 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: 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 ); Something on my return?
Mark Posted November 16, 2015 Posted November 16, 2015 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.
Ali Majrashi Posted November 16, 2015 Posted November 16, 2015 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; } }
Kevin Carwile Posted November 17, 2015 Posted November 17, 2015 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.
Ali Majrashi Posted November 17, 2015 Posted November 17, 2015 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? ?
Ali Majrashi Posted November 17, 2015 Posted November 17, 2015 //<?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
Ali Majrashi Posted November 17, 2015 Posted November 17, 2015 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
Kevin Carwile Posted November 17, 2015 Posted November 17, 2015 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.
TSP Posted November 17, 2015 Posted November 17, 2015 To be fair though, shouldn't passing along the member object to createItem work here?
Ali Majrashi Posted November 17, 2015 Posted November 17, 2015 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
Adriano Faria Posted November 18, 2015 Author Posted November 18, 2015 Thank you, @Ali Majrashi but I can't use on processForm, because this will create the article in loggedin user name then will change the author. The problem here is that this will fire notifications in name of the loggedin user name, not the other author. I'll try to debug a litte more.
eden buganim Posted November 24, 2015 Posted November 24, 2015 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?
Kevin Carwile Posted November 24, 2015 Posted November 24, 2015 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.
eden buganim Posted November 24, 2015 Posted November 24, 2015 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...
Adriano Faria Posted January 1, 2016 Author Posted January 1, 2016 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.
Recommended Posts
Archived
This topic is now archived and is closed to further replies.