Skip to content

Commit

Permalink
Add support for Course Groups service
Browse files Browse the repository at this point in the history
Spec is not yet published by IMS but is in use by some LTI systems
  • Loading branch information
spvickers committed Feb 17, 2021
1 parent 9e05de5 commit 0c3878b
Show file tree
Hide file tree
Showing 11 changed files with 392 additions and 10 deletions.
12 changes: 12 additions & 0 deletions src/ApiHook/ApiContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,24 @@ public function __construct($context)

/**
* Check if the API hook has been configured.
*
* @return bool True if the API hook has been configured
*/
public function isConfigured()
{
return true;
}

/**
* Get course group sets and groups.
*
* @return bool True if the request was successful
*/
public function getGroups()
{
return false;
}

/**
* Get Memberships.
*
Expand Down
5 changes: 5 additions & 0 deletions src/ApiHook/ApiHook.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ trait ApiHook
*/
public static $CONTEXT_ID_HOOK = "ContextId";

/**
* Course Groups service hook name.
*/
public static $GROUPS_SERVICE_HOOK = "Groups";

/**
* Memberships service hook name.
*/
Expand Down
6 changes: 6 additions & 0 deletions src/ApiHook/canvas/CanvasApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ trait CanvasApi

/**
* Check if the API hook has been configured.
*
* @return bool True if the API hook has been configured
*/
public function isConfigured()
{
Expand Down Expand Up @@ -117,6 +119,8 @@ private function setGroupSets($perPage, $prefix)
}
}
} while ($url);

return $http->ok;
}

/**
Expand Down Expand Up @@ -288,6 +292,8 @@ private function setGroups($perPage, $users)
}
}
} while ($url);

return $http->ok;
}

}
26 changes: 26 additions & 0 deletions src/ApiHook/canvas/CanvasApiContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,32 @@ public function __construct($context)
$this->sourceObject = $context;
}

/**
* Get course group sets and groups.
*
* @return bool True if the request was successful
*/
public function getGroups()
{
$ok = false;
$platform = $this->sourceObject->getPlatform();
$this->domain = $platform->getSetting('canvas.domain');
$this->token = $platform->getSetting('canvas.token');
$this->courseId = $this->sourceObject->getSetting('custom_canvas_course_id');
$perPage = $platform->getSetting('canvas.per_page', strval(self::$DEFAULT_PER_PAGE));
if (!is_numeric($perPage)) {
$perPage = self::$DEFAULT_PER_PAGE;
}
$prefix = $platform->getSetting('canvas.group_set_prefix');
if ($this->domain && $this->token && $this->courseId) {
if ($this->setGroupSets($perPage, $prefix)) {
$ok = $this->setGroups($perPage, array());
}
}

return $ok;
}

/**
* Get memberships.
*
Expand Down
6 changes: 6 additions & 0 deletions src/ApiHook/moodle/MoodleApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ trait MoodleApi

/**
* Check if the API hook has been configured.
*
* @return bool True if the API hook has been configured
*/
public function isConfigured()
{
Expand Down Expand Up @@ -93,6 +95,7 @@ private function get($withGroups)
*/
private function setGroupings($prefix)
{
$ok = false;
$this->sourceObject->groupSets = array();
$this->sourceObject->groups = array();
$params = array(
Expand All @@ -109,6 +112,7 @@ private function setGroupings($prefix)
);
$groupings = $this->callMoodleApi('core_group_get_groupings', $params);
if (is_array($groupings)) {
$ok = true;
foreach ($groupings as $grouping) {
if (!empty($grouping->groups) && (empty($prefix) || (strpos($grouping->name, $prefix) === 0))) {
$groupingId = strval($grouping->id);
Expand All @@ -123,6 +127,8 @@ private function setGroupings($prefix)
}
}
}

return $ok;
}

/**
Expand Down
27 changes: 27 additions & 0 deletions src/ApiHook/moodle/MoodleApiContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,33 @@ public function __construct($context)
$this->sourceObject = $context;
}

/**
* Get course group sets and groups.
*
* @return bool True if the request was successful
*/
public function getGroups()
{
$this->courseId = $this->context->ltiContextId;
$platform = $this->sourceObject->getPlatform();
$this->url = $platform->getSetting('moodle.url');
$this->token = $platform->getSetting('moodle.token');
$perPage = $platform->getSetting('moodle.per_page', '');
if (!is_numeric($perPage)) {
$perPage = self::$DEFAULT_PER_PAGE;
} else {
$perPage = intval($perPage);
}
$prefix = $platform->getSetting('moodle.grouping_prefix');
if ($this->url && $this->token && $this->courseId) {
$ok = $this->setGroupings($prefix);
} else {
$ok = false;
}

return $ok;
}

/**
* Get Memberships.
*
Expand Down
73 changes: 66 additions & 7 deletions src/Context.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,27 @@ class Context
public $type = null;

/**
* UserResult group sets (null if the platform does not support the groups enhancement)
* User group sets (null if the platform does not support the groups enhancement)
*
* A group set is represented by an associative array with the following elements:
* - title
* - groups (array of group IDs)
* - num_members
* - num_staff
* - num_learners
* The array key value is the group set ID.
*
* @var array|null $groupSets
*/
public $groupSets = null;

/**
* UserResult groups (null if the platform does not support the groups enhancement)
* User groups (null if the platform does not support the groups enhancement)
*
* A group is represented by an associative array with the following elements:
* - title
* - set (ID of group set, omitted if the group is not part of a set)
* The array key value is the group ID.
*
* @var array|null $groups
*/
Expand Down Expand Up @@ -418,6 +431,43 @@ public function setToolSettings($settings = array())
return $ok;
}

/**
* Check if a Course Group service is available.
*
* @return bool True if this context supports a Course Group service
*/
public function hasGroupService()
{
$has = !empty($this->getSetting('custom_context_groups_url'));
if (!$has) {
$has = self::hasConfiguredApiHook(self::$MEMBERSHIPS_SERVICE_HOOK, $this->getPlatform()->getFamilyCode(), $this);
}
return $has;
}

/**
* Get course group sets and groups.
*
* @return bool True if the request was successful
*/
public function getGroups()
{
$groupsUrl = $this->getSetting('custom_context_groups_url');
$groupsetsUrl = $this->getSetting('custom_context_group_sets_url');
$service = new Service\Groups($this, $groupsUrl, $groupsetsUrl);
$ok = $service->get();
if (!empty($service->getHttpMessage())) {
$this->lastServiceRequest = $service->getHttpMessage();
}
if (!$ok && $this->hasConfiguredApiHook(self::$GROUPS_SERVICE_HOOK, $this->getPlatform()->getFamilyCode(), $this)) {
$className = $this->getApiHook(self::$GROUPS_SERVICE_HOOK, $this->getPlatform()->getFamilyCode());
$hook = new $className($this);
$ok = $hook->getGroups();
}

return $ok;
}

/**
* Check if the Membership service is supported.
*
Expand Down Expand Up @@ -473,19 +523,28 @@ public function getMemberships($withGroups = false)
{
$ok = false;
$userResults = array();
$hasLtiService = !empty($this->getSetting('custom_context_memberships_url')) || !empty($this->getSetting('custom_context_memberships_v2_url'));
$hasMembershipsService = !empty($this->getSetting('custom_context_memberships_url'));
$hasNRPService = !empty($this->getSetting('custom_context_memberships_v2_url'));
$hasGroupsService = !empty($this->getSetting('custom_context_groups_url')) ||
$this->hasConfiguredApiHook(self::$GROUPS_SERVICE_HOOK, $this->getPlatform()->getFamilyCode(), $this);
$hasApiHook = $this->hasConfiguredApiHook(self::$MEMBERSHIPS_SERVICE_HOOK, $this->getPlatform()->getFamilyCode(), $this);
if ($hasLtiService && (!$withGroups || !$hasApiHook)) {
if (!empty($this->getSetting('custom_context_memberships_v2_url'))) {
if (($hasMembershipsService || $hasNRPService) && (!$withGroups || ($hasNRPService && $hasGroupsService) || !$hasApiHook)) {
if ($hasNRPService) {
$url = $this->getSetting('custom_context_memberships_v2_url');
$format = Service\Membership::MEDIA_TYPE_MEMBERSHIPS_NRPS;
} else {
$url = $this->getSetting('custom_context_memberships_url');
$format = Service\Membership::MEDIA_TYPE_MEMBERSHIPS_V1;
}
$service = new Service\Membership($this, $url, $format);
$userResults = $service->get();
$this->lastServiceRequest = $service->getHttpMessage();
if (!$withGroups || !$hasNRPService) {
$userResults = $service->get();
} else {
$userResults = $service->getWithGroups();
}
if (!empty($service->getHttpMessage())) {
$this->lastServiceRequest = $service->getHttpMessage();
}
$ok = $userResults !== false;
}
if (!$ok && $hasApiHook) {
Expand Down
17 changes: 15 additions & 2 deletions src/ResourceLink.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,27 @@ class ResourceLink
public $ltiResourceLinkId = null;

/**
* UserResult group sets (null if the platform does not support the groups enhancement)
* User group sets (null if the platform does not support the groups enhancement)
*
* A group set is represented by an associative array with the following elements:
* - title
* - groups (array of group IDs)
* - num_members
* - num_staff
* - num_learners
* The array key value is the group set ID.
*
* @var array|null $groupSets
*/
public $groupSets = null;

/**
* UserResult groups (null if the platform does not support the groups enhancement)
* User groups (null if the platform does not support the groups enhancement)
*
* A group is represented by an associative array with the following elements:
* - title
* - set (ID of group set, omitted if the group is not part of a set)
* The array key value is the group ID.
*
* @var array|null $groups
*/
Expand Down
Loading

0 comments on commit 0c3878b

Please sign in to comment.