| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470 |
- <?php
- // This file is part of the Sloodle project (www.sloodle.org)
-
- /**
- * This file defines the Sloodle awards module.
- *
- * @package sloodle
- * @copyright Copyright (c) 2008 Sloodle (various contributors)
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU GPL v3
- *
- * @contributor Peter R. Bloomfield
- * @contributor Paul G. Preibisch - aka Fire Centaur
- */
-
- /** The Sloodle module base. */
- require_once(SLOODLE_LIBROOT.'/modules/module_base.php');
- /** General Sloodle functions. */
- require_once(SLOODLE_LIBROOT.'/general.php');
-
- /** SLOODLE course object data structure */
- require_once(SLOODLE_LIBROOT.'/sloodlecourseobject.php');
- /**
- * The Sloodle StipendGiver module class.
- * @package sloodle
- */
- class SloodleModuleAwards extends SloodleModule
- {
- // DATA //
-
- /**
- * Internal for Moodle only - course module instance.
- * Corresponds to one record from the Moodle 'course_modules' table.
- * @var object
- * @access private
- */
- var $cm = null;
-
- /**
- * Internal only - Sloodle module instance database object.
- * Corresponds to one record from the Moodle 'sloodle' table.
- * @var object
- * @access private
- */
- var $sloodle_module_instance = null;
-
- /**
- * Internal only - Sloodle StipendGiver instance database object.
- * Corresponds to one record from the Moodle 'sloodle_awards' table.
- * @var object
- * @access private
- */
- var $sloodle_awards_instance = null;
-
- var $sCourseObj = null;
-
-
- var $sloodleid = null;
-
- // FUNCTIONS //
-
- /**
- * Constructor
- */
- function SloodleModuleAwards(&$_session)
- {
- $constructor = get_parent_class($this);
- parent::$constructor($_session);
- }
-
- /**
- * Loads data from the database.
- * Note: even if the function fails, it may still have overwritten some or all existing data in the object.
- * @param mixed $id The site-wide unique identifier for all modules. Type depends on VLE. On Moodle, it is an integer course module identifier ('id' field of 'course_modules' table)
- * @return bool True if successful, or false otherwise
- */
- function load($id)
- {
- // Make sure the ID is valid
- if (!is_int($id) || $id <= 0) return false;
-
- // Fetch the course module data
- if (!($this->cm = get_coursemodule_from_id('sloodle', $id))) return false;
- // Load from the primary table: Sloodle instance
- if (!($this->sloodle_module_instance = sloodle_get_record('sloodle', 'id', $this->cm->instance))) return false;
- // Load from the primary table: sloodle instance
- if (!($this->sloodle_instance = sloodle_get_record('sloodle', 'id', $this->cm->instance))) {
- sloodle_debug("Failed to load Sloodle module with instance ID #{$cm->instance}.<br/>");
- return false;
- }
-
-
-
- if ($this->sloodle_module_instance->type != SLOODLE_TYPE_AWARDS) return false;
-
- // Load from the secondary table: StipendGiver instance
- if (!($this->sloodle_awards_instance = sloodle_get_record('sloodle_awards', 'sloodleid', $this->cm->instance))) return false;
-
- return true;
- }
-
- function ProcessActions( $relevant_configs, $controllerid, $multiplier, $userid, $useruuid, $objuuid) {
- global $CFG;
- $controller = new SloodleController();
- if (!$controller->load_by_course_module_id($controllerid)) {
- return false;
- }
- if (!$roundid = $controller->get_active_roundid(true)) {
- return false;
- }
- $time = time();
- if ( isset($relevant_configs['sloodleawardsdeposit_numpoints']) && isset($relevant_configs['sloodleawardsdeposit_currency']) ) {
- $numpoints = intval($relevant_configs['sloodleawardsdeposit_numpoints']);
- $currencyid = intval($relevant_configs['sloodleawardsdeposit_currency']);
- if (!$currencyid) {
- return false;
- }
- $award = new stdClass();
- $award->userid = $userid;
- $award->currencyid = $currencyid;
- $award->amount = $numpoints * $multiplier;
- $award->timeawarded = $time;
- $award->roundid = $roundid;
- if ( !sloodle_insert_record('sloodle_award_points', $award) ) {
- return false;
- }
- $need_notify = true;
- // Notify any active objects that care about changes to scores
- // We'll check this in the object definition.
- // TODO: We should probably do this with a notification_request table,
- // ...where the scoreboard etc will register with Sloodle that it's interested in certain events.
- // TODO: Figure out the round/controller filters
- $user_point_total_recs = sloodle_get_records_sql_params( "select sum(amount) as balance from {$CFG->prefix}sloodle_award_points where currencyid=? and roundid=? and userid=?;", array($currencyid, $roundid, $userid));
- if (!$user_point_total_recs && (count($user_point_total_recs) == 0 ) ) {
- return false;
- }
- $first_rec = array_shift($user_point_total_recs);
- $balance = $first_rec->balance;
- // This sends a single points change notification to an object.
- // It's used by the shared media scoreboard to prompt a re-fetch of score data.
- SloodleModuleAwards::NotifyRealtimeBroadcastClients('awards_points_change', 10601, $controllerid, $userid, array('balance' => $balance, 'roundid' => $roundid, 'userid' => $userid, 'currencyid' => $currencyid, 'timeawarded' => $time ) );;
- SloodleActiveObject::NotifySubscriberObjects( 'awards_points_change', 10601, $controllerid, $userid, array('balance' => $balance, 'roundid' => $roundid, 'userid' => $userid, 'currencyid' => $currencyid, 'timeawarded' => $time ) );
- }
- if ( isset($relevant_configs['sloodleawardswithdraw_numpoints']) && isset($relevant_configs['sloodleawardswithdraw_currency']) ) {
- $numpoints = intval($relevant_configs['sloodleawardswithdraw_numpoints']) * -1;
- $currencyid = intval($relevant_configs['sloodleawardswithdraw_currency']);
- if (!$currencyid) {
- return false;
- }
- $award = new stdClass();
- $award->userid = $userid;
- $award->currencyid = $currencyid;
- $award->amount = $numpoints * $multiplier;
- $award->timeawarded = $time;
- $award->roundid = $roundid;
- if ( !sloodle_insert_record('sloodle_award_points', $award) ) {
- return false;
- }
- $need_notify = true;
- // Notify any active objects that care about changes to scores
- // We'll check this in the object definition.
- // TODO: We should probably do this with a notification_request table,
- // ...where the scoreboard etc will register with Sloodle that it's interested in certain events.
- // TODO: Figure out the round/controller filters
- $user_point_total_recs = sloodle_get_records_sql_params( "select sum(amount) as balance from {$CFG->prefix}sloodle_award_points where currencyid=? and roundid=? and userid=?;", array($currencyid, $roundid, $userid));
- if (!$user_point_total_recs && (count($user_point_total_recs) == 0 ) ) {
- return false;
- }
- $first_rec = array_shift($user_point_total_recs);
- $balance = $first_rec->balance;
- // This sends a single points change notification to an object.
- // It's used by the shared media scoreboard to prompt a re-fetch of score data.
- SloodleModuleAwards::NotifyRealtimeBroadcastClients('awards_points_change', 10601, $controllerid, $userid, array('balance' => $balance, 'roundid' => $roundid, 'userid' => $userid, 'currencyid' => $currencyid, 'timeawarded' => $time ) );;
- SloodleActiveObject::NotifySubscriberObjects( 'awards_points_change', 10601, $controllerid, $userid, array('balance' => $balance, 'roundid' => $roundid, 'userid' => $userid, 'currencyid' => $currencyid, 'timeawarded' => $time ) );
- }
-
- return true;
- }
- function UserCurrencyBalance( $userid, $currencyid) {
- global $CFG;
- $userid = intval($userid);
- $currencyid = intval($currencyid);
- $balancesql = "select sum(amount) as balance from {$CFG->prefix}sloodle_award_points where userid = ? and currencyid = ?";
- $results = sloodle_get_records_sql_params( $balancesql, array($userid, $currencyid) );
- if (!$results || ( count($results) == 0) ) {
- //SloodleDebugLogger::log('DEBUG', "nothing found for $balancesql");
- return 0;
- }
- $result = array_shift($results);
- //SloodleDebugLogger::log('DEBUG', "balance for sql $balancesql was ".$result->balance);
- return $result->balance;
- }
- /*
- Returns an array of error messages for requirements that haven't been satisfied.
- ...eg. If an object has been configured to require 3 gold coins, and the user doesn't have enough, it'll return a message saying you don't have enough gold coins.
- */
- function RequirementFailures( $relevant_configs, $controllerid, $multiplier, $userid, $useruuid ) {
- //SloodleDebugLogger::log('DEBUG', "in ProcessRequirements");
- global $CFG;
- $minimum_balances = array();
- $failures = array();
- if ( isset($relevant_configs['sloodleawardsrequire_numpoints']) && isset($relevant_configs['sloodleawardsrequire_currency']) ) {
- $numpoints = intval($relevant_configs['sloodleawardsrequire_numpoints']);
- $currencyid = intval($relevant_configs['sloodleawardsrequire_currency']);
- if ($currencyid && $numpoints) {
- if ( SloodleModuleAwards::UserCurrencyBalance($userid, $currencyid) < $numpoints ) {
- if (isset($relevant_configs['sloodleawardsrequire_notenoughmessage']) && $relevant_configs['sloodleawardsrequire_notenoughmessage'] != '') {
- $failures = array_merge( $failures, array($relevant_configs['sloodleawardsrequire_notenoughmessage']));
- } else {
- $failures = array_merge( $failures, array(get_string('awards:notenoughcurrency', 'sloodle')) );
- }
- }
- }
- }
- if ( isset($relevant_configs['sloodleawardswithdraw_numpoints']) && isset($relevant_configs['sloodleawardswithdraw_currency']) ) {
- $numpoints = intval($relevant_configs['sloodleawardswithdraw_numpoints']);
- $currencyid = intval($relevant_configs['sloodleawardswithdraw_currency']);
- if ($currencyid && $numpoints) {
- if ( SloodleModuleAwards::UserCurrencyBalance($userid, $currencyid) < $numpoints ) {
- if (isset($relevant_configs['sloodleawardswithdraw_notenoughmessage']) && $relevant_configs['sloodleawardswithdraw_notenoughmessage'] != '') {
- $failures = array_merge( $failures, array($relevant_configs['sloodleawardswithdraw_notenoughmessage']));
- } else {
- $failures = array_merge( $failures, array(get_string('awards:notenoughcurrency', 'sloodle')) );
- }
- }
- }
- }
- return $failures;
- }
-
- /*
- An array of the names of config parameters that are understood by this module to mean it should do something.
- Will have the name of the specific interaction appended to it.
- eg. awards makes available an interaction config called "sloodleawardsdeposit_numpoints".
- The quiz would then have a config name=>value pair like sloodleawards_deposit_numpoints_answerquestion => 3
- Via the ActiveObject, the quiz will tell the awards module that answerquestion has happened to a particular user
- ...and the awards module will give them the points.
- */
- function ActionConfigNames() {
- return array(
- 'sloodleawardsdeposit_numpoints',
- 'sloodleawardsdeposit_currency',
- 'sloodleawardswithdraw_numpoints',
- 'sloodleawardswithdraw_currency'
- );
- }
- /*
- An array of the names of config parameters that are understood by this module to check something before doing whatever it would normally do.
- Will have the name of the specific interaction appended to it.
- */
- function RequirementConfigNames() {
- return array(
- 'sloodleawardsrequire_numpoints',
- 'sloodleawardsrequire_currency',
- 'sloodleawardsrequire_notenoughmessage',
- 'sloodleawardswithdraw_numpoints',
- 'sloodleawardswithdraw_currency',
- 'sloodleawardswithdraw_notenoughmessage'
- );
- }
- /**
- * Gets the short type name of this instance.
- * @return string
- */
- function get_type()
- {
- return 'awards';
- }
- /**
- * Gets the full type name of this instance, according to the current language pack, if available.
- * Note: should be overridden by sub-classes.
- * @return string Full type name if possible, or the short name otherwise.
- */
- function get_type_full()
- {
- return get_string('modulename', 'awards');
- }
- /*
- Prepare a page full of scoreboard results and send it to the specified active objects.
- This was originally designed for the zztext scoreboard.
- If it finds a config parameter called sloodleactivepage it will limit to that page.
- */
- function PageScoreMessage( $aoarr, $notification_action, $success_code, $controllerid, $userid, $params, $addtimestampparams ) {
- global $CFG;
- if (count($aoarr) == 0) {
- return true;
- }
- $roundid = $params['roundid'];
- $currencyid = $params['currencyid'];
- $currencyname = '';
- $aoarr = SloodleActiveObject::FilterForConfigNameValue( $aoarr, 'sloodlecurrencyid', $currencyid);
- if ($currencyid) {
- // Ge the name of the currency
- $currency_recs = sloodle_get_records_sql_params( "select id, name as currency_name from {$CFG->prefix}sloodle_currency_types where id = ?;", array($currencyid));
- $currency_rec = array_shift($currency_recs);
- $currencyname = $currency_rec->currency_name;
- }
- $user_point_total_recs = sloodle_get_records_sql_params( "select p.userid as userid, sum(amount) as balance, su.avname as avname, su.uuid as uuid from {$CFG->prefix}sloodle_award_points p inner join {$CFG->prefix}sloodle_users su on p.userid=su.userid where currencyid=? and roundid=? group by userid order by balance desc;", array($currencyid, $roundid));
- foreach($aoarr as $ao) {
- $response = new SloodleResponse();
- //$response->set_status_code($success_code);
- $response->set_status_code(1639271140);
- $response->set_status_descriptor('NOTIFICATION');
- $response->set_request_descriptor('NOTIFICATION');
- $response->set_http_in_password($ao->httpinpassword);
- $def = $ao->objectDefinition();
- $linesperpage = 10;
- if ( isset($def->fixed_parameters) && isset($def->fixed_parameters['linesperpage']) ) {
- $linesperpage = $def->fixed_parameters['linesperpage'];
- }
- $charactersperline = 40;
- if ( isset($def->fixed_parameters) && isset($def->fixed_parameters['charactersperline']) ) {
- $charactersperline = $def->fixed_parameters['charactersperline'];
- }
- $page = $ao->config_value( 'sloodleactivepage' );
- if (!$page) {
- $page = 1;
- }
- $scoreboardtitle= $ao->config_value('sloodleobjecttitle');
- /*
- foreach($params as $n=>$v) {
- $response->add_data_line($n.'|'.$v);
- }
- */
- $num_pages = ceil( count($user_point_total_recs) / $linesperpage );
- $response->add_data_line("status|$page|$num_pages|$scoreboardtitle||$currencyid|$currencyname");
- $offset = ( ($page-1) * $linesperpage );
- $page_points = array_slice( $user_point_total_recs, $offset, $linesperpage );
- foreach($page_points as $up) {
- $uuid = $up->uuid;
- $avname = $up->avname;
- $score = $up->balance;
- $availablechars = $charactersperline - ( strlen($score) + 1 ); // leave room for a space folowed by the score
- $displayavname = substr($avname, 0, $availablechars); // truncate the name if it's too long to fit.
- $displayavname = str_pad( $displayavname, $availablechars, " ");
- $displayline = $displayavname." ".$score;
- $response->add_data_line("$uuid|$score|$displayline");
- }
- $renderStr="";
- $response->render_to_string($renderStr);
- $async = ( defined('SLOODLE_ASYNC_SEND_MESSAGES') && SLOODLE_ASYNC_SEND_MESSAGES );
- // If this stuff fails, tough. We did our best.
- if ($resarr = $ao->sendMessage($renderStr, $async, $async)) {
- if($resarr['info']['http_code'] == 200){
- $ao->lastmessagetimestamp = time();
- $ao->save();
- }
- }
- }
- return true;
- }
- function NotifyRealtimeBroadcastClients($event_type, $some_code, $controllerid, $userid, $currencyid, $params) {
- //
- /*Params should look like:
- array('balance' => $balance, 'roundid' => $roundid, 'userid' => $userid, 'currencyid' => $currencyid, 'timeawarded' => $time )
- */
- if (!defined('SLOODLE_REALTIME_BROADCAST_SERVER_UPDATE') || SLOODLE_REALTIME_BROADCAST_SERVER_UPDATE == '') {
- return false;
- }
- global $CFG;
- $currencyid = isset($params['currencyid']) ? intval($params['currencyid']) : 0;
- $controllerid = isset($params['controllerid']) ? intval($params['controllerid']) : 0;
- $useruuid = SloodleUser::AvatarUUIDForUserID($userid);
- SloodleDebugLogger::log('DEBUG', "got user uuid $useruuid for user $userid");
- $site = $CFG->wwwroot;
- $room = $site.'/scores/avatar/'.$useruuid.'/controller/'.$controllerid;
- if (preg_match('#^(http|https)://(.*)$#', $room, $matches)) {
- $room = $matches[2];
- }
- $payloadobj = new stdClass();
- $payloadobj->currencyid = $currencyid;
- $payloadobj->points = $points;
- $payloadjson = json_encode($payloadobj);
- $url = SLOODLE_REALTIME_BROADCAST_SERVER_UPDATE.'/?cmd=update&uuid='.urlencode($useruuid).'&payload='.urlencode($payloadjson);
- SloodleDebugLogger::log('DEBUG', "sending to node server at url $url");
- $ch = curl_init(); // initialize curl handle
- curl_setopt($ch, CURLOPT_URL, $url); // set url to post to
- curl_setopt($ch, CURLOPT_FAILONERROR,0);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); // return into a variable
- curl_setopt($ch, CURLOPT_TIMEOUT, 10);
- // TODO:
- //curl_setopt($ch, CURLOPT_POST, 1); // set POST method
- //curl_setopt($ch, CURLOPT_POSTFIELDS,$msg); // add POST fields
- $result = curl_exec($ch); // run the whole process
- $info = curl_getinfo($ch);
- curl_close($ch);
- return array('info'=>$info,'result'=>$result);
- }
- }
- ?>
|