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

Ability to show discussion between a certain date?

I want to show a filtered view basically of the discussion page that shows exactly like each discussion does on the discussion page.

So go to the database get all the discussion that fall between this and that date for a certain field. And output them exactly like on the discussion page.

«1

Comments

  • rbrahmsonrbrahmson "You may say I'm a dreamer / But I'm not the only one" NY ✭✭✭

    are you answering your own question?

    Look at the filterdiscussion plugin and the lengthy comment at the top of the source - tells you how to do it with the plugin. Then you can just use the code if you need this inside your own plugin;-)

  • phreakphreak Vanilla*APP (White Label) & Vanilla*Skins Shop MVP

    We have a free plugin which separates the list view by dates.

    Would that be a first step to gain a better UX of the discussion view?

    https://vanillaskins.com/plugins.html#dateSeperator

    • VanillaAPP | iOS & Android App for Vanilla - White label app for Vanilla Forums OS
    • VanillaSkins | Plugins, Themes, Graphics and Custom Development for Vanilla
  • R_JR_J Ex-Fanboy Munich Admin

    @rbrahmson : clever! I would have mimiced the controller logic and reused only the view, but your approach is much more robust, future proof and requires less code.


    Since @MrCaspan doesn't need a flexible solution as you needed in your plugin, Vanillas "new" filters maybe better suited than hooking into the model:


       public function discussionsController_abracadabra_create($sender, $args) {
           // e.g. 2020-02-28 & 2020-02-21
           $today = DateTimeFormatter::timeStampToDate(time());
           $lastWeek = DateTimeFormatter::timeStampToDate(strtotime("{$today} - 1 week"));
    
           // Define some filters.
           $filter = [
               // yourforum.com/discussions/abracadabra?filter=new-events
               'new-events' => [
                   'name' => Gdn::translate('New Events'),
                   'wheres' => [
                       'd.DateInserted >=' => $lastWeek,
                       'd.DateInserted <=' => $today
                   ]
               ],
               // yourforum.com/discussions/abracadabra?filter=upcoming-events
               'upcoming-events' => [
                   'name' => Gdn::translate('Upcoming Events'),
                   'wheres' => [
                       'd.EventCalendarDate >=' => $lastWeek,
                       'd.EventCalendarDate <=' => $today
                   ]
               ]
           ];
           // Add filters to DiscussionModel.
           $discussionModel = GDN::getContainer()->get(DiscussionModel::class);
           foreach ($filter as $key => $value) {
               $discussionModel->addFilter($key, $value['name'], $value['wheres']);
           }
    
           // Only set individual title if filter applies
           $currentFilter = $sender->Request->get('filter');
           if ($filter[$currentFilter]['name'] ?? false) {
               $sender->title($filter[$currentFilter]['name']);
           }
           // Re-use vanillas default "Recent Discussions" view.
           $sender->View = 'index';
           $sender->index($args);
       }
    


    Maybe naming the method "discussionsController_events_create()" and the filters only "new" and "upcoming" would end up in less surprisingly urls... 😀

  • MrCaspanMrCaspan
    edited February 2020

    Yeah basically i want to use the discussion view set by the forum, i just want to filter the dates it shows and show it on my day view of the Events calendar.

    Thanks for all the code and help guys. Ill dig into this today and see what I can do!

    EDIT @R_J This looks like exactly what i am looking for thank you!

  • MrCaspanMrCaspan
    edited February 2020

    So @R_J if I have 3 different views for the EventsPage Year, Month, Day. If the user hits http://forum.com/EventsCalendar/2002 to will go to the year view, http://forum.com/EventsCalendar/2002/02 will go to the month view and http://forum.com/EventsCalendar/2002/02/28 will go to the day view.

    So I don't want to render out the entire view for discussion as I have my own header that I use on the EventsCalender day view but just use the same format that the discussions are formated in but in my day view.. To use literal words

    • Print my control header
    • Take the arguments passed to me on the date to look up IE 2020-02-28 event sin the database that match this
    • Print out using the same format as the discussion page any results found


  • MrCaspanMrCaspan
    edited March 2020

    So i am confused. Should I be calling the discussions view and then filtering it for my Day view. Or should I be doing my own query to the Database and then asking it to use the discussions view to render it.. I am still a bit lost on how I should achieve this. Sorry to bug I'm trying to look at the documentation and other examples but still spinning around my head!

  • This is how I believe it should be done:

    I have a function called  "public function vanillaController_eventCalendar_create($sender, $args = []) {}" this is where I set all my code based on if the user is looking at the Year, Month, Day. If the user is looking at https://forumURL/EventCalendar/2002/02/28 then I render the day.php as they are looking at the day view. So in my vanillaController_eventCalendar_create() function I would need to query the database for the events on the day passed in the argument[2] and then use the discussions view to render out each discussion on that day.

  • R_JR_J Ex-Fanboy Munich Admin

    Correct. The method where month or week information is fetched from db should be extended to fetch day information. You have a view for month and week, now you need to add one for day.

    The discussions view that you see in Recent Discussions is made up of several parts. Look at applications\vanilla\views\discussions\index.php

    It includes the "helper_functions.php" from the same folder and in that helper functions are small bits like "writeDiscussion". You can try to read that index.php and fetch only what you need for your day view from the helper functions.

    That might work, but maybe the CSS rules will not apply to your page. You would have to test that.

  • okay thanks!

  • R_JR_J Ex-Fanboy Munich Admin

    by the way: the code will become much cleaner if you make vanillaController_eventCalendar_create() a dispatcher and route it to some dedicated calendarDay, calendarMonth, calendarWeek methods.

  • Thanks @R_J I will clean it up once i am done as right now i am doing it all in a case statement in that function. I will break it out after for now I want to just get this code running and also understand it :)

    This is the code i have in the day view

    <?php if (!defined('APPLICATION')) exit();
    
    // This will load in the writeDiscussion helper
    include_once $this->fetchViewLocation('helper_functions', 'discussions', 'vanilla');
    
    // Loop around or data and print out each result
    foreach ($this->DiscussionData->result() as $Discussion) {
      writeDiscussion($Discussion, $this, $Session);
    }
    
    ?>
    
    
    

    It would just seem that I need to populate the DiscussionData object with data from the database? I am not sure how I would do that

  • NM i think i got it I created this function and passed it a date object, and it returned a SQL Result Object

        public function getDay(object $Date) {
    
    
            $sql = Gdn::sql();
            $sql->select('*')
    			->Distinct()
                ->from('Discussion')
                ->where('EventCalendarDate =', $Date->format('Y-m-d'))
                ->orderBy('EventCalendarDate');
    
    
            // add permission restrictions if necessary 
            $perms = DiscussionModel::categoryPermissions();
            if ($perms !== true) {
                $sql->whereIn('CategoryID', $perms);
            }
    
    
            // return $Sql->GetSelect();
            return $sql->get();
       }
    

    I then passed this SQLResult Object to my day.php and looped around it using the writeDiscussion() function.... I just spit out my data :) now i just need to make it look like the rest of the discussion views. I think I just need to load the CSS file

  • MrCaspanMrCaspan
    edited March 2020

    Wow this is so confusing to me.. LOL Okay so I think I got what i need from the database and I apply it against the Discussion view and I spit all my data out... It looks great one problem... all the links are messed up

    If i hover over the links for the forum posts it seems that they all are referencing the page i am on and not the actual pages all the other links are good. If you look at the screenshot all the links in Green work but the main link (in red) just adds #latest to the current page URL! Should I be passing a variable that it is missing to this location?



  • It would seem that this code is it in table_functions();

     $discussionUrl = $discussion->Url;
        if ($session->UserID) {
          $discussionUrl .= '#latest';
        }
    

    After I am doing my SQL query would I have to build this Url parameter for each Discussion?

  • Seems there is a calculate function in class.dicussionmodel.php

    it does some setting of data in there...


        // Fix up output
        $discussion->Name = htmlspecialchars($discussion->Name);
        $discussion->Attributes = dbdecode($discussion->Attributes);
        $discussion->Url = discussionUrl($discussion);
        $discussion->CanonicalUrl = $discussion->Attributes['CanonicalUrl'] ?? $discussion->Url;
        $discussion->Tags = $this->formatTags($discussion->Tags);
    
  • R_JR_J Ex-Fanboy Munich Admin

    If you re-use the discussions view, that piece of code should be responsible for the link:


       function writeDiscussion($discussion, $sender, $session) {
           $cssClass = cssClass($discussion);
           $discussionUrl = $discussion->Url;
    ...
               <div class="ItemContent Discussion">
                   <div class="Title" role="heading" aria-level="3">
                       <?php
                       echo adminCheck($discussion, ['', ' ']).anchor($discussionName, $discussionUrl);
                       $sender->fireEvent('AfterDiscussionTitle');
                       ?>
                   </div>
    
    

    You can forget about the "#latest", it just redirects a logged in user to the first unread comment. Not sure about your code, but you might want to check that the object you pass in (the dataset) has a correct Url property.

  • MrCaspanMrCaspan
    edited March 2020

    Yeah I am reusing the discussion view but in Table format and I want the day view to follow that view option. I think I have it now and I can build this URL for it and pass it to the method/function... I am once done I am going to post the Plugin so that people can pull it apart and tell me what I did wrong LOL Or help improve it... that's how I believe the forum works :)

    This is my first venture into Method based programming and object oriented programming in PHP. I can pick stuff up quick and I feel like I am getting the handle of this but the documentation would help a lot to know what methods are exposed or how to load them into your plugin! I love the way Vanilla works!

  • Okay so to revive an old thread I have added the following to my plugin

    public function discussionsController_events_create($sender, $args) {
    	// /discussions/events/2020/04/04?filter=date
    
    	// Save our passed date arguments
    	$year	= intval($args[0]);
    	$month	= intval($args[1]);
    	$day	= intval($args[2]);
    		
    	// Test it to make sure it's a real date
    	if (checkdate ($month, $day, $year) === true) {
    
    		// now that we know its valid save it in YYYY-MM-DD format
    		$passedDate = $year.'-'.$month.'-'.$day;
    			
    		// Add filters to DiscussionModel.
    		$discussionModel = GDN::getContainer()->get(DiscussionModel::class);
    		$discussionModel->addFilter('date', 'New Events', ['d.EventCalendarDate =' => $passedDate]);
    			
    	} // End of if
    
    	// Set the title
    	$sender->title('Games Calendar');
    		
            // Re-use vanillas default "Recent Discussions" view.
            $sender->View = 'index';
            $sender->index();
       }
    

    This works great other then the UGLY '?filter=date" on the end of the URL... is there a way to do this same thing but not show the filter in the URL address? I want to apply the filter not have to create it then call it via the URL filter parameter

  • R_JR_J Ex-Fanboy Munich Admin

    The code you show above re-uses very much of Vanillas DiscussionsController->index() method. Therefore you cannot simply change the sql it uses to fetch the information from the db. But you are allowed to set filters. What should be possible is to omit the filter in the links, but I assume they will reappear as soon as the page is loaded by Vanilla.


    In the DiscussionsController->index() method there is the following line: $DiscussionModel->setFilters(Gdn::request()->get()); So the filter must be part of the GET request to be applied. But you could add Gdn::request()->setRequestArguments('filter', 'date'); to your code to replace the missing filter from the call.

    But since it is now part of the GET request, Vanilla most probably will make it a part of the url it shows.



    If you ask me, that is micro optimizing. Only web developers take notice of such a part of the url and waste time thinking about it.

    But if you really want it that much you have two options:

    1. Do not reuse that much of Vanilla, but rebuild the index() method of the DiscussionsController. Ugly from a programmers view: DRY
    2. Use another event fired to remove that filter after the data has been fetched, e.g. AfterBuildPager.


    If you go for option 2, you need to a) ensure the RequestMethod is your "events" b) fetch the filters c) clear date filter d) re-apply the filters

  • MrCaspanMrCaspan
    edited April 2020

    We were a bit off on the syntax but gave me enough to figure it out you have to specify the get then pass a key => value to it

    Gdn::request()->setRequestArguments('get', array("filter" => "date"));
    

    This worked like a beauty and did not show up in the address bar!!

    Secondary question to this;

    Because I am reusing the index view of the Discussions class is there a way for me to inject my calendar header to the top of this page?

Sign In or Register to comment.