aboutsummaryrefslogtreecommitdiff
path: root/lib/classes/Score.php
diff options
context:
space:
mode:
authorPhilipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de>2024-09-24 10:53:31 +0200
committerPhilipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de>2024-09-24 10:53:31 +0200
commit4459dd7917f4d1c34f40bb68f0e991e9c3d53e4c (patch)
tree5c07151ae61276d334e88f6309c30d439a85c12e /lib/classes/Score.php
parentda0022e5c1abbf9825ae76debaabdff7e8623bb4 (diff)
parent97a188592c679890a25c37ab78463add76a52ff7 (diff)
Merge branch 'main' into issue-3911issue-3911
Diffstat (limited to 'lib/classes/Score.php')
-rw-r--r--lib/classes/Score.php225
1 files changed, 225 insertions, 0 deletions
diff --git a/lib/classes/Score.php b/lib/classes/Score.php
new file mode 100644
index 0000000..3b7f149
--- /dev/null
+++ b/lib/classes/Score.php
@@ -0,0 +1,225 @@
+<?
+/**
+ * Score.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 = \Studip\Cache\Factory::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 "
+ . ($table['date_column'] ?? 'mkdate')
+ . " AS mkdate FROM "
+ . $table['table']
+ . " WHERE "
+ . ($table['user_id_column'] ?? 'user_id')
+ . " = :user "
+ . (!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::class) as $plugin) {
+ foreach ((array) $plugin->getPluginActivityTables() as $table) {
+ if ($table['table']) {
+ $tables[] = $table;
+ }
+ }
+ }
+
+ return $tables;
+ }
+}