/** * Class constructor. * * @param LTI_Resource_Link $resource_link Resource_Link object * @param string $id Value of share key (optional, default is null) */ public function __construct($resource_link, $id = NULL) { $this->initialise(); $this->data_connector = $resource_link->getConsumer()->getDataConnector(); $this->id = $id; $this->primary_context_id =& $this->primary_resource_link_id; if (!empty($id)) { $this->load(); } else { $this->primary_consumer_key = $resource_link->getKey(); $this->primary_resource_link_id = $resource_link->getId(); } }
/** * Get an array of LTI_Resource_Link_Share objects for each resource link which is sharing this resource link * * @param LTI_Resource_Link $resource_link * @return array */ public function Resource_Link_getShares($resource_link) { $shares = array(); $key = $resource_link->getKey(); $id = $resource_link->getId(); $sql = 'SELECT consumer_key, context_id, title, share_approved ' . 'FROM ' . $this->dbTableNamePrefix . LTI_Data_Connector::RESOURCE_LINK_TABLE_NAME . ' ' . 'WHERE (primary_consumer_key = :key) AND (primary_context_id = :id) ' . 'ORDER BY consumer_key'; $query = $this->db->prepare($sql); $query->bindValue('key', $key, PDO::PARAM_STR); $query->bindValue('id', $id, PDO::PARAM_STR); if ($query->execute()) { while ($row = $query->fetch()) { $share = new LTI_Resource_Link_Share(); $share->consumer_key = $row['consumer_key']; $share->resource_link_id = $row['context_id']; $share->title = $row['title']; $share->approved = $row['share_approved'] == 1; $shares[] = $share; } } return $shares; }
function prepare_items($per_page) { global $wpdb; /** * REQUIRED. Now we need to define our column headers. This includes a complete * array of columns to be displayed (slugs & titles), a list of columns * to keep hidden, and a list of columns that are sortable. Each of these * can be defined in another method (as we've done here) before being * used to build the value for our _column_headers property. */ $columns = $this->get_columns(); $hidden = array(); $sortable = $this->get_sortable_columns(); /** * REQUIRED. Finally, we build an array to be used by the class for column * headers. The $this->_column_headers property takes an array which contains * 3 other arrays. One for all columns, one for hidden columns, and one * for sortable columns. */ $this->_column_headers = array($columns, $hidden, $sortable); /** * Optional. You can handle your bulk actions however you see fit. In this * case, we'll handle them within our package just to keep things clean. */ $this->process_bulk_action(); /** * Get all the shares and convert in array for this class to process */ // Get the context $consumer = new LTI_Tool_Consumer($_SESSION[LTI_SESSION_PREFIX . 'key'], array($wpdb->base_prefix)); $resource = new LTI_Resource_Link($consumer, $_SESSION[LTI_SESSION_PREFIX . 'resourceid']); $lti_shares = $resource->getShares(); for ($i = 0; $i < count($lti_shares); $i++) { $data[$i]['ID'] = $i; $data[$i]['name'] = $lti_shares[$i]->title; $data[$i]['key'] = $lti_shares[$i]->consumer_key; $data[$i]['approved'] = $lti_shares[$i]->approved ? 'Yes' : 'No'; $data[$i]['resource_link_id'] = $lti_shares[$i]->resource_link_id; } /** * This checks for sorting input and sorts the data in our array accordingly. * * In a real-world situation involving a database, you would probably want * to handle sorting by passing the 'orderby' and 'order' values directly * to a custom query. The returned data will be pre-sorted, and this array * sorting technique would be unnecessary. */ function usort_reorder($a, $b) { $orderby = !empty($_REQUEST['orderby']) ? $_REQUEST['orderby'] : 'name'; //If no sort, default to title $order = !empty($_REQUEST['order']) ? $_REQUEST['order'] : 'asc'; //If no order, default to asc $result = strcmp($a[$orderby], $b[$orderby]); //Determine sort order return $order === 'asc' ? $result : -$result; //Send final sort direction to usort } // Don't usort if there is no data if (isset($data)) { usort($data, 'usort_reorder'); } /** * REQUIRED for pagination. Let's figure out what page the user is currently * looking at. We'll need this later, so you should always include it in * your own package classes. */ $current_page = $this->get_pagenum(); /** * REQUIRED for pagination. Let's check how many items are in our data array. * In real-world use, this would be the total number of items in your database, * without filtering. We'll need this later, so you should always include it * in your own package classes. */ $total_items = 0; if (isset($data)) { $total_items = count($data); } /** * The WP_List_Table class does not handle pagination for us, so we need * to ensure that the data is trimmed to only the current page. There needs * to be data here... */ if ($total_items > 0) { $data = array_slice($data, ($current_page - 1) * $per_page, $per_page); } /** * REQUIRED. Now we can add our *sorted* data to the items property, where * it can be used by the rest of the class. */ if (isset($data)) { $this->items = $data; } /** * REQUIRED. We also have to register our pagination options & calculations. */ $this->set_pagination_args(array('total_items' => $total_items, 'per_page' => $per_page, 'total_pages' => ceil($total_items / $per_page))); }
function lti_register_user_submenu_page() { // Check this is an LTI site for which the following make sense if (is_null(get_option('ltisite'))) { return; } // Not sure if this is strictly needed but it stops the LTI option // appearing on the main site (/) if (is_main_site()) { return; } global $wpdb, $current_user, $lti_options_page; // Check whether this blog is LTI, if not return if (get_option('ltisite') == 1) { // Sort out consumer instance and membership service stuff $consumer = new LTI_Tool_Consumer($_SESSION[LTI_SESSION_PREFIX . 'userkey'], array($wpdb->base_prefix)); $resource_link = new LTI_Resource_Link($consumer, $_SESSION[LTI_SESSION_PREFIX . 'userresourcelink']); // If there is a membership service then offer appropriate options if ($resource_link->hasMembershipsService()) { // Add a submenu to the users menu $plugin_page = add_users_page(__('Sync Enrolments', 'lti-text'), __('Sync Enrolments', 'lti-text'), 'administrator', __('lti_sync_enrolments', 'lti-text'), 'lti_sync_enrolments'); // Called when lti_sync_enrolments page is called add_action('admin_head-' . $plugin_page, 'lti_sync_admin_header'); } // Add a submenu to the tool menu for sharing if sharing is enabled and this is // the consumer from where the sharing was initiated. if ($_SESSION[LTI_SESSION_PREFIX . 'key'] == $_SESSION[LTI_SESSION_PREFIX . 'userkey'] && $_SESSION[LTI_SESSION_PREFIX . 'resourceid'] == $_SESSION[LTI_SESSION_PREFIX . 'userresourcelink']) { $manage_share_keys_page = add_menu_page(__('LTI Share Keys', 'lti-text'), __('LTI Share Keys', 'lti-text'), 'administrator', __('lti_manage_share_keys', 'lti-text'), 'lti_manage_share_keys', plugin_dir_url(__FILE__) . 'IMS.png'); // Image for menu item add_action('load-' . $manage_share_keys_page, 'lti_manage_share_keys_screen_options'); // Add submenus to the Manage LTI menu add_submenu_page(__('lti_manage_share_keys', 'lti-text'), __('Add New', 'lti-text'), __('Add New', 'lti-text'), 'administrator', __('lti_create_share_key', 'lti-text'), 'lti_create_share_key'); // Function to call // add_action('load-' . $manage_share_keys_page, 'manage_share_keys_screen_options'); } } }
function lti_get_share_enabled_state($key) { global $wpdb; $consumer = new LTI_Tool_Consumer($_SESSION[LTI_SESSION_PREFIX . 'key'], array($wpdb->base_prefix)); $resource = new LTI_Resource_Link($consumer, $_SESSION[LTI_SESSION_PREFIX . 'resourceid']); $shares = $resource->getShares(); foreach ($shares as $share) { if ($share->consumer_key == $key) { $reply = is_null($share->approved) ? FALSE : TRUE; return $reply; } } return FALSE; }
function lti_sync_enrolments() { global $wpdb, $blog_id; // Load class require_once 'LTI_User_List_Table.php'; // Load Membership Library functions require_once 'MembershipLibrary.php'; // Create $_SESSION variables if not present if (empty($_SESSION[LTI_SESSION_PREFIX . 'all'])) { $_SESSION[LTI_SESSION_PREFIX . 'all'] = array(); } if (empty($_SESSION[LTI_SESSION_PREFIX . 'provision'])) { $_SESSION[LTI_SESSION_PREFIX . 'provision'] = array(); } if (empty($_SESSION[LTI_SESSION_PREFIX . 'new_to_blog'])) { $_SESSION[LTI_SESSION_PREFIX . 'new_to_blog'] = array(); } if (empty($_SESSION[LTI_SESSION_PREFIX . 'newadmins'])) { $_SESSION[LTI_SESSION_PREFIX . 'newadmins'] = array(); } if (empty($_SESSION[LTI_SESSION_PREFIX . 'changed'])) { $_SESSION[LTI_SESSION_PREFIX . 'changed'] = array(); } if (empty($_SESSION[LTI_SESSION_PREFIX . 'role_changed'])) { $_SESSION[LTI_SESSION_PREFIX . 'role_changed'] = array(); } if (empty($_SESSION[LTI_SESSION_PREFIX . 'remove'])) { $_SESSION[LTI_SESSION_PREFIX . 'remove'] = array(); } if (empty($_SESSION[LTI_SESSION_PREFIX . 'nochanges'])) { $_SESSION[LTI_SESSION_PREFIX . 'nochanges'] = 0; } // Set up help tab $screen = get_current_screen(); $screen->add_help_tab(array('id' => 'my_help_tab', 'title' => __('My Help Tab', 'lti-text'), 'content' => '<p>' . __('Descriptive content that will show in My Help Tab-body goes here.', 'lti-text') . '</p>')); // Get instance of LTI_User_List_Table and get the current action $ltiuser = new LTI_User_List_Table(); $choice = $ltiuser->current_action(); $consumer = new LTI_Tool_Consumer($_SESSION[LTI_SESSION_PREFIX . 'userkey'], array($wpdb->base_prefix)); $resource_link = new LTI_Resource_Link($consumer, $_SESSION[LTI_SESSION_PREFIX . 'userresourcelink']); if (!$resource_link->hasMembershipsService()) { echo '<h2>' . __('No memberships service', 'lti-text') . '</h2>'; return; } // Deal with current action switch ($choice) { case 'continue': // Get the users from the resource link $lti_users = $resource_link->doMembershipsService(); if (!$lti_users) { echo '<h2>' . __('Error on Synchronisation', 'lti-text') . '</h2>'; echo '<p>' . sprintf(__('Error returned from consumer (%s)', 'lti-text'), $consumer->name) . '</p>'; echo '<p>' . sprintf(__('Request to consumer: %s', 'lti-text'), '<br />' . urldecode(str_replace('&', '<br />', $resource_link->ext_request))) . '</p>'; echo '<p>' . sprintf(__('Response from consumer: %s', 'lti-text'), '<br />' . $resource_link->ext_response) . '</p>'; return; } // Get straight-forward list to work with in WordPress $membership_consumer = lti_create_user_list($lti_users); // Get current membership of this blog $wp_user_search = new WP_User_Query($blog_id); $current_members = $wp_user_search->get_results(); // Create the various lists $membership_consumer = lti_create_membership_lists($membership_consumer); // Assign list to $_SESSION variables $_SESSION[LTI_SESSION_PREFIX . 'all'] = serialize($membership_consumer); $_SESSION[LTI_SESSION_PREFIX . 'provision'] = serialize(lti_get_members($_SESSION[LTI_SESSION_PREFIX . 'all'], 'provision')); $_SESSION[LTI_SESSION_PREFIX . 'new_to_blog'] = serialize(lti_get_members($_SESSION[LTI_SESSION_PREFIX . 'all'], 'new_to_blog')); $_SESSION[LTI_SESSION_PREFIX . 'newadmins'] = serialize(lti_get_members($_SESSION[LTI_SESSION_PREFIX . 'all'], 'newadmins')); $_SESSION[LTI_SESSION_PREFIX . 'changed'] = serialize(lti_get_members($_SESSION[LTI_SESSION_PREFIX . 'all'], 'changed')); $_SESSION[LTI_SESSION_PREFIX . 'role_changed'] = serialize(lti_get_members($_SESSION[LTI_SESSION_PREFIX . 'all'], 'rchanged')); // Blog members for removal need to be handled differently $_SESSION[LTI_SESSION_PREFIX . 'remove'] = serialize(lti_deleted_members($membership_consumer, $current_members)); case 'all': // Not currently used // Display all the members from the consumer lti_display($_SESSION[LTI_SESSION_PREFIX . 'all'], $ltiuser); break; case 'provision': // Not currently used echo "<h2>" . __('Membership Synchronisation - New Members', 'lti-text') . "</h2>"; if (!empty($_SESSION[LTI_SESSION_PREFIX . 'provision'])) { lti_display($_SESSION[LTI_SESSION_PREFIX . 'provision'], $ltiuser); } break; // Display the various lists // Display the various lists case 'new_to_blog': // Not currently used echo "<h2>" . __('Membership Synchronisation - New Blog Members', 'lti-text') . "</h2>"; if (!empty($_SESSION[LTI_SESSION_PREFIX . 'new_to_blog'])) { lti_display($_SESSION[LTI_SESSION_PREFIX . 'new_to_blog'], $ltiuser); } break; case 'newadmins': echo "<h2>" . __('Membership Synchronisation - New Administrators to Blog', 'lti-text') . "</h2>"; if (!empty($_SESSION[LTI_SESSION_PREFIX . 'newadmins'])) { lti_display($_SESSION[LTI_SESSION_PREFIX . 'newadmins'], $ltiuser); } break; case 'changed': // Not currently used echo "<h2>" . __('Membership Synchronisation - Changed Members', 'lti-text') . "</h2>"; if (!empty($_SESSION[LTI_SESSION_PREFIX . 'changed'])) { lti_display($_SESSION[LTI_SESSION_PREFIX . 'changed'], $ltiuser); } break; case 'rchanged': echo "<h2>" . __('Membership Synchronisation - Role Changed', 'lti-text') . "</h2>"; if (!empty($_SESSION[LTI_SESSION_PREFIX . 'role_changed'])) { lti_display($_SESSION[LTI_SESSION_PREFIX . 'role_changed'], $ltiuser); } break; case 'remove': echo "<h2>" . __('Membership Synchronisation - Members for Removal from Blog', 'lti-text') . "</h2>"; if (!empty($_SESSION[LTI_SESSION_PREFIX . 'remove'])) { lti_display($_SESSION[LTI_SESSION_PREFIX . 'remove'], $ltiuser); } break; case 'error': echo "<h2>" . __('Synchronisation Errors', 'lti-text') . "</h2>"; echo "<p>" . $_SESSION[LTI_SESSION_PREFIX . 'error'] . "</p>"; echo "<p>" . __('Remaining users from consumer added', 'lti-text') . "</p>"; $_SESSION[LTI_SESSION_PREFIX . 'error'] = ''; break; default: // If consumer has setting service then get date/time of last synchronisation $last_sync = ''; if ($resource_link->hasSettingService()) { $last_sync = $resource_link->doSettingService(LTI_Resource_Link::EXT_READ, NULL); } // Simply produce descriptive text when page first encountered. ?> <h2><?php _e('Membership Synchronisation', 'lti-text'); ?> </h2> <p><?php _e('This page allows you to update this group with any changes to the enrolments in the course which is the source for this group. These updates may include:', 'lti-text'); ?> </p> <ul style="list-style-type: disc; margin-left: 15px; padding-left: 15px;"> <li><?php _e('new members', 'lti-text'); ?> </li> <li><?php _e('changes to the names of existing members', 'lti-text'); ?> </li> <li><?php _e('changes to the type (instructor or student) of an existing member', 'lti-text'); ?> </li> <li><?php _e('deletion of members which no longer exist in the course', 'lti-text'); ?> </li> </ul> <p><?php _e('Click on the <i>Continue</i> to obtain a list of the changes to be processed. The updates will not be made until you confirm them.', 'lti-text'); ?> </p> <?php if (!empty($last_sync)) { echo '<p>' . sprintf(__('Last Synchronisation: %s', 'lti-text'), $last_sync) . '</p>'; } ?> <form method="post" action="<?php get_admin_url(); ?> users.php?page=lti_sync_enrolments"> <input type="hidden" name="action" value="continue" /> <p class="submit"> <input id="membership" class="button-primary" type="submit" value="<?php _e('Continue', 'lti-text'); ?> " name="membership"> </p> </form> <?php // Set sessions changes to 0 $_SESSION[LTI_SESSION_PREFIX . 'nochanges'] = 0; } }
/** * Get the grade * * @param $userId * @throws \Tk\Exception * @return float */ public function getGrade($userId) { $consumer = new \LTI_Tool_Consumer($this->consumerKey, $this->getConfig()->getLtiDataConnector()); $resource = new \LTI_Resource_Link($consumer, $this->resourceId); $user = new \LTI_User($resource, $userId); $ltiOutcome = new \LTI_Outcome(); if (!$resource->doOutcomesService(\LTI_Resource_Link::EXT_READ, $ltiOutcome, $user)) { throw new \Tk\Exception('Error reading from grade-center.'); } return $ltiOutcome->getValue(); }