Skip to content
Snippets Groups Projects
Score.class.php 8.53 KiB
Newer Older
<?
/**
 * Score.class.php - Score class
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * @author      Ralf Stockmann <rstockm@gwdg.de>
 * @license     http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
 * @category    Stud.IP
 */

class Score
{
    // How long is the duration of a score-block?
    const MEASURING_STEP = 1800; // half an hour

    public static function getScoreContent($persons)
    {
        $user_ids = array_keys($persons);

        // News
        $query = "SELECT nr.range_id as user_id, COUNT(*) AS newscount
                  FROM news_range AS nr
                  INNER JOIN news AS n ON (nr.news_id = n.news_id)
                  WHERE nr.range_id IN (?) AND UNIX_TIMESTAMP() <= n.date + n.expire
                  GROUP BY nr.range_id
                  ORDER BY NULL";
        $statement = DBManager::get()->prepare($query);
        $statement->execute([$user_ids]);
        while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
            $persons[$row['user_id']]['newscount'] = $row['newscount'];
        }

        // Events
        $query = "SELECT `range_id` AS user_id, COUNT(*) AS eventcount
                  FROM `calendar_date_assignments`
                  INNER JOIN `calendar_dates`
                  ON (`calendar_date_assignments`.`calendar_date_id` = `calendar_dates`.`id` AND `access` = 'PUBLIC')
                  WHERE `range_id` IN (?) AND UNIX_TIMESTAMP() <= `end`
                  GROUP BY `range_id`
                  ORDER BY NULL";
        $statement = DBManager::get()->prepare($query);
        $statement->execute([$user_ids]);
        while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
            $persons[$row['user_id']]['eventcount'] = $row['eventcount'];
        }

        // Votes
        if (Config::get()->VOTE_ENABLE){
            $query = "SELECT questionnaire_assignments.range_id as user_id, COUNT(*) AS votecount
                      FROM questionnaire_assignments
                      WHERE questionnaire_assignments.range_id IN (?)
                          AND questionnaire_assignments.range_type = 'user'
                      GROUP BY questionnaire_assignments.range_id
                      ORDER BY NULL";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$user_ids]);
            while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
                $persons[$row['user_id']]['votecount'] = $row['votecount'];
            }
        }

        return $persons;
    }

    /**
    * Retrieves the titel for a given studip score
    *
    * @param        integer a score value
    * @param        integer gender (0: unknown, 1: male; 2: female)
    * @return       string  the titel
    *
    */
    public static function getTitel($score, $gender = 0)
    {
        if ($score) {
            $logscore = floor(log10($score) / log10(2));
        } else {
            $logscore = 0;
        }

        if ($logscore > 20) {
            $logscore = 20;
        }

        $titel = [];
        $titel[0]  = [_('Unbeschriebenes Blatt'), _('Unbeschriebenes Blatt')];
        $titel[1]  = [_('Unbeschriebenes Blatt'), _('Unbeschriebenes Blatt')];
        $titel[2]  = [_('Unbeschriebenes Blatt'), _('Unbeschriebenes Blatt')];
        $titel[3]  = [_('Neuling'), _('Neuling')];
        $titel[4]  = [_('Greenhorn'), _('Greenhorn')];
        $titel[5]  = [_('Anfänger'), _('Anfängerin')];
        $titel[6]  = [_('Einsteiger'), _('Einsteigerin')];
        $titel[7]  = [_('Beginner'), _('Beginnerin')];
        $titel[8]  = [_('Novize'), _('Novizin')];
        $titel[9]  = [_('Fortgeschrittener'), _('Fortgeschrittene')];
        $titel[10] = [_('Kenner'), _('Kennerin')];
        $titel[11] = [_('Könner'), _('Könnerin')];
        $titel[12] = [_('Profi'), _('Profi')];
        $titel[13] = [_('Experte'), _('Expertin')];
        $titel[14] = [_('Meister'), _('Meisterin')];
        $titel[15] = [_('Großmeister'), _('Großmeisterin')];
        $titel[16] = [_('Idol'), _('Idol')];
        $titel[17] = [_('Guru'), _('Hohepriesterin')];
        $titel[18] = [_('Lichtgestalt'), _('Lichtgestalt')];
        $titel[19] = [_('Halbgott'), _('Halbgöttin')];
        $titel[20] = [_('Gott'), _('Göttin')];

        return $titel[$logscore][$gender == 2 ? 1 : 0];
    }

    /**
    * Retrieves the score for the current user
    *
    * @return       integer the score
    *
    */
    public static function GetMyScore($user_or_id = null)
    {
        $user = $user_or_id ? User::toObject($user_or_id) : User::findCurrent();
        $cache = StudipCacheFactory::getCache();
        if ($cache->read("user_score_of_".$user->id)) {
            return $cache->read("user_score_of_".$user->id);
        }
        //Behold! The all new mighty score algorithm!
        //Step 1: Select all activities as mkdate-timestamps.
        //Step 2: Group these activities to timeslots of halfhours
        //        with COUNT(*) as a weigh of the timeslot.
        //Step 3: Calculate the measurement of the timeslot from the weigh of it.
        //        This makes the first activity count fully, the second
        //        almost half and so on. We use log_n to make huge amounts of
        //        activities to not count so much.
        //Step 4: Calculate a single score for each timeslot depending on the
        //        measurement and the mkdate-timestamp. Use arctan as the function
        //        here so that older activities tend to zero.
        //Step 5: Sum all scores from all timeslots together.
        $sql = "
            SELECT round(SUM((-atan(measurement / " . round(31556926 / self::MEASURING_STEP) . ") / PI() + 0.5) * 200)) as score
            FROM (
                SELECT ((unix_timestamp() / " . self::MEASURING_STEP . ") - timeslot) / (LN(weigh) + 1) AS measurement
                FROM (
                    SELECT (round(mkdate / " . self::MEASURING_STEP . ")) as timeslot, COUNT(*) AS weigh
                    FROM (
                        " . self::createTimestampQuery() . "
                    ) as mkdates
                    GROUP BY timeslot
                ) as measurements
            ) as dates
        ";
        $stmt = DBManager::get()->prepare($sql);
        $stmt->execute([':user' => $user->id]);
        $score = $stmt->fetchColumn();
        if ($user->score && $user->score != $score) {
            $user->score = $score;
            $user->store();
        }
        $cache->write("user_score_of_{$user->id}", $score, 60 * 5);

        return $score;
    }

    protected static function createTimestampQuery()
    {
        $statements = [];
        foreach (self::getActivityTables() as $table) {
            $statements[] = "SELECT "
Moritz Strohm's avatar
Moritz Strohm committed
                . ($table['date_column'] ?? 'mkdate')
                . " AS mkdate FROM "
                . $table['table']
                . " WHERE "
Moritz Strohm's avatar
Moritz Strohm committed
                . ($table['user_id_column'] ?? 'user_id')
Moritz Strohm's avatar
Moritz Strohm committed
                . (!empty($table['where']) ? (' AND ' . $table['where']) : '');
        }
        return join(' UNION ', $statements);
    }

    protected static function getActivityTables()
    {
        $tables = [];
        $tables[] = ['table' => 'user_info'];
        $tables[] = ['table' => 'comments'];
        $tables[] = ['table' => 'file_refs'];
        $tables[] = ['table' => 'forum_entries'];
        $tables[] = ['table' => 'news'];
        $tables[] = ['table' => 'seminar_user'];
        $tables[] = [
            'table' => 'blubber_threads'
        ];
        $tables[] = [
            'table' => 'blubber_comments'
        ];
        $tables[] = [
            'table'          => 'kategorien',
            'user_id_column' => 'range_id',
        ];
        $tables[] = [
            'table'          => 'message',
            'user_id_column' => 'autor_id'
        ];
        $tables[] = ['table' => 'questionnaires'];
        $tables[] = [
            'table'       => 'questionnaire_answers',
            'date_column' => 'chdate',
        ];
        $tables[] = ['table' => 'questionnaire_anonymous_answers'];
        $tables[] = [
            'table'       => 'wiki_pages',
            'date_column' => 'chdate'
        ];

        foreach (PluginManager::getInstance()->getPlugins('ScorePlugin') as $plugin) {
            foreach ((array) $plugin->getPluginActivityTables() as $table) {
                if ($table['table']) {
                    $tables[] = $table;
                }
            }
        }

        return $tables;
    }
}