HackerOne users: Testing against this community violates our program's Terms of Service and will result in your bounty being denied.

Anyone know of an addon to ban users from a discussion?

12467

Comments

  • MikeOlsonMikeOlson
    edited July 2017

    Hmmm this is what was saved in the discussion table:

  • R_JR_J Ex-Fanboy Munich Admin

    You can save to the Attributes column whatever you like: simple values or arrays. So there is no need to create a string from out of the arrays. Therefore you don't need $userIDs = "[".implode(',', $userIDs)."]";


    @MikeOlson said:
    I understand that $sender->RequestArgs[0] is the discussionid

    But you only have guessed that :wink:

    Better would be to understand it and looking at Vanillas source code is very helpful here. You are inside of the discussionController...($sender) method. So $sender is a DiscussionController object. Look at the DiscussionController:

    https://github.com/vanilla/vanilla/blob/release/2.3/applications/vanilla/controllers/class.discussioncontroller.php#L14
    It doesn't have a RequestArgs property. But it extends the VanillaController, so we can take a look there:

    https://github.com/vanilla/vanilla/blob/release/2.3/applications/vanilla/controllers/class.vanillacontroller.php#L14
    No RequestArgs here. But this controller extends the "base" controller: Gdn_Controller (base, because every controller extends that one)

    And here in the base controller you will find a clean explanation for "RequestArgs":
    https://github.com/vanilla/vanilla/blob/release/2.3/library/core/class.controller.php#L88-L97

  • R_JR_J Ex-Fanboy Munich Admin

    Why is that column name lower case? It really shouldn't be. What you see in there is a serialized string. It says it has an array with one element (I guess) and that the element is a string with 13 characters: DiscussionBan.

    Something went wrong. Let me check my code and check if you have copied it the right way...

  • R_JR_J Ex-Fanboy Munich Admin

    Oh no, the result of a:1:{s:13:"DiscussionBan";N;} is

    array (
      'DiscussionBan' => NULL,
    );
    

    So everything is correct except for the fact that $userIDs is null when you save it. There is a typo:

                $userIDs = [];
                foreach ($userArray as $name) {
                    $userModel = new UserModel();
                    $user = $userModel->getByUsername($name);
                    $userIDs[] = $user->UserID;
                }
    ...
                $discussionModel->saveToSerializedColumn(
                    'Attributes', // The column name
                    $sender->RequestArgs[0], // You should find out what this is
                    'DiscussionBan', // This serves as a internal key so that we can identify our d
                    $userIds
                );
    

    The last $userIDs has a lower case "d".

  • @R_J said:
    You can save to the Attributes column whatever you like: simple values or arrays. So there is no need to create a string from out of the arrays. Therefore you don't need $userIDs = "[".implode(',', $userIDs)."]";


    @MikeOlson said:
    I understand that $sender->RequestArgs[0] is the discussionid

    But you only have guessed that :wink:

    Better would be to understand it and looking at Vanillas source code is very helpful here. You are inside of the discussionController...($sender) method. So $sender is a DiscussionController object. Look at the DiscussionController:

    https://github.com/vanilla/vanilla/blob/release/2.3/applications/vanilla/controllers/class.discussioncontroller.php#L14
    It doesn't have a RequestArgs property. But it extends the VanillaController, so we can take a look there:

    https://github.com/vanilla/vanilla/blob/release/2.3/applications/vanilla/controllers/class.vanillacontroller.php#L14
    No RequestArgs here. But this controller extends the "base" controller: Gdn_Controller (base, because every controller extends that one)

    And here in the base controller you will find a clean explanation for "RequestArgs":
    https://github.com/vanilla/vanilla/blob/release/2.3/library/core/class.controller.php#L88-L97

    I got that from doing a print_r on it and saw the value.

  • INteresting on how to follow the controllers back.

  • MikeOlsonMikeOlson
    edited July 2017

    @R_J said:
    Oh no, the result of a:1:{s:13:"DiscussionBan";N;} is

    array (
      'DiscussionBan' => NULL,
    );
    

    So everything is correct except for the fact that $userIDs is null when you save it. There is a typo:

                $userIDs = [];
                foreach ($userArray as $name) {
                    $userModel = new UserModel();
                    $user = $userModel->getByUsername($name);
                    $userIDs[] = $user->UserID;
                }
    ...
                $discussionModel->saveToSerializedColumn(
                    'Attributes', // The column name
                    $sender->RequestArgs[0], // You should find out what this is
                    'DiscussionBan', // This serves as a internal key so that we can identify our d
                    $userIds
                );
    

    The last $userIDs has a lower case "d".

    Aha!!! I see it. I think that was the result of intellisense on my editor because at one point I had it with the lower case d and I must have hit return when it had that highlighted. I hate "intelli"sense

  • MikeOlsonMikeOlson
    edited July 2017

    Ok now it is saving: a:1:{s:13:"DiscussionBan";s:7:"[16,19]";}

    That looks right for the users that I selected in the form

  • R_JR_J Ex-Fanboy Munich Admin

    @MikeOlson said:
    INteresting on how to follow the controllers back.

    Reading Vanillas source and investigating in there is the best way to become a plugin author!

  • I will be reviewing this entire thread for quite some time over and over and over again.

  • Ok so one of the first steps I need to do is to populate the text box if there already was people banned from the thread.

    I went looking how to do that in the discussion model but I didn't see how to do that. (In fact I didn't see the save to serialized either)

  • R_JR_J Ex-Fanboy Munich Admin

    @MikeOlson said:
    I will be reviewing this entire thread for quite some time over and over and over again.

    Yes, you really should :wink:

    @MikeOlson said:
    I went looking how to do that in the discussion model

    What is it that you want to populate? A field in the database (class model) or a form field (class form)?

    https://open.vanillaforums.com/discussion/comment/248317/#Comment_248317

  • R_JR_J Ex-Fanboy Munich Admin

    @MikeOlson said:
    I went looking how to do that in the discussion model but I didn't see how to do that. (In fact I didn't see the save to serialized either)

    @MikeOlson said:
    INteresting on how to follow the controllers back.

    This time you have to follow back the DiscussionModels ancestors

  • MikeOlsonMikeOlson
    edited July 2017

    Not sure why this isn't working:

                $DiscussionID = $sender->RequestArgs[0];         
                $DiscussionModel = new DiscussionModel();
            $DiscussionModel->getID($DiscussionID);
            $discussionAttributes = $DiscussionModel->Attributes;
            print_r($discussionAttributes);
    

    If I do print_r($DiscussionModel) I can see all the data for that row in the discussion table.
    Shouldn't $discussionAttributes = $DiscussionModel->Attributes; pull out just the attributes field from that?

  • instead I was able to get the value of the attributes field by using a query:

                $DiscussionID = $sender->RequestArgs[0];         
            $Attributes = Gdn::sql()
               ->select('Attributes')
               ->from('Discussion')
               ->where('DiscussionID',$DiscussionID)
               ->get(); // Now it's a dataset!
            //print_r($Attributes);
    
            foreach ($Attributes->resultArray() as $attribute) {
            // Do something to each user with 1 comment.
            print_r($attribute);
            }
    

    Not sure this is the best method to use and then I need to figure out how to loop through the data

  • R_JR_J Ex-Fanboy Munich Admin

    You need

    @MikeOlson said:
    Not sure why this isn't working:

                $DiscussionID = $sender->RequestArgs[0];         
                $DiscussionModel = new DiscussionModel();
          $DiscussionModel->getID($DiscussionID);
          $discussionAttributes = $DiscussionModel->Attributes;
          print_r($discussionAttributes);
    

    >

    The result of discussionModel->getID is a discussion object. That's what you are looking for. So you would need to use it like that $Discussion = $DiscussionModel->getID($DiscussionID);. Afterwards you have a Discussion object that you holds the information you need.

    If you look at the contents of the $discussion with print_r you would find everything you need.

  • Yeah I did a print_r on $discussion and found that there were like 3 listing for attributes.

  • R_JR_J Ex-Fanboy Munich Admin

    If a discussion has Attributes (not every discussion need to have that information) it is stored as an array.

    Maybe it's time to post your complete code to do some cleaning on it and see what is working and what is missing

  • Here is my class...Where I do not know how to get at the attributes data. While I have done a lot of PHP scripting I am new to object oriented PHP coding.

    <?php
    // Define the plugin:
    $PluginInfo['discussionBan'] = array(
        'Name' => 'Discussion Ban',
        'Description' => 'Grants moderators or permissioned users ability to ban users from specific discussions',
        'Version' => '1.1',
        'RequiredApplications' => array('Vanilla' => '>=2.3'),
        'RequiredTheme' => false,
        'RequiredPlugins' => false,
        'HasLocale' => true,
        'License' => 'GNU GPL2',
        'Author' => "Mike Olson",
        'AuthorUrl' => 'https://open.vanillaforums.com/profile/MikeOlson'
    );
    
    /**
     * Class DiscussionBanPlugin
     *
     * @see http://docs.vanillaforums.com/developers/plugins
     * @see http://docs.vanillaforums.com/developers/plugins/quickstart
     */
    class DiscussionBanPlugin extends Gdn_Plugin {
        public function base_discussionOptions_handler($sender, $args) {
            // If user hasn't moderator permissions, we do not want to edit anything.
            if (!Gdn::session()->checkPermission('Garden.Moderation.Manage')) {
                return;
            }
    
            if (isset($args['DiscussionOptions'])) {
    
            /*
                $args['DiscussionOptions']['discussionBan'] = array(
                    'Label' => t('Ban Users From This Discussion'),
                    'Url' => 'discussion/discussionBan/'.$args['Discussion']->DiscussionID,
                    'Class' => 'Popup'
                );
           */     
                $args['DiscussionOptions']['discussionBan'] = [
                    'Label' => t('Ban User from Discussion'),
                    'Url' => url('discussion/discussionban/'.$args['Discussion']->DiscussionID), 
                    'Class' => 'Popup'
                ];
    
    
            }
        }
    
        /**
         * Add autocomplete.js to every page.
         *
         * @param GardenController $sender Instance of the calling class.
         *
         * @return void.
         */
        public function base_render_before($sender) {
            $sender->addJsFile('jquery.tokeninput.js');
        }
    
        /**
         * Show ban user form and save results to discussion attributes.
         *
         * @param PluginController $sender Instance of the calling class
         *
         * @return void.
         */
        public function discussionController_discussionBan_create($sender) {
            $sender->permission('Garden.Moderation.Manage');
            $sender->Form = new Gdn_Form();
            $sender->setData('Title', t('Ban Users From This Discussion'));
    
            if ($sender->Form->authenticatedPostBack() == false) {
                // This will be run when the view is opened
                //$sender->Form->setValue('UserNames', 'HelloWorld');
    
                $DiscussionID = $sender->RequestArgs[0];         
    
                $DiscussionModel = new DiscussionModel();
                $DiscussionModel->getID($DiscussionID);
                $array = get_object_vars($DiscussionModel);
                print_r($DiscussionModel->data->Attributes);
                // ^^ I do not know how to get at the attributes array
                print_r($array);
    
            } else {
                // This will only be run when the user pressed the button.
                $userNames = $sender->Form->getFormValue('UserNames', false);
                if ($userNames === false) {
                    return;
                }
                //print_r($userNames)."<br /><br />";
                $userArray = explode(',', $userNames);
                //print_r($userArray)."<br /><br />";
                //print_r($sender->RequestArgs[0]);
    
                $userIDs = [];
                foreach ($userArray as $name) {
                    $userModel = new UserModel();
                    $user = $userModel->getByUsername($name);
                    $userIDs[] = $user->UserID;
                }
                //print_r($userIDs);
    
                $userIDs = "[".implode(',', $userIDs)."]"; 
                //print_r($userIDs);
    
    
                $discussionModel = new DiscussionModel(); // Since we want to save to discussion table...
                $discussionModel->saveToSerializedColumn(
                'Attributes', // The column name
                $sender->RequestArgs[0], // You should find out what this is
                'DiscussionBan', // This serves as a internal key so that we can identify our d
                $userIDs
                ); 
    
    
                $sender->informMessage(t("Your changes have been saved."));
            }        
    
            $sender->render('discussionBan', '', 'plugins/discussionBan');
    
        }
    }
    
    

    Here is my view...

    <?php if (!defined('APPLICATION')) exit(); ?>
    
    
    <h1><?php echo $this->data('Title') ?></h1>
    <div class="FormWrapper DiscussionBan">
        <?php
        echo $this->Form->open();
        echo $this->Form->errors();
        ?>
    
        <ul>
            <li>
                <?php
                echo $this->Form->label('Users to ban', 'UserNames');
                echo wrap(
                    $this->Form->textBox('UserNames', array('class' => 'InputBox MultiComplete')),
                    'div',
                    array('class' => 'TextBoxWrapper')
                );
                ?>
            </li>
        </ul>
    
        <?php
        echo $this->Form->close('Ban Users');
    
        /*
    
            $discussionModel = new DiscussionModel(); // Since we want to save to discussion table...
        $discussionModel->saveToSerializedColumn(
        'Attributes', // The column name
        $sender->RequestArgs[0], // You should find out what this is
        'DiscussionBan', // This serves as a internal key so that we can identify our d
        [1,2,3,4,5]
    ); 
    
    */
        ?>
    
    
    </div>
    <script>
    jQuery(document).ready(function($) {
       $.fn.userTokenInput = function() {
          $(this).each(function() {
             /// Author tag token input.
               var $author = $(this);
    
               var author = $author.val();
               if (author && author.length) {
                   author = author.split(",");
                   for (i = 0; i < author.length; i++) {
                       author[i] = { id: i, name: author[i] };
                   }
               } else {
                   author = [];
               }
    
               $author.tokenInput(gdn.url('/user/tagsearch'), {
                   hintText: gdn.definition("TagHint", "Start to type..."),
                   tokenValue: 'name',
                   searchingText: '', // search text gives flickery ux, don't like
                   searchDelay: 300,
                   minChars: 1,
                   zindex: 9999,
                   prePopulate: author,
                   animateDropdown: false
               });
          });
       };
    
       $('.MultiComplete').userTokenInput();
    });
    </script>
    
  • R_JR_J Ex-Fanboy Munich Admin
    edited July 2017

    Alright, here is the plugin with a few changes:
    1. added 'MobileFriendly' => true, to PluginInfo array so that your plugin would also be available on mobile browsers
    2. I understood that you have a problem with the short array notation: only using [1,2,3] instead of array(1,2,3) isn't working for you. You should update your PHP version! I've deleted a comment block from base_discussionOptions_handler
    3. Added docblock to base_discussionOptions_handler
    4. Added some extra blank lines and removed trailing spaces here and there
    5. New line 72 & 73: print discussion attributes
    6. Commente the wrong $userIDs = "[".implode(',', $userIDs)."]";

    <?php
    // Define the plugin:
    $PluginInfo['discussionBan'] = array(
        'Name' => 'Discussion Ban',
        'Description' => 'Grants moderators or permissioned users ability to ban users from specific discussions',
        'Version' => '1.1',
        'RequiredApplications' => array('Vanilla' => '>=2.3'),
        'RequiredTheme' => false,
        'RequiredPlugins' => false,
        'MobileFriendly' => true,
        'HasLocale' => true,
        'License' => 'GNU GPL2',
        'Author' => "Mike Olson",
        'AuthorUrl' => 'https://open.vanillaforums.com/profile/MikeOlson'
    );
    /**
     * Class DiscussionBanPlugin
     *
     * @see http://docs.vanillaforums.com/developers/plugins
     * @see http://docs.vanillaforums.com/developers/plugins/quickstart
     */
    class DiscussionBanPlugin extends Gdn_Plugin {
        /**
         * Add new entry to discussion options.
         *
         * @param GardenController $sender Instance of the calling class.
         * @param mixed $args Event arguments.
         *
         * @return void.
         */
        public function base_discussionOptions_handler($sender, $args) {
            // If user hasn't moderator permissions, we do not want to edit anything.
            if (!Gdn::session()->checkPermission('Garden.Moderation.Manage')) {
                return;
            }
            if (isset($args['DiscussionOptions'])) {
                $args['DiscussionOptions']['discussionBan'] = array(
                    'Label' => t('Ban User from Discussion'),
                    'Url' => 'discussion/discussionBan/'.$args['Discussion']->DiscussionID,
                    'Class' => 'Popup'
                );
            }
        }
    
        /**
         * Add autocomplete.js to every page.
         *
         * @param GardenController $sender Instance of the calling class.
         *
         * @return void.
         */
        public function base_render_before($sender) {
            $sender->addJsFile('jquery.tokeninput.js');
        }
    
        /**
         * Show ban user form and save results to discussion attributes.
         *
         * @param PluginController $sender Instance of the calling class
         *
         * @return void.
         */
        public function discussionController_discussionBan_create($sender) {
            $sender->permission('Garden.Moderation.Manage');
            $sender->Form = new Gdn_Form();
            $sender->setData('Title', t('Ban Users From This Discussion'));
            if ($sender->Form->authenticatedPostBack() == false) {
                // This will be run when the view is opened
                //$sender->Form->setValue('UserNames', 'HelloWorld');
                $DiscussionID = $sender->RequestArgs[0];
                $DiscussionModel = new DiscussionModel();
                $Discussion = $DiscussionModel->getID($DiscussionID);
                print_r($Discussion->Attributes);
            } else {
                // This will only be run when the user pressed the button.
                $userNames = $sender->Form->getFormValue('UserNames', false);
                if ($userNames === false) {
                    return;
                }
                //print_r($userNames)."<br /><br />";
                $userArray = explode(',', $userNames);
                //print_r($userArray)."<br /><br />";
                //print_r($sender->RequestArgs[0]);
                $userIDs = [];
                foreach ($userArray as $name) {
                    $userModel = new UserModel();
                    $user = $userModel->getByUsername($name);
                    $userIDs[] = $user->UserID;
                }
                //print_r($userIDs);
                // wrong: $userIDs = "[".implode(',', $userIDs)."]";
                //print_r($userIDs);
                $discussionModel = new DiscussionModel(); // Since we want to save to discussion table...
                $discussionModel->saveToSerializedColumn(
                    'Attributes', // The column name
                    $sender->RequestArgs[0], // Holds the discussion ID
                    'DiscussionBan', // Internal key
                    $userIDs
                );
                $sender->informMessage(t("Your changes have been saved."));
            }
            $sender->render('discussionBan', '', 'plugins/discussionBan');
        }
    }
    

    I will give some explanation on that - give me some time...

Sign In or Register to comment.