diff --git a/LTI-Tool-Provider-Library-PHP b/LTI-Tool-Provider-Library-PHP
index 44f54b1..488d5de 160000
--- a/LTI-Tool-Provider-Library-PHP
+++ b/LTI-Tool-Provider-Library-PHP
@@ -1 +1 @@
-Subproject commit 44f54b11c547570baa538634dbb8ceb7ba0b70f8
+Subproject commit 488d5deab56776d3f28cefa272ef1c054541d300
diff --git a/LTIPlugin.php b/LTIPlugin.php
index e11e3d4..0faabed 100644
--- a/LTIPlugin.php
+++ b/LTIPlugin.php
@@ -28,6 +28,65 @@
use IMSGlobal\LTI\OAuth\OAuthServer;
use IMSGlobal\LTI\OAuth\OAuthSignatureMethod_HMAC_SHA1;
use IMSGlobal\LTI\OAuth\OAuthRequest;
+use IMSGlobal\LTI\ToolProvider;
+
+class LTIResourceLink extends ToolProvider\ResourceLink
+{
+ public function setConsumer($consumer)
+ {
+ $this->consumer = $consumer;
+ }
+}
+
+class LTIConsumer
+{
+ public $secret;
+ private $key;
+ public function getKey()
+ {
+ return $this->key;
+ }
+ public function __construct($key,$secret)
+ {
+ $this->secret = $secret;
+ $this->key = $key;
+ }
+}
+
+
+class LTIResource
+{
+ public $outcomeServiceURL;
+ public function getSetting($setting)
+ {
+ if ($setting == "lis_outcome_service_url") {
+ return $this->outcomeServiceURL;
+ }
+ return false;
+ }
+ public function __construct($outcomeserviceurl)
+ {
+ $this->outcomeServiceURL = $outcomeserviceurl;
+ }
+}
+
+
+class LTIUser
+{
+ public $ltiResultSourcedId;
+ private $resourceLink;
+
+ public function getResourceLink()
+ {
+ return $this->resourceLink;
+ }
+
+ public function __construct($outcomeserviceurl,$sourceid) {
+ $this->ltiResultSourcedId = $sourceid;
+ $this->resourceLink = new LTIResource($outcomeserviceurl);
+ }
+}
+
class LTIPlugin extends PluginBase
{
@@ -41,6 +100,7 @@ public function init()
$this->subscribe('newSurveySettings');
$this->subscribe('newDirectRequest'); //for LTI call
$this->subscribe('newUnsecureRequest', 'newDirectRequest'); //for LTI call
+ $this->subscribe('afterSurveyComplete'); //for LTI result return
}
protected $settings = [
@@ -86,6 +146,18 @@ public function init()
'label' => 'Optional: The LTI attributes that stores the last name of the participant',
'help' => 'Leave blank for no data to be stored. For openEdX and Canvas it appears to be lis_person_name_family. This maps to lastname in your participant table'
],
+ 'sResultSourceAttribute' => [
+ 'type' => 'string',
+ 'default' => 'lis_result_sourcedid',
+ 'label' => 'Optional: The LTI attributes that stores the result sourcedid - this is required when you want to return a result to the LMS. The default appears to be lis_result_sourcedid',
+ 'help' => 'Leave blank for no data to be stored. This maps to ATTRIBUTE_5'
+ ],
+ 'sOutcomeServiceURLAttribute' => [
+ 'type' => 'string',
+ 'default' => 'lis_outcome_service_url',
+ 'label' => 'Optional: The LTI attributes that stores the outcome service URL - this is required when you want to return a result to the LMS',
+ 'help' => 'Leave blank for no data to be stored. This maps to ATTRIBUTE_6. The default appears to be lis_outcome_service_url'
+ ],
'bDebugMode' => [
'type' => 'select',
'options' => [
@@ -150,7 +222,6 @@ public function newDirectRequest()
// Get the current token count
$tokenCount = $multipleCompletions ? 0 : (int) Token::model($surveyId)->countByAttributes($tokenQuery);
-
// If no token, then create a new one and start survey
if ($multipleCompletions || $tokenCount === 0) {
$firstname = $params[$this->get('sFirstNameAttribute', null, null, $this->settings['sFirstNameAttribute'])] ?? '';
@@ -164,8 +235,15 @@ public function newDirectRequest()
'lastname' => $lastname,
'email' => $email
];
+ $tokenReturn = [];
+ if (!empty($this->get('sReturnExpression', 'Survey', $surveyId))) {
+ $tokenReturn = [
+ 'attribute_5' => $params[$this->get('sResultSourceAttribute', null, null, $this->settings['sResultSourceAttribute'])] ?? '',
+ 'attribute_6' => $params[$this->get('sOutcomeServiceURLAttribute', null, null, $this->settings['sOutcomeServiceURLAttribute'])] ?? ''
+ ];
+ }
$token = Token::create($surveyId);
- $token->setAttributes(array_merge($tokenQuery, $tokenAdd));
+ $token->setAttributes(array_merge($tokenQuery, $tokenAdd, $tokenReturn));
$token->generateToken();
if (!$token->save()) {
@@ -199,6 +277,39 @@ public function newDirectRequest()
Yii::app()->getController()->redirect($redirectUrl);
}
+ /**
+ * If result return is enabled - send a result back
+ */
+ public function afterSurveyComplete()
+ {
+ $event = $this->event;
+ $surveyId = $event->get('surveyId');
+
+ $rr = $this->get('sReturnExpression', 'Survey', $surveyId);
+
+ if (!empty($rr)) { //return the assessment value
+ $survey = Survey::model()->findByPk($surveyId);
+ if (isset($survey->tokenAttributes['attribute_5']) &&
+ isset($survey->tokenAttributes['attribute_6'])) {
+
+ $responseId = $event->get('responseId');
+ $response = $this->api->getResponse($surveyId, $responseId);
+ $token = Token::model($surveyId)->findByToken($response['token']);
+ $pr = LimeExpressionManager::ProcessString($rr, null, array(), 3, 1, false, false, true);
+ if (!empty($token->attribute_5) && !empty($token->attribute_6)) {
+ //send result back
+ $lti_outcome = new ToolProvider\Outcome($pr);
+ $resource_link = new LTIResourceLink();
+ $consumer = new LTIConsumer($this->get('sAuthKey', 'Survey', $surveyId),$this->get('sAuthSecret', 'Survey', $surveyId));
+ $resource_link->setConsumer($consumer);
+ $user = new LTIUser($token->attribute_6,$token->attribute_5);
+ $res = $resource_link->doOutcomesService(ToolProvider\ResourceLink::EXT_WRITE, $lti_outcome, $user);
+ }
+ }
+ }
+ }
+
+
/**
* Add setting on survey level: provide URL for LTI connector and check that tokens table / attributes exist
*/
@@ -214,11 +325,17 @@ public function beforeSurveySettings()
$info = 'Please activate the survey before continuing';
}
+ $rr = $this->get('sReturnExpression', 'Survey', $event->get('survey'));
+
if (!(isset($survey->tokenAttributes['attribute_1']) &&
isset($survey->tokenAttributes['attribute_2']) &&
isset($survey->tokenAttributes['attribute_3']) &&
- isset($survey->tokenAttributes['attribute_4']))) {
- $info = 'Please ensure the survey participant function has been enabled, and that there at least 4 attributes created';
+ isset($survey->tokenAttributes['attribute_4']))
+ || ((!empty($rr)) &&
+ !(isset($survey->tokenAttributes['attribute_5']) &&
+ isset($survey->tokenAttributes['attribute_6'])))
+ ) {
+ $info = 'Please ensure the survey participant function has been enabled, and that there at least ' . (empty($rr) ? "4" : "6") . ' attributes created';
}
$apiKey = $this->get('sAuthKey', 'Survey', $event->get('survey'));
@@ -267,6 +384,12 @@ public function beforeSurveySettings()
'label' => 'Allow a user in a course to complete this survey more than once',
'help' => 'This will allow multiple tokens to be created for the same user each time they go to access the survey'
],
+ 'sReturnExpression' => [
+ 'type' => 'string',
+ 'label' => 'If returning a result, please enter the text or expression you wish to return here. Leave blank to not return a result. LMS systems typically accept a value between 0 and 1',
+ 'help' => 'For example, {A1} will return whatever was stored in question A1, 1 will just return the score of 1',
+ 'current' => $this->get('sReturnExpression', 'Survey', $event->get('survey')),
+ ],
'sInfo' => [
'type' => 'info',
'label' => 'The URL to access this survey via the LTI Provider',
diff --git a/README.md b/README.md
index 1b2728c..1f5c15b 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,18 @@
# LTIPlugin
LimeSurvey Plugin that allows LimeSurvey to act as an LTI provider for tools such as Moodle, Canvas and openEdX. LimeSurvey will have access to the LMS course name and course and student identifier and allow the completion of a survey.
+This plugin can also be used to return a grade/score/result back to the LMS based on a LimeSurvey expression. Therefore this plugin can be used to administer an exam or quiz in LimeSurvey which calculates a score and returns it automatically to the LMS.
## Installation
Download the zip from the [releases](https://github.com/adamzammit/LTIPlugin/releases) page and extract to your plugins folder. You can also clone directly from git: go to your plugins directory and type
```
-git clone https://github.com/adamzammit/LTIPlugin.git LTIPlugin
+git clone --recursive https://github.com/adamzammit/LTIPlugin.git LTIPlugin
```
## Requirements
-- LimeSurvey version 3.x, 4.x
-- Surveys need to be activated, with a participant table set up with at least 4 attributes avaiable (the plugin will use the first 4 attributes for LTI related data)
+- LimeSurvey version 3.x, 4.x, 5.x
+- Surveys need to be activated, with a participant table set up with at least 4 attributes avaiable, 6 attributes if you want to return a grade/result (the plugin will use the first 4 or 6 attributes for LTI related data)
- If your LTI Provider is running on HTTPS, then LimeSurvey must run over HTTPS also
## Configuration (LimeSurvey)
@@ -27,6 +28,32 @@ git clone https://github.com/adamzammit/LTIPlugin.git LTIPlugin
9. A random key and password should be generated - save the settings then a URL to access should be displayed (otherwise a message will be displayed notifying of the requirements for the LTI plugin as above)
10. Use the URL listed and the key and secret generated to set up your LMS to use LimeSUrvey as an LTI Provider (see below for examples)
11. By default a course participant will be able to complete the survey only once, and will return to the previous point of completion when visiting the survey again if not completed. If you want them to be able to complete multiple times for the same unit - please set "Allow a user in a course to complete this survey more than once" to "Yes"
+12. If you want to return a grade/score backto the LMS - enter a text or expression in the return result box. You can just put the number 1 if you want 100% returned on completion, otherwise you can use any valid LimeSurvey expression to send a calculated value (this could be used to send back a score on an exam for example). The value should always be a floating point number between 0.0 and 1.0
+
+
+### Configuration and usage (Canvas)
+
+1. Edit your course
+2. In your course, visit "Settings" then the tab "Apps", then "View App Configurations", then click on the green "+_App" button
+3. Choose "Manual entry" for your configuration type
+4. Name the app
+5. Copy the consumer key, secret and Launch URL from the LimeSurvey LTIPlugin settings page (under Simple plugins in your LimeSurvey survey)
+
+Now that the application is configured, you can:
+1. Add a new item to a module in your course, and choose "External Tool" then the name of your app and don't forget to "publish"
+2. If you add as an "Assignment" and you have the return result set in LimeSurvey simple plugin settings, the score will be returned
+
+If you have recieved a "CSRF Token" error in LimeSurvey you may need to check the box "Load in a new tab" when editing the item in Canvas
+
+### Configuration and Usage (Moodle)
+
+1. Add a new "Activity or resource"
+2. Choose "External Tool"
+3. The "Tool URL" is the URL that appears on the "Settings for plugin LTI Plugin" page for your survey
+4. Click on "Show more" under "General"
+5. The "Consumer key" is the key that appears on the LTI plugin settings page
+6. The "Shared secret" is the secret that appears on the LTI plugin settings page
+
### Configuration (OpenEdX)
@@ -45,16 +72,6 @@ git clone https://github.com/adamzammit/LTIPlugin.git LTIPlugin
If you have recieved a "CSRF Token" error in LimeSurvey you may need to set "LTI Launch Target" to "New Window" in OpenEdX to overcome this.
-### Configuration and Usage (Moodle)
-
-1. Add a new "Activity or resource"
-2. Choose "External Tool"
-3. The "Tool URL" is the URL that appears on the "Settings for plugin LTI Plugin" page for your survey
-4. Click on "Show more" under "General"
-5. The "Consumer key" is the key that appears on the LTI plugin settings page
-6. The "Shared secret" is the secret that appears on the LTI plugin settings page
-
-
### Usage (OpenEdX)
1. Add a new "Unit"
diff --git a/config.xml b/config.xml
index 0f77566..d978a0c 100644
--- a/config.xml
+++ b/config.xml
@@ -4,12 +4,12 @@
LTIPlugin
plugin
2020-08-27
- 2021-10-13
+ 2021-10-14
Adam Zammit
https://acspri.org.au/
software@acspri.org.au
https://acspri.org.au/
- 1.0.7
+ 1.0.8
GNU General Public License v3.0