MyBB Community Forums

Full Version: View Unread Posts
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
Hi Eldenroot,

I've specifically registered here and I'm replying as you've:
- provided me with clue as to 1.1 working nice
- shown big effort to get this plugin working, which is admirable

I really don't comprehend why such good script as myBB has no proper View Unread Posts function, as it is present in all other big scripts that are much less fun to work with (phpBB, IPB etc).
Shame Łukasz backed out, I really don't agree with his point of view on message boards. But it's hard to blame him, really. After all, he did it for free Smile

I think I have the solution (not yet quite sure, but I might be onto something)
It seems that all the problems are coming from timing issue. I've observed that topics and posts are mainly left as unread when you quickly back to previous screen and script has no chance to save the result.

First of all, disable ajax updating as it causes a lot of this issues.
Then replace (in unreadPosts.php):
time(), $time and $newTime (used in 1.3)
with:
TIME_NOW (used in 1.1)

such as in:

mark_thread_read($thread['tid'], $thread['fid'], time());

or

$newTime = time();
self::$readTime = $newTime;
mark_thread_read($post['tid'], $post['fid'], $newTime);

I recommend either using https://www.diffnow.com/compare-clips to compare unreadPosts.php 1.3 vs 1.1 for this change or I could provide you with my file.

I've tested this solution several times, but still have no feedback from larger group of users (I'm waiting for their spam Big Grin). It seems to work. Basically, this is the main difference in 1.1 vs 1.3.
There were no changes in jscript file, tpl - I don't think it's to blame, functions_indicator perhaps - we'll see.

Best regards!
Thank you for your reply!

Unfortunately I cannot test right now, so I cannot provide any helpful feedback.

Anyway I can confirm, that the quick navigation through unread posts make them unread again (do not marke read state properly).

Can you add a modified file to just copy and paste? Let us know, thank you!
hello,

I have changed time() to TIME_NOW in unreadposts.php yesterday. 
I did not changed $time and $newTime, I think, that are only variables filled with time() and after the changes with TIME_NOW...  

This changes are not enough in our forum. We had still the issue with some read posts shown as unread. 
I looked in the other php and in functions_indicators.php I found 2 x time() I have changed them too and now we try it.

hi,

the changes wasn't successfull :-( So I have reloaded the 1.11 now.
I confirm that although it improves things, it is not quite a fix we all need.
Will look for other differences between 1.1 and 1.3 in spare time and if I will come up with something, will let you know and also paste the code.
Yes, agree, thx
Hi

There are a lot of instances of $readTime which serves the same as time() is functions_indicator, I've changed them all with TIME_NOW and also removed $mark_time from:

mark_forum_read($fid, $mark_time);

as it wasn't there in 1.1, just

mark_forum_read($fid);

I think it may be the problem behind marking the posts as read and then they show again as unread.
Anyway, another round of testing I guess to check whether is changes things.
Let us know
Hi again,

I think it finally works. Below code for functions_indicators.php:

<?php
/**
 * MyBB 1.8
 * Copyright 2014 MyBB Group, All Rights Reserved
 *
 * Website: http://www.mybb.com
 * License: http://www.mybb.com/about/license
 *
 */

/**
 * Mark a particular thread as read for the current user.
 *
 * @param int $tid The thread ID
 * @param int $fid The forum ID of the thread
 */
function mark_thread_read($tid, $fid, $mark_time = 0)
{
    global $mybb, $db;

    
    // START - Unread posts MOD
    // Disable mark read if not needed
    if (function_exists("unreadPosts_is_installed") && unreadPosts_is_installed()) {
        // For idiots who can't use hooks
        if (THIS_SCRIPT != 'newreply.php' && THIS_SCRIPT != 'newthread.php' && THIS_SCRIPT != 'showthread.php' && empty($mark_time)) {
            $mark_time = TIME_NOW;
        }
    
        if (!$mark_time || !$mybb->user['uid'] || !$mybb->settings['threadreadcut']) {
            return;
        }

        switch ($db->type) {
            case "pgsql":
            case "sqlite":
                $db->replace_query("threadsread", array('tid' => $tid, 'uid' => $mybb->user['uid'], 'dateline' => $mark_time), array("tid", "uid"));
                break;
            default:
                $db->write_query("
                    REPLACE INTO " . TABLE_PREFIX . "threadsread (tid, uid, dateline)
                    VALUES('$tid', '{$mybb->user['uid']}', '{$mark_time}')
                ");
        }

        $unread_count = fetch_unread_count($fid);
        if ($unread_count == 0) {
            mark_forum_read($fid);
        }
        return;
    }
    // END - Unread posts MOD

    // Can only do "true" tracking for registered users
    if($mybb->settings['threadreadcut'] > 0 && $mybb->user['uid'])
    {
        // For registered users, store the information in the database.
        switch($db->type)
        {
            case "pgsql":
            case "sqlite":
                $db->replace_query("threadsread", array('tid' => $tid, 'uid' => $mybb->user['uid'], 'dateline' => TIME_NOW), array("tid", "uid"));
                break;
            default:
                $db->write_query("
                    REPLACE INTO ".TABLE_PREFIX."threadsread (tid, uid, dateline)
                    VALUES('$tid', '{$mybb->user['uid']}', '".TIME_NOW."')
                ");
        }
    }
    // Default back to cookie marking
    else
    {
        my_set_array_cookie("threadread", $tid, TIME_NOW, -1);
    }

    $unread_count = fetch_unread_count($fid);
    if($unread_count == 0)
    {
        mark_forum_read($fid);
    }
}

/**
 * Fetches the number of unread threads for the current user in a particular forum.
 *
 * @param string $fid The forums (CSV list)
 * @return int The number of unread threads
 */
function fetch_unread_count($fid)
{
    global $cache, $db, $mybb;

    $forums_all = $forums_own = array();
    $forums = explode(',', $fid);
    foreach($forums as $forum)
    {
        $permissions = forum_permissions($forum);
        if(!empty($permissions['canonlyviewownthreads']))
        {
            $forums_own[] = $forum;
        }
        else
        {
            $forums_all[] = $forum;
        }
    }
    if(!empty($forums_own))
    {
        $where = "(fid IN (".implode(',', $forums_own).") AND uid = {$mybb->user['uid']})";
        $where2 = "(t.fid IN (".implode(',', $forums_own).") AND t.uid = {$mybb->user['uid']})";
    }
    if(!empty($forums_all))
    {
        if(isset($where))
        {
            $where = "({$where} OR fid IN (".implode(',', $forums_all)."))";
            $where2 = "({$where2} OR t.fid IN (".implode(',', $forums_all)."))";
        }
        else
        {
            $where = 'fid IN ('.implode(',', $forums_all).')';
            $where2 = 't.fid IN ('.implode(',', $forums_all).')';
        }
    }
    $cutoff = TIME_NOW-$mybb->settings['threadreadcut']*60*60*24;

    if(!empty($permissions['canonlyviewownthreads']))
    {
        $onlyview = " AND uid = '{$mybb->user['uid']}'";
        $onlyview2 = " AND t.uid = '{$mybb->user['uid']}'";
    }

    if($mybb->user['uid'] == 0)
    {
        $comma = '';
        $tids = '';
        $threadsread = $forumsread = array();

        if(isset($mybb->cookies['mybb']['threadread']))
        {
            $threadsread = my_unserialize($mybb->cookies['mybb']['threadread']);
        }
        if(isset($mybb->cookies['mybb']['forumread']))
        {
            $forumsread = my_unserialize($mybb->cookies['mybb']['forumread']);
        }

        if(!empty($threadsread))
        {
            foreach($threadsread as $key => $value)
            {
                $tids .= $comma.(int)$key;
                $comma = ',';
            }
        }

        if(!empty($tids))
        {
            $count = 0;

            // We've read at least some threads, are they here?
            $query = $db->simple_select("threads", "lastpost, tid, fid", "visible=1 AND closed NOT LIKE 'moved|%' AND {$where} AND lastpost > '{$cutoff}'", array("limit" => 100));

            while($thread = $db->fetch_array($query))
            {
                if((!isset($threadsread[$thread['tid']]) || $thread['lastpost'] > (int)$threadsread[$thread['tid']]) && (!isset($forumsread[$thread['fid']]) || $thread['lastpost'] > (int)$forumsread[$thread['fid']]))
                {
                    ++$count;
                }
            }

            return $count;
        }

        // Not read any threads?
        return false;
    }
    else
    {
        // START - Unread posts MOD
        if (function_exists("unreadPosts_is_installed") && unreadPosts_is_installed()) {
            $cutoff = $mybb->user['lastmark'];
        }
        // END - Unread posts MOD
        
        switch($db->type)
        {
            case "pgsql":
                $query = $db->query("
                    SELECT COUNT(t.tid) AS unread_count
                    FROM ".TABLE_PREFIX."threads t
                    LEFT JOIN ".TABLE_PREFIX."threadsread tr ON (tr.tid=t.tid AND tr.uid='{$mybb->user['uid']}')
                    LEFT JOIN ".TABLE_PREFIX."forumsread fr ON (fr.fid=t.fid AND fr.uid='{$mybb->user['uid']}')
                    WHERE t.visible=1 AND t.closed NOT LIKE 'moved|%' AND {$where2} AND t.lastpost > COALESCE(tr.dateline,$cutoff) AND t.lastpost > COALESCE(fr.dateline,$cutoff) AND t.lastpost>$cutoff
                ");
                break;
            default:
                $query = $db->query("
                    SELECT COUNT(t.tid) AS unread_count
                    FROM ".TABLE_PREFIX."threads t
                    LEFT JOIN ".TABLE_PREFIX."threadsread tr ON (tr.tid=t.tid AND tr.uid='{$mybb->user['uid']}')
                    LEFT JOIN ".TABLE_PREFIX."forumsread fr ON (fr.fid=t.fid AND fr.uid='{$mybb->user['uid']}')
                    WHERE t.visible=1 AND t.closed NOT LIKE 'moved|%' AND {$where2} AND t.lastpost > IFNULL(tr.dateline,$cutoff) AND t.lastpost > IFNULL(fr.dateline,$cutoff) AND t.lastpost>$cutoff
                ");
        }
        return $db->fetch_field($query, "unread_count");
    }
}

/**
 * Mark a particular forum as read.
 *
 * @param int $fid The forum ID
 */
function mark_forum_read($fid)
{
    global $mybb, $db;

    // START - Unread posts MOD
    if (is_null($readTime)) {
        $readTime = TIME_NOW;
    }
    // END - Unread posts MOD

    // Can only do "true" tracking for registered users
    if($mybb->settings['threadreadcut'] > 0 && $mybb->user['uid'])
    {
        // Experimental setting to mark parent forums as read
        $forums_to_read = array();

        if($mybb->settings['readparentforums'])
        {
            $ignored_forums = array();
            $forums = array_reverse(explode(",", get_parent_list($fid)));

            unset($forums[0]);
            if(!empty($forums))
            {
                $ignored_forums[] = $fid;

                foreach($forums as $forum)
                {
                    $fids = array($forum);
                    $ignored_forums[] = $forum;

                    $children = explode(",", get_parent_list($forum));
                    foreach($children as $child)
                    {
                        if(in_array($child, $ignored_forums))
                        {
                            continue;
                        }

                        $fids[] = $child;
                        $ignored_forums[] = $child;
                    }

                    if(fetch_unread_count(implode(",", $fids)) == 0)
                    {
                        $forums_to_read[] = $forum;
                    }
                }
            }
        }

        switch($db->type)
        {
            case "pgsql":
            case "sqlite":
                add_shutdown(array($db, "replace_query"), array("forumsread", array('fid' => $fid, 'uid' => $mybb->user['uid'], 'dateline' => TIME_NOW), array("fid", "uid")));

                if(!empty($forums_to_read))
                {
                    foreach($forums_to_read as $forum)
                    {
                        add_shutdown(array($db, "replace_query"), array("forumsread", array('fid' => $forum, 'uid' => $mybb->user['uid'], 'dateline' => TIME_NOW), array('fid', 'uid')));
                    }
                }
                break;
            default:
                $child_sql = '';
                if(!empty($forums_to_read))
                {
                    foreach($forums_to_read as $forum)
                    {
                        $child_sql .= ", ('{$forum}', '{$mybb->user['uid']}', '".TIME_NOW."')";
                    }
                }

                $db->query("
                    REPLACE INTO ".TABLE_PREFIX."forumsread (fid, uid, dateline)
                    VALUES('{$fid}', '{$mybb->user['uid']}', '".TIME_NOW."'){$child_sql}
                ");
        }
        
            // START - Unread posts MOD
            $forums_to_read[] = $fid;
            $fids = implode(',', $forums_to_read);
            $db->query("DELETE TTR.* 
                        FROM " . TABLE_PREFIX . "threadsread AS TTR
                        INNER JOIN " . TABLE_PREFIX . "threads AS TT ON TT.tid = TTR.tid
                        WHERE TTR.uid = '" . $mybb->user['uid'] . "' AND TT.fid IN (" . $fids . ")");
            // END - Unread posts MOD  
    }
    // Mark in a cookie
    else
    {
        my_set_array_cookie("forumread", $fid, TIME_NOW, -1);
    }
}

/**
 * Marks all forums as read.
 *
 */
function mark_all_forums_read()
{
    global $mybb, $db, $cache;

    // Can only do "true" tracking for registered users
    if($mybb->user['uid'] > 0)
    {
        $db->update_query("users", array('lastvisit' => TIME_NOW), "uid='".$mybb->user['uid']."'");
        require_once MYBB_ROOT."inc/functions_user.php";
        update_pm_count('', 2);

        if($mybb->settings['threadreadcut'] > 0)
        {
            // Need to loop through all forums and mark them as read
            $forums = $cache->read('forums');

            $update_count = ceil(count($forums)/20);

            if($update_count < 15)
            {
                $update_count = 15;
            }

            $mark_query = '';
            $done = 0;
            foreach(array_keys($forums) as $fid)
            {
                switch($db->type)
                {
                    case "pgsql":
                    case "sqlite":
                        $mark_query[] = array('fid' => $fid, 'uid' => $mybb->user['uid'], 'dateline' => TIME_NOW);
                        break;
                    default:
                        if($mark_query != '')
                        {
                            $mark_query .= ',';
                        }
                        $mark_query .= "('{$fid}', '{$mybb->user['uid']}', '".TIME_NOW."')";
                }
                ++$done;

                // Only do this in loops of $update_count, save query time
                if($done % $update_count)
                {
                    switch($db->type)
                    {
                        case "pgsql":
                        case "sqlite":
                            foreach($mark_query as $replace_query)
                            {
                                add_shutdown(array($db, "replace_query"), array("forumsread", $replace_query, array("fid", "uid")));
                            }
                            $mark_query = array();
                            break;
                        default:
                            $db->shutdown_query("
                                REPLACE INTO ".TABLE_PREFIX."forumsread (fid, uid, dateline)
                                VALUES {$mark_query}
                            ");
                            $mark_query = '';
                    }
                }
            }

            if($mark_query != '')
            {
                switch($db->type)
                {
                    case "pgsql":
                    case "sqlite":
                        foreach($mark_query as $replace_query)
                        {
                            add_shutdown(array($db, "replace_query"), array("forumsread", $replace_query, array("fid", "uid")));
                        }
                        break;
                    default:
                        $db->shutdown_query("
                            REPLACE INTO ".TABLE_PREFIX."forumsread (fid, uid, dateline)
                            VALUES {$mark_query}
                        ");
                }
            }
        }
    }
    else
    {
        my_setcookie("mybb[readallforums]", 1);
        my_setcookie("mybb[lastvisit]", TIME_NOW);

        my_unsetcookie("mybb[threadread]");
        my_unsetcookie("mybb[forumread]");
    }
}
So only these "changes" into 1.13 base code?

Please let us know after few days, I will test during the weekend (I hope that I will have some spare time).

Thank you
Yes.
I haven't checked what other changes the author made between 1.1 and 1.3 just focused on the time() "and friends".
Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49