diff --git a/qa-include/Q2A/Plugin/AbstractPointModule.php b/qa-include/Q2A/Plugin/AbstractPointModule.php new file mode 100644 index 000000000..03177bf8c --- /dev/null +++ b/qa-include/Q2A/Plugin/AbstractPointModule.php @@ -0,0 +1,20 @@ +<?php + +abstract class Q2A_Plugin_AbstractPointModule implements Q2A_Plugin_IPointModule +{ + /** + * Return the amount of points that the module expects to change for the given user id. This default implementation + * just calls the getPointsForUsers() function wrapping the given user id as the only user in the array. It can be + * overridden in subclasses + * + * @param int|string $userId The user id + * + * @return int The number of points that the module should change for the given user + */ + public function getPointsForUser($userId) + { + $userIdPoints = $this->getPointsForUsers(array($userId)); + + return reset($userIdPoints); + } +} diff --git a/qa-include/Q2A/Plugin/IPointModule.php b/qa-include/Q2A/Plugin/IPointModule.php new file mode 100644 index 000000000..8de3f2a39 --- /dev/null +++ b/qa-include/Q2A/Plugin/IPointModule.php @@ -0,0 +1,22 @@ +<?php + +interface Q2A_Plugin_IPointModule +{ + /** + * Return the amount of points that the module expects to change for the given user id + * + * @param int|string $userId The user id + * + * @return int The number of points that the module should change for the given user + */ + public function getPointsForUser($userId); + + /** + * Return the amount of points that the module expects to change for the given array of user ids + * + * @param array $userIds The array of user ids + * + * @return array The array containing as keys the user ids and as values the amount of points to change + */ + public function getPointsForUsers($userIds); +} diff --git a/qa-include/app/recalc.php b/qa-include/app/recalc.php index 0fdf6174c..2eaab774c 100644 --- a/qa-include/app/recalc.php +++ b/qa-include/app/recalc.php @@ -246,7 +246,29 @@ function qa_recalc_perform_step(&$state) if ($recalccount > 0) { $lastuserid = $userids[$recalccount - 1]; - qa_db_users_recalc_points($next, $lastuserid); + + // Get points from all registered point modules + + $userIdPointsMap = array(); + + $modules = qa_load_modules_for_type('point'); + if (!empty($modules)) { + $processUserIds = array_slice($userids, 0, $recalccount); + + foreach ($modules as $module) { + $currentPluginUserIdPointsMap = $module->getPointsForUsers($processUserIds); + foreach ($currentPluginUserIdPointsMap as $userId => $points) { + if (!isset($userIdPointsMap[$userId])) { + $userIdPointsMap[$userId] = 0; + } + + $userIdPointsMap[$userId] += $points; + } + } + } + + qa_db_users_recalc_points($next, $lastuserid, $userIdPointsMap); + $done += $recalccount; } else { diff --git a/qa-include/db/points.php b/qa-include/db/points.php index ec282f14d..6189b0929 100644 --- a/qa-include/db/points.php +++ b/qa-include/db/points.php @@ -162,7 +162,7 @@ function qa_db_points_calculations() * @param $columns * @return mixed */ -function qa_db_points_update_ifuser($userid, $columns) +function qa_db_points_update_ifuser($userid, $columns = null) { if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } @@ -202,8 +202,15 @@ function qa_db_points_update_ifuser($userid, $columns) $updatepoints .= '+(' . $multiple . '*' . (isset($keycolumns[$field]) ? '@_' : '') . $field . ')'; } + $pluginPoints = 0; + + $modules = qa_load_modules_for_type('point'); + foreach ($modules as $module) { + $pluginPoints += $module->getPointsForUser($userid); + } + $query = 'INSERT INTO ^userpoints (' . $insertfields . 'points) VALUES (' . $insertvalues . $insertpoints . ') ' . - 'ON DUPLICATE KEY UPDATE ' . $updates . 'points=' . $updatepoints . '+bonus'; + 'ON DUPLICATE KEY UPDATE ' . $updates . 'points=' . $updatepoints . '+ bonus + ' . ((string) $pluginPoints); // build like this so that a #, $ or ^ character in the $userid (if external integration) isn't substituted qa_db_query_raw(str_replace('~', "='" . qa_db_escape_string($userid) . "'", qa_db_apply_sub($query, array($userid)))); diff --git a/qa-include/db/recalc.php b/qa-include/db/recalc.php index 351cd751b..1ac218d27 100644 --- a/qa-include/db/recalc.php +++ b/qa-include/db/recalc.php @@ -266,11 +266,13 @@ function qa_db_users_get_for_recalc_points($startuserid, $count) /** - * Recalculate all userpoints columns for users $firstuserid to $lastuserid in the database + * Recalculate all userpoints columns for users $firstuserid to $lastuserid in the database. Send a user id to point map containing + * the result of applying all plugins point recalculations * @param $firstuserid * @param $lastuserid + * @param $userIdPointsMap */ -function qa_db_users_recalc_points($firstuserid, $lastuserid) +function qa_db_users_recalc_points($firstuserid, $lastuserid, $userIdPointsMap) { require_once QA_INCLUDE_DIR . 'db/points.php'; @@ -315,8 +317,34 @@ function qa_db_users_recalc_points($firstuserid, $lastuserid) $updatepoints .= '+(' . ((int)$calculation['multiple']) . '*' . $field . ')'; } + $pluginLeftJoin = ''; + $pluginExtraPoints = ''; + + if (!empty($userIdPointsMap)) { + // Start the left join + + $pluginLeftJoin = 'LEFT JOIN ('; + + // Build the derived table + + reset($userIdPointsMap); + $userId = key($userIdPointsMap); + $pluginLeftJoin .= sprintf('SELECT %s userid, %d points ', $userId, $userIdPointsMap[$userId]); + unset($userIdPointsMap[$userId]); + + foreach ($userIdPointsMap as $userId => $points) { + $pluginLeftJoin .= sprintf('UNION SELECT %s, %d ', $userId, $userIdPointsMap[$userId]); + } + + // Finish the left join + + $pluginLeftJoin .= ') plugin_points ON up.userid = plugin_points.userid '; + + $pluginExtraPoints = '+ COALESCE(plugin_points.points, 0) '; + } + qa_db_query_sub( - 'UPDATE ^userpoints SET points=' . $updatepoints . '+bonus WHERE userid>=# AND userid<=#', + 'UPDATE ^userpoints up ' . $pluginLeftJoin . 'SET up.points=' . $updatepoints . '+ bonus ' . $pluginExtraPoints . 'WHERE up.userid >= # AND up.userid <= #', $firstuserid, $lastuserid ); } diff --git a/qa-include/qa-base.php b/qa-include/qa-base.php index 01b22fc6a..7b31a0696 100644 --- a/qa-include/qa-base.php +++ b/qa-include/qa-base.php @@ -942,7 +942,7 @@ function qa_load_module($type, $name) } /** - * Return an array of instantiated clases for modules which have defined $method + * Return an array of instantiated classes for modules which have defined $method * (all modules are loaded but not included in the returned array) * @param $method * @return array @@ -966,7 +966,28 @@ function qa_load_all_modules_with($method) } /** - * Return an array of instantiated clases for modules of $type which have defined $method + * Return an array of instantiated classes for modules of type $type + * @param $type + * @return array + */ +function qa_load_modules_for_type($type) +{ + $modules = array(); + + $trynames = qa_list_modules($type); + + foreach ($trynames as $tryname) { + $module = qa_load_module($type, $tryname); + if (isset($module)) { + $modules[$tryname] = $module; + } + } + + return $modules; +} + +/** + * Return an array of instantiated classes for modules of $type which have defined $method * (other modules of that type are also loaded but not included in the returned array) * @param $type * @param $method