From c3768f8208f96fb2275fcee796272f19807f3923 Mon Sep 17 00:00:00 2001
From: Andrew Gardener
Date: Wed, 30 Sep 2020 13:51:03 -0700
Subject: [PATCH] Add LTI 1.3
---
.gitignore | 1 +
Dockerfile | 4 +-
Dockerfile-app-unittest | 4 +-
app/config/core.php | 4 +-
app/config/sql/delta_18.sql | 91 +
app/config/sql/ipeer.sql | 5 +-
app/config/sql/ipeer_samples_data.sql | 132 +-
app/controllers/components/lti_requester.php | 103 -
app/controllers/components/lti_verifier.php | 288 ---
app/controllers/courses_controller.php | 11 +-
app/controllers/lti_controller.php | 297 +--
.../ltitoolregistrations_controller.php | 130 +
app/libs/caliper/entity.php | 3 -
app/libs/lti.php | 24 +
app/libs/lti/launch_data_parser.php | 258 ++
app/libs/lti/lti_cache.php | 47 +
app/libs/lti/lti_cookie.php | 37 +
app/libs/lti/lti_database.php | 53 +
app/libs/lti/names_and_roles_service.php | 136 +
.../names_and_roles_service_data_parser.php | 144 ++
app/libs/upgrade_scripts/upgrade_349.php | 58 +
app/locale/default.pot | 8 +
app/models/course.php | 5 +
app/models/event.php | 15 +-
app/models/lti_context.php | 152 ++
app/models/lti_nonce.php | 43 +
app/models/lti_resource_link.php | 87 +
app/models/lti_tool_registration.php | 158 ++
app/models/lti_user.php | 162 ++
app/models/user.php | 18 +-
.../caliper/app_controller_hooks.test.php | 2 +
app/tests/cases/caliper/course_hooks.test.php | 2 +
.../caliper/event_mixeval_hooks.test.php | 2 +
.../cases/caliper/event_rubric_hooks.test.php | 2 +
.../event_simple_evaulation_hooks.test.php | 2 +
.../cases/caliper/event_survey_hooks.test.php | 2 +
.../cases/caliper/mixeval_hooks.test.php | 2 +
app/tests/cases/caliper/rubric_hooks.test.php | 2 +
.../caliper/simple_evaluation_hooks.test.php | 2 +
app/tests/cases/caliper/survey_hooks.test.php | 2 +
.../components/evaluation_component.test.php | 22 +-
.../controllers/accesses_controller.test.php | 46 +-
.../controllers/courses_controller.test.php | 5 +-
.../departments_controller.test.php | 2 +
.../controllers/evaltools_controller.test.php | 2 +
.../evaluations_controller.test.php | 10 +-
.../controllers/events_controller.test.php | 2 +
.../controllers/faculties_controller.test.php | 2 +
.../controllers/groups_controller.test.php | 2 +
.../controllers/home_controller.test.php | 4 +-
.../cases/controllers/lti_controller.test.php | 2183 +++++++++++++++++
.../controllers/mixevals_controller.test.php | 2 +
.../oauth_clients_controller.test.php | 2 +
.../oauth_tokens_controller.test.php | 2 +
.../controllers/rubrics_controller.test.php | 32 +-
.../controllers/searchs_controller.test.php | 2 +
.../simpleevaluations_controller.test.php | 2 +
.../surveygroups_controller.test.php | 2 +
.../controllers/surveys_controller.test.php | 2 +
.../sysparameters_controller.test.php | 2 +
.../cases/controllers/v1_controller.test.php | 24 +-
app/tests/cases/models/access.test.php | 26 +-
app/tests/cases/models/course.test.php | 2 +
.../cases/models/course_department.test.php | 13 +-
app/tests/cases/models/department.test.php | 2 +
app/tests/cases/models/email_merge.test.php | 2 +
.../cases/models/email_schedule.test.php | 2 +
.../cases/models/email_template.test.php | 2 +
.../cases/models/evaluation_mixeval.test.php | 4 +-
.../models/evaluation_mixeval_detail.test.php | 2 +
.../cases/models/evaluation_rubric.test.php | 2 +
.../models/evaluation_rubric_detail.test.php | 2 +
.../cases/models/evaluation_simple.test.php | 2 +
.../models/evaluation_submission.test.php | 2 +
app/tests/cases/models/event.test.php | 2 +
.../cases/models/event_template_type.test.php | 2 +
app/tests/cases/models/faculty.test.php | 11 +-
app/tests/cases/models/group.test.php | 2 +
app/tests/cases/models/group_event.test.php | 2 +
.../cases/models/groups_members.test.php | 2 +
.../models/lti_tool_registration.test.php | 66 +
app/tests/cases/models/mixeval.test.php | 4 +-
.../cases/models/mixeval_question.test.php | 4 +-
.../models/mixeval_question_desc.test.php | 6 +-
app/tests/cases/models/oauth_client.test.php | 12 +-
app/tests/cases/models/oauth_token.test.php | 12 +-
app/tests/cases/models/penalty.test.php | 18 +-
app/tests/cases/models/personalize.test.php | 2 +
app/tests/cases/models/question.test.php | 4 +-
app/tests/cases/models/response.test.php | 2 +
app/tests/cases/models/roles_user.test.php | 11 +-
app/tests/cases/models/rubric.test.php | 2 +
app/tests/cases/models/rubric_lom.test.php | 2 +
.../cases/models/rubrics_criteria.test.php | 2 +
.../models/rubrics_criteria_comment.test.php | 2 +
.../cases/models/simple_evaluation.test.php | 4 +-
app/tests/cases/models/survey.test.php | 2 +
app/tests/cases/models/survey_group.test.php | 2 +
.../cases/models/survey_group_member.test.php | 2 +
.../cases/models/survey_group_set.test.php | 4 +-
app/tests/cases/models/survey_input.test.php | 2 +
.../cases/models/survey_question.test.php | 4 +-
app/tests/cases/models/sys_parameter.test.php | 8 +-
app/tests/cases/models/user.test.php | 2 +
app/tests/cases/models/user_course.test.php | 10 +-
app/tests/cases/models/user_enrol.test.php | 2 +
app/tests/fixtures/lti_context_fixture.php | 15 +
app/tests/fixtures/lti_nonce_fixture.php | 15 +
.../fixtures/lti_resource_link_fixture.php | 15 +
.../lti_tool_registration_fixture.php | 16 +
app/tests/fixtures/lti_user_fixture.php | 15 +
app/views/courses/home.ctp | 16 +-
app/views/elements/courses/submenu.ctp | 7 +
app/views/lti/index.ctp | 10 -
app/views/lti_tool_registrations/add.ctp | 70 +
app/views/lti_tool_registrations/edit.ctp | 70 +
app/views/lti_tool_registrations/index.ctp | 47 +
app/views/pages/admin.ctp | 9 +
build/sqlclean/superadmin.sql | 4 +-
composer.json | 71 +-
composer.lock | 425 +++-
docker-compose.yml | 10 +-
readme.md | 4 +-
version.txt | 2 +-
124 files changed, 5066 insertions(+), 880 deletions(-)
create mode 100644 app/config/sql/delta_18.sql
delete mode 100644 app/controllers/components/lti_requester.php
delete mode 100644 app/controllers/components/lti_verifier.php
create mode 100644 app/controllers/ltitoolregistrations_controller.php
create mode 100644 app/libs/lti.php
create mode 100644 app/libs/lti/launch_data_parser.php
create mode 100644 app/libs/lti/lti_cache.php
create mode 100644 app/libs/lti/lti_cookie.php
create mode 100644 app/libs/lti/lti_database.php
create mode 100644 app/libs/lti/names_and_roles_service.php
create mode 100644 app/libs/lti/names_and_roles_service_data_parser.php
create mode 100644 app/libs/upgrade_scripts/upgrade_349.php
create mode 100644 app/models/lti_context.php
create mode 100644 app/models/lti_nonce.php
create mode 100644 app/models/lti_resource_link.php
create mode 100644 app/models/lti_tool_registration.php
create mode 100644 app/models/lti_user.php
create mode 100644 app/tests/cases/controllers/lti_controller.test.php
create mode 100644 app/tests/cases/models/lti_tool_registration.test.php
create mode 100644 app/tests/fixtures/lti_context_fixture.php
create mode 100644 app/tests/fixtures/lti_nonce_fixture.php
create mode 100644 app/tests/fixtures/lti_resource_link_fixture.php
create mode 100644 app/tests/fixtures/lti_tool_registration_fixture.php
create mode 100644 app/tests/fixtures/lti_user_fixture.php
delete mode 100644 app/views/lti/index.ctp
create mode 100644 app/views/lti_tool_registrations/add.ctp
create mode 100644 app/views/lti_tool_registrations/edit.ctp
create mode 100644 app/views/lti_tool_registrations/index.ctp
diff --git a/.gitignore b/.gitignore
index 08d69b1b5..a0dafff54 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,3 +19,4 @@ tags
vendor/
.idea
.data
+.DS_Store
diff --git a/Dockerfile b/Dockerfile
index f15f14efe..af1468a3d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -10,7 +10,7 @@ RUN apt-get update && apt-get install --no-install-recommends --no-install-sugge
&& rm -rf /var/lib/apt/lists/* \
&& ln -s /usr/lib/x86_64-linux-gnu/libldap.so /usr/lib/libldap.so \
&& ln -s /usr/lib/x86_64-linux-gnu/liblber.so /usr/lib/liblber.so \
- && docker-php-ext-install -j$(nproc) xml gd ldap mysqli \
+ && docker-php-ext-install -j$(nproc) xml gd ldap mysqli intl \
&& pecl install timezonedb xdebug\
&& docker-php-ext-enable timezonedb xdebug\
&& curl https://getcomposer.org/download/1.8.4/composer.phar -o /usr/local/bin/composer \
@@ -21,7 +21,7 @@ COPY . /var/www/html
COPY docker/docker-entrypoint-php-fpm.sh /
RUN cd /var/www/html \
- && composer install --no-ansi --no-dev --no-interaction --no-plugins --no-progress --no-suggest --optimize-autoloader \
+ && composer install --no-ansi --no-dev --no-interaction --no-plugins --no-progress --no-scripts --no-suggest --optimize-autoloader \
&& mkdir -p /var/www/html/app/tmp/cache/persistent /var/www/html/app/tmp/cache/models /var/www/html/app/tmp/logs \
&& chown www-data:www-data -R /var/www/html/app/tmp/cache \
&& chown www-data:www-data -R /var/www/html/app/tmp/logs
diff --git a/Dockerfile-app-unittest b/Dockerfile-app-unittest
index 588eea5c3..6204505bc 100644
--- a/Dockerfile-app-unittest
+++ b/Dockerfile-app-unittest
@@ -12,9 +12,11 @@ RUN apt-get update && apt-get install --no-install-recommends --no-install-sugge
&& rm -rf /var/lib/apt/lists/* \
&& ln -s /usr/lib/x86_64-linux-gnu/libldap.so /usr/lib/libldap.so \
&& ln -s /usr/lib/x86_64-linux-gnu/liblber.so /usr/lib/liblber.so \
- && docker-php-ext-install -j$(nproc) xml gd ldap mysqli pdo_mysql\
+ && docker-php-ext-install -j$(nproc) xml gd ldap mysqli pdo_mysql intl \
&& pecl install timezonedb \
&& docker-php-ext-enable timezonedb \
+ && pecl install xdebug \
+ && docker-php-ext-enable xdebug \
&& curl https://getcomposer.org/download/1.8.4/composer.phar -o /usr/local/bin/composer \
&& chmod +x /usr/local/bin/composer \
&& pecl install -f oauth-2.0.2 \
diff --git a/app/config/core.php b/app/config/core.php
index 31cdcea59..e868aa68b 100644
--- a/app/config/core.php
+++ b/app/config/core.php
@@ -324,7 +324,7 @@
/**
* iPeer database version
*/
- Configure::write('DATABASE_VERSION', 17);
+ Configure::write('DATABASE_VERSION', 18);
$CWL['LoginURL'] = 'https://www.auth.cwl.ubc.ca/auth/login';
@@ -347,7 +347,7 @@
$CWL['applicationID'] = '';
$CWL['applicationPassword'] = '';
- define('IPEER_VERSION', '3.4.8');
+ define('IPEER_VERSION', '3.4.9');
/**
diff --git a/app/config/sql/delta_18.sql b/app/config/sql/delta_18.sql
new file mode 100644
index 000000000..64a32bf9f
--- /dev/null
+++ b/app/config/sql/delta_18.sql
@@ -0,0 +1,91 @@
+ALTER TABLE `courses` MODIFY `canvas_id` varchar(255) NULL DEFAULT NULL;
+ALTER TABLE `courses` ADD INDEX `canvas_id` (`canvas_id`);
+ALTER TABLE `users` DROP `lti_id`;
+
+DROP TABLE IF EXISTS `lti_tool_registrations`;
+CREATE TABLE `lti_tool_registrations` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `iss` varchar(255) NOT NULL,
+ `client_id` varchar(255) NOT NULL,
+ `auth_login_url` varchar(255) NOT NULL,
+ `auth_token_url` varchar(255) NOT NULL,
+ `key_set_url` varchar(255) NOT NULL,
+ `tool_private_key` text NOT NULL,
+ `tool_public_key` text NOT NULL,
+ `user_identifier_field` varchar(255) DEFAULT NULL,
+ `student_number_field` varchar(255) DEFAULT NULL,
+ `term_field` varchar(255) DEFAULT NULL,
+ `canvas_id_field` varchar(255) DEFAULT NULL,
+ `faculty_name_field` varchar(255) DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `iss` (`iss`),
+ KEY `client_id` (`client_id`)
+) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
+
+INSERT INTO `acos` (id, parent_id, model, foreign_key, alias, lft, rght) VALUES
+(338,2,NULL,NULL,'Ltitoolregistrations',664,673),
+(339,338,NULL,NULL,'index',665,666),
+(340,338,NULL,NULL,'add',667,668),
+(341,338,NULL,NULL,'edit',669,670),
+(342,338,NULL,NULL,'delete',671,672),
+(343,2,NULL,NULL,'Lti',673,674),
+(344,343,NULL,NULL,'roster',675,676);
+
+INSERT INTO `aros_acos` (id, aro_id, aco_id, _create, _read, _update, _delete) VALUES
+(NULL,1,338,'1','1','1','1'),
+(NULL,2,344,'1','1','1','1'),
+(NULL,3,344,'1','1','1','1'),
+(NULL,4,344,'-1','-1','-1','-1'),
+(NULL,5,344,'-1','-1','-1','-1');
+
+DROP TABLE IF EXISTS `lti_nonces`;
+CREATE TABLE `lti_nonces` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `nonce` varchar(255) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `nonce` (`nonce`)
+) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
+
+DROP TABLE IF EXISTS `lti_contexts`;
+CREATE TABLE `lti_contexts` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `lti_tool_registration_id` int(11) NOT NULL,
+ `context_id` varchar(255) NOT NULL,
+ `course_id` int(11) DEFAULT NULL,
+ `nrps_context_memberships_url` varchar(255) DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ FOREIGN KEY (`lti_tool_registration_id`) REFERENCES `lti_tool_registrations` (`id`) ON DELETE CASCADE,
+ FOREIGN KEY (`course_id`) REFERENCES `courses` (`id`) ON DELETE CASCADE,
+ UNIQUE KEY `lti_tool_registration_id_context_id` (`lti_tool_registration_id`,`context_id`)
+) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
+
+DROP TABLE IF EXISTS `lti_resource_links`;
+CREATE TABLE `lti_resource_links` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `lti_context_id` int(11) NOT NULL,
+ `resource_link_id` varchar(255) NOT NULL,
+ `event_id` int(11) DEFAULT NULL,
+ `lineitems_url` varchar(255) DEFAULT NULL,
+ `lineitem_url` varchar(255) DEFAULT NULL,
+ `scope_lineitem` INT(1) DEFAULT '0',
+ `scope_lineitem_read_only` INT(1) DEFAULT '0',
+ `scope_result_readonly` INT(1) DEFAULT '0',
+ `scope_result_score` INT(1) DEFAULT '0',
+ PRIMARY KEY (`id`),
+ FOREIGN KEY (`lti_context_id`) REFERENCES `lti_contexts` (`id`) ON DELETE CASCADE,
+ FOREIGN KEY (`event_id`) REFERENCES `events` (`id`) ON DELETE CASCADE,
+ UNIQUE KEY `lti_context_id_resource_link_id` (`lti_context_id`,`resource_link_id`)
+) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
+
+
+DROP TABLE IF EXISTS `lti_users`;
+CREATE TABLE `lti_users` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `lti_tool_registration_id` int(11) NOT NULL,
+ `lti_user_id` varchar(255) NOT NULL,
+ `ipeer_user_id` int(11) DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ FOREIGN KEY (`lti_tool_registration_id`) REFERENCES `lti_tool_registrations` (`id`) ON DELETE CASCADE,
+ FOREIGN KEY (`ipeer_user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
+ UNIQUE KEY `lti_tool_registration_id_lti_user_id` (`lti_tool_registration_id`,`lti_user_id`)
+) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
\ No newline at end of file
diff --git a/app/config/sql/ipeer.sql b/app/config/sql/ipeer.sql
index 7734ad35e..cc11c5ea5 100644
--- a/app/config/sql/ipeer.sql
+++ b/app/config/sql/ipeer.sql
@@ -369,7 +369,10 @@ INSERT INTO acos (id, parent_id, model, foreign_key, alias, lft, rght) VALUES
(331,300,NULL,NULL,'viewusername',660,661),
(332,300,NULL,NULL,'submitstudenteval',662,663),
(333,84,NULL,NULL,'export',193,194),
-(334,84,NULL,NULL,'import',195,196);
+(334,84,NULL,NULL,'import',195,196),
+(335,16,NULL,NULL,'syncCanvasEnrollment',NULL,NULL),
+(336,112,NULL,NULL,'syncCanvas',NULL,NULL),
+(337,64,NULL,NULL,'exportCanvas',NULL,NULL);
-- --------------------------------------------------------
diff --git a/app/config/sql/ipeer_samples_data.sql b/app/config/sql/ipeer_samples_data.sql
index 1c6226e88..8e181106b 100644
--- a/app/config/sql/ipeer_samples_data.sql
+++ b/app/config/sql/ipeer_samples_data.sql
@@ -2220,8 +2220,6 @@ INSERT INTO user_tutors (id, user_id, course_id, creator_id, created, updater_id
(3, 37, 2, 0, NOW(), NULL, NOW()),
(4, 37, 3, 0, NOW(), NULL, NOW());
-SET foreign_key_checks = 1;
-
------------------------
@@ -2268,7 +2266,7 @@ VALUES (
);
INSERT INTO `sys_parameters` (
- `parameter_code`, `parameter_value`, `parameter_type`,
+ `parameter_code`, `parameter_value`, `parameter_type`,
`description`, `record_status`, `creator_id`, `created`,
`updater_id`, `modified`)
VALUES (
@@ -2277,7 +2275,7 @@ VALUES (
);
INSERT INTO `sys_parameters` (
- `parameter_code`, `parameter_value`, `parameter_type`,
+ `parameter_code`, `parameter_value`, `parameter_type`,
`description`, `record_status`, `creator_id`, `created`,
`updater_id`, `modified`)
VALUES (
@@ -2311,6 +2309,7 @@ INSERT INTO `acos`
ALTER TABLE `courses` ADD COLUMN `canvas_id` VARCHAR(25) NULL DEFAULT NULL;
-- add table to store oauth access/refresh tokens and expiry timestamp of the access token
+DROP TABLE IF EXISTS `user_oauths`;
CREATE TABLE IF NOT EXISTS `user_oauths` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL DEFAULT '0',
@@ -2375,6 +2374,7 @@ ALTER TABLE `events` ADD COLUMN `canvas_assignment_id` VARCHAR(25) NULL DEFAULT
--- START: Added by DB upgrade to version 17
-- add table to store delayed jobs
+DROP TABLE IF EXISTS `jobs`;
CREATE TABLE IF NOT EXISTS `jobs` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`handler` TEXT NOT NULL,
@@ -2391,3 +2391,127 @@ CREATE TABLE IF NOT EXISTS `jobs` (
-- store course term
ALTER TABLE `courses` ADD COLUMN `term` VARCHAR(50) NULL DEFAULT NULL;
--- END: Added by DB upgrade to version 17
+
+--- START: Added by DB upgrade to version 18
+ALTER TABLE `courses` MODIFY `canvas_id` varchar(255) NULL DEFAULT NULL;
+ALTER TABLE `courses` ADD INDEX `canvas_id` (`canvas_id`);
+ALTER TABLE `users` DROP `lti_id`;
+
+DROP TABLE IF EXISTS `lti_tool_registrations`;
+CREATE TABLE `lti_tool_registrations` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `iss` varchar(255) NOT NULL,
+ `client_id` varchar(255) NOT NULL,
+ `auth_login_url` varchar(255) NOT NULL,
+ `auth_token_url` varchar(255) NOT NULL,
+ `key_set_url` varchar(255) NOT NULL,
+ `tool_private_key` text NOT NULL,
+ `tool_public_key` text NOT NULL,
+ `user_identifier_field` varchar(255) DEFAULT NULL,
+ `student_number_field` varchar(255) DEFAULT NULL,
+ `term_field` varchar(255) DEFAULT NULL,
+ `canvas_id_field` varchar(255) DEFAULT NULL,
+ `faculty_name_field` varchar(255) DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `iss` (`iss`),
+ KEY `client_id` (`client_id`)
+) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `lti_tool_registrations`
+--
+INSERT INTO `lti_tool_registrations` (`id`, `iss`, `client_id`, `auth_login_url`, `auth_token_url`, `key_set_url`, `tool_private_key`, `tool_public_key`, `user_identifier_field`, `student_number_field`, `term_field`, `canvas_id_field`, `faculty_name_field`) VALUES
+(1, 'https://docker-canvas.instructure.com', '10000000000013', 'http://mock_lti.com/api/lti/authorize_redirect', 'http://mock_lti.com/login/oauth2/token', 'http://mock_lti.com/api/lti/security/jwks', '-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEApBK2zJCDg9s8QDeci6E4QWlTSGav3qh5edjbXULo5Mv0KxN7\nqLyC05QfRrs/I+P5a6D18S/ecAGYPH5xQKuPvqOEotPrRhHCkJB5PtLDsF4ZZbr/\nwWLWG5OYhCkY/H2Wip9rsx1GjKG73EMMTqT2p14K+GW4dg8/HbxQLA4yGeNnGr4D\nd87A+n9wUvMZYAxoCiHiSFD7x0hVIg/q4VXoWHBGEnnqCMC9Gtd7g7HZtQzbYMm4\nm2uY5JHhs+MXS8YKf6Ftc58sJHK5fMtjs9vMVOCkAlrEiEEn+tEHOjSNlzMg+P03\nUU79Lt/MDjXv3mtEPVmPjpJevT4Kjf1HxCSUNQIDAQABAoIBAF5Jmt9IFSwLKz7E\nNqRPS+LbQk8TI/JS4yxQoQ+hSfFh+7ldguzfGFe6gZbGOGzJsCZX475tAelgITpy\nd2bwsLSfh7ODEWu8/RDS1bpyqJ6MFRBPPHbH8775POaGL6O6EG8tWlkec9KRh0H3\nDfWL+2sHMkq5Oh4ueNj/xRrsNYKGLsD0bJMS9eFswDCpvL3fscu/JrrQT+CltBTJ\nj8lTHmGRIF9UOg0Ef1kEgOxcR+AZ2djP3d+zkKZxMATLKWnA1HRFPb7XpJQfjA+k\nsismB4FuhvTSN6IRaci1U5qASHUnIjbTMfFsqJ3h17RivQmSEz1r28OE1HyD/tdE\nIIy3WikCgYEAz6r27/MfEWXgOAwloKJAQi0sqa/0VkWQcNPN3jSgO+AN0iqPLSuj\nAlrLqlLcRlyYAfe7t6B/8SAklJtdy0x9uBaJXrmHhby4jeBksyycQULUzTUhGdbW\nGDfR+XbvNoGUaH1q+vIpglz2jw3N1/M6B/i16wd6Q81UO5WYxQj1j7sCgYEAykJW\nIq4A4UQmtM6gdsXXranV80NOlcH0p521Ec6wpU0dxfI+qVVbT4FxqxfB9Pq5N4V0\nreEYN1ALbjLi3fvChbx8P+lg6k/Tuhn7oiH3kado8iUUR00KyRwWeaMbVwUzU9sQ\nUhB/XfR3J7l3inN/dAlfdSsYbnQJN2U88CKEVM8CgYBfM2UZAz+O3kE38HmfdkI3\nFDaRY9SDaEibML4Dy+RZDpHHczNH5eVIww7y+iF5MCGPZV5tA+sjQzUB22fYNyy7\nI7m97xetu6JviBsh+KV5VYXwvRZ7nf1wBMcBsgBf4G+Ep1pPyIw28x8k3ZMsGJjV\n5rKfGEJ4qryexCnQyhao2QKBgCel71qm/3cpM+k3pA8EY24gn9cq94m11q7Q5IDU\nIp6UymRWQ2BQYjDosA6Y/qV2TL6Mg73eJTAamdMFWKGpS42J0FV6+0uTUG7nzwMO\nY4iC57in+hysBpQ71FAN4DsjwtcKV12u7DjPxlfcLInQcEif2b2PMB/e0Tuxtcth\nCM3TAoGAM+z4u7mi5jxyW9teAYtx3Yb6RGeuly7XvlknV0Lwf2438P2HNZiOa4SE\nSXHZir6LWNv8HOdGapYxUlDfmeNneo4D9B8lBpVs/FsuQF1aOI6B299SlVLPmF+a\nl88qKzXKv7M1pcOv74GK1AIVDF8XJvt1PyaQX92M14q2Ga8Jdjk=\n-----END RSA PRIVATE KEY-----', '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApBK2zJCDg9s8QDeci6E4\nQWlTSGav3qh5edjbXULo5Mv0KxN7qLyC05QfRrs/I+P5a6D18S/ecAGYPH5xQKuP\nvqOEotPrRhHCkJB5PtLDsF4ZZbr/wWLWG5OYhCkY/H2Wip9rsx1GjKG73EMMTqT2\np14K+GW4dg8/HbxQLA4yGeNnGr4Dd87A+n9wUvMZYAxoCiHiSFD7x0hVIg/q4VXo\nWHBGEnnqCMC9Gtd7g7HZtQzbYMm4m2uY5JHhs+MXS8YKf6Ftc58sJHK5fMtjs9vM\nVOCkAlrEiEEn+tEHOjSNlzMg+P03UU79Lt/MDjXv3mtEPVmPjpJevT4Kjf1HxCSU\nNQIDAQAB\n-----END PUBLIC KEY-----', 'https://purl.imsglobal.org/spec/lti/claim/custom|username', 'https://purl.imsglobal.org/spec/lti/claim/custom|student_number', 'https://purl.imsglobal.org/spec/lti/claim/custom|term_name', 'https://purl.imsglobal.org/spec/lti/claim/custom|canvas_course_id', 'https://purl.imsglobal.org/spec/lti/claim/custom|account_name');
+
+INSERT INTO `acos` (id, parent_id, model, foreign_key, alias, lft, rght) VALUES
+(338,2,NULL,NULL,'Ltitoolregistrations',664,673),
+(339,338,NULL,NULL,'index',665,666),
+(340,338,NULL,NULL,'add',667,668),
+(341,338,NULL,NULL,'edit',669,670),
+(342,338,NULL,NULL,'delete',671,672),
+(343,2,NULL,NULL,'Lti',673,674),
+(344,343,NULL,NULL,'roster',675,676);
+
+INSERT INTO `aros_acos` (id, aro_id, aco_id, _create, _read, _update, _delete) VALUES
+(NULL,1,338,'1','1','1','1'),
+(NULL,2,344,'1','1','1','1'),
+(NULL,3,344,'1','1','1','1'),
+(NULL,4,344,'-1','-1','-1','-1'),
+(NULL,5,344,'-1','-1','-1','-1');
+
+DROP TABLE IF EXISTS `lti_nonces`;
+CREATE TABLE `lti_nonces` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `nonce` varchar(255) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `nonce` (`nonce`)
+) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
+
+DROP TABLE IF EXISTS `lti_contexts`;
+CREATE TABLE `lti_contexts` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `lti_tool_registration_id` int(11) NOT NULL,
+ `context_id` varchar(255) NOT NULL,
+ `course_id` int(11) DEFAULT NULL,
+ `nrps_context_memberships_url` varchar(255) DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ FOREIGN KEY (`lti_tool_registration_id`) REFERENCES `lti_tool_registrations` (`id`) ON DELETE CASCADE,
+ FOREIGN KEY (`course_id`) REFERENCES `courses` (`id`) ON DELETE CASCADE,
+ UNIQUE KEY `lti_tool_registration_id_context_id` (`lti_tool_registration_id`,`context_id`)
+) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `lti_contexts`
+--
+INSERT INTO `lti_contexts` (`id`, `lti_tool_registration_id`, `context_id`, `course_id`, `nrps_context_memberships_url`) VALUES
+(1, 1, 'mock_lti_context_id', 1, 'http://mock_lti.com/api/lti/courses/13/names_and_roles');
+
+
+DROP TABLE IF EXISTS `lti_resource_links`;
+CREATE TABLE `lti_resource_links` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `lti_context_id` int(11) NOT NULL,
+ `resource_link_id` varchar(255) NOT NULL,
+ `event_id` int(11) DEFAULT NULL,
+ `lineitems_url` varchar(255) DEFAULT NULL,
+ `lineitem_url` varchar(255) DEFAULT NULL,
+ `scope_lineitem` INT(1) DEFAULT '0',
+ `scope_lineitem_read_only` INT(1) DEFAULT '0',
+ `scope_result_readonly` INT(1) DEFAULT '0',
+ `scope_result_score` INT(1) DEFAULT '0',
+ PRIMARY KEY (`id`),
+ FOREIGN KEY (`lti_context_id`) REFERENCES `lti_contexts` (`id`) ON DELETE CASCADE,
+ FOREIGN KEY (`event_id`) REFERENCES `events` (`id`) ON DELETE CASCADE,
+ UNIQUE KEY `lti_context_id_resource_link_id` (`lti_context_id`,`resource_link_id`)
+) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `lti_resource_links`
+--
+INSERT INTO `lti_resource_links` (`id`, `lti_context_id`, `resource_link_id`, `event_id`, `lineitems_url`, `lineitem_url`, `scope_lineitem`, `scope_lineitem_read_only`, `scope_result_readonly`, `scope_result_score`) VALUES
+(1, 1, 'mock_lti_resource_id', null, 'http://mock_lti.com/api/lti/courses/13/line_items', null, 1, 1, 0, 1),
+(2, 1, 'mock_lti_context_id', null, 'http://mock_lti.com/api/lti/courses/13/line_items', null, 1, 1, 0, 1);
+
+DROP TABLE IF EXISTS `lti_users`;
+CREATE TABLE `lti_users` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `lti_tool_registration_id` int(11) NOT NULL,
+ `lti_user_id` varchar(255) NOT NULL,
+ `ipeer_user_id` int(11) DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ FOREIGN KEY (`lti_tool_registration_id`) REFERENCES `lti_tool_registrations` (`id`) ON DELETE CASCADE,
+ FOREIGN KEY (`ipeer_user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
+ UNIQUE KEY `lti_tool_registration_id_lti_user_id` (`lti_tool_registration_id`,`lti_user_id`)
+) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
+--- END: Added by DB upgrade to version 18
+
+
+--
+-- Dumping data for table `lti_users`
+--
+INSERT INTO `lti_users` (`id`, `lti_tool_registration_id`, `lti_user_id`, `ipeer_user_id`) VALUES
+(1, 1, 'mock_lti_user_id_instructor', 2);
+
+
+
+SET foreign_key_checks = 1;
\ No newline at end of file
diff --git a/app/controllers/components/lti_requester.php b/app/controllers/components/lti_requester.php
deleted file mode 100644
index aac9b4f46..000000000
--- a/app/controllers/components/lti_requester.php
+++ /dev/null
@@ -1,103 +0,0 @@
-
- * @copyright 2012 All rights reserved.
- * @license MIT {@link http://www.opensource.org/licenses/MIT}
- */
-class LtiRequesterComponent extends CakeObject
-{
- public $components = array('LtiVerifier');
-
- /**
- * requestRoster
- *
- * @param mixed $params
- *
- * @access public
- * @return void
- */
- public function requestRoster($params)
- {
- // Check that roster requests are supported by the server
- $ltimid = $params['ext_ims_lis_memberships_id'];
- if (empty($ltimid)) {
- return "Missing 'ext_ims_lis_memberships_id'. Calling LTI consumer does not support roster requests.";
- }
-
- $ltimurl = $params['ext_ims_lis_memberships_url'];
- if (empty($ltimurl)) {
- return "Missing 'ext_ims_lis_memberships_url'. Calling LTI consumer does not support roster requests.";
- }
-
- // build an array of all the params we need to use
- $oauth_key = $params['oauth_consumer_key']; // assuming this exists
- $request = array(
- 'oauth_version' => '1.0',
- 'oauth_nonce' => rand() . "-" . rand(),
- 'oauth_timestamp' => time(),
- 'oauth_consumer_key' => $oauth_key,
- 'oauth_signature_method' => 'HMAC-SHA1',
- 'oauth_callback' => 'about:blank',
- 'lti_version' => 'LTI-1p0',
- 'lti_message_type' => 'basic-lis-readmembershipsforcontext',
- 'id' => $ltimid,
- );
-
- // calculate the signature of all the params
- $secret = $this->LtiVerifier->getSecret($oauth_key);
- if (empty($secret)) {
- return "Missing secret, key '$oauth_key' not found in keystore.";
- }
- $hmac = $this->LtiVerifier->getHMAC($request, $secret, $ltimurl);
-
- // add the signature in into the params
- $request['oauth_signature'] = $hmac;
- $request = http_build_query($request);
-
- // send the actual POST request
- $params = array(
- 'http' => array('method' => 'POST', 'content' => $request)
- );
- $ctx = stream_context_create($params);
- $fp = @fopen($ltimurl, 'rb', false, $ctx);
- if (!$fp) {
- return 'Unable to connect to ' . $ltimurl;
- }
- // read the response
- $response = @stream_get_contents($fp);
- if ($response === false) {
- return 'Unable to read data from ' . $ltimurl;
- }
-
- // parse the response xml
- $xml = new SimpleXMLElement($response);
- if (strcasecmp($xml->statusinfo->codemajor, 'Success') != 0) {
- return 'Unable to retrieve roster: ' . $xml->statusinfo->description;
- }
-
- // convert the response xml to an array
- $ret = array();
- foreach ($xml->memberships->member as $member) {
- $student = array();
- foreach ($member as $key => $val) {
- // note $val is still a SimpleXML object, so need cast with ""
- $student[$key] = "$val";
- }
- $ret[] = $student;
- }
- return $ret;
- }
-}
diff --git a/app/controllers/components/lti_verifier.php b/app/controllers/components/lti_verifier.php
deleted file mode 100644
index de11818ff..000000000
--- a/app/controllers/components/lti_verifier.php
+++ /dev/null
@@ -1,288 +0,0 @@
-
- * @copyright 2012 All rights reserved.
- * @license MIT {@link http://www.opensource.org/licenses/MIT}
- */
-class LtiVerifierComponent extends CakeObject
-{
- public $components = array('Auth');
-
- private $store = array('lti_secret' => 'secret');
- // time range in seconds within which the timestamp is considered valid
- // Note that for security reasons, since we're not storing the nonces,
- // the timestamp plays a double role as a nonce, the delay should be
- // kept low, only a few minutes max.
- private $timestamptimeout = 60;
-
- /**
- * The chances of this function working would be significantly improved
- * if the User table has a column named 'lti_id'. Also would help if the
- * Auth component was used.
- *
- * @param array $params the LTI parameters
- * @param array $user the user model used by this app
- *
- * @return - false if authentication successful, a string describing the
- * error otherwise
- * */
-
- public function login($params, $user)
- {
- $userid = $params['user_id'];
- $ret = $user->find(
- 'first',
- array('conditions' => array('User.lti_id' => $userid)));
- if (empty($ret)) {
- return 'User not found';
- }
- $userid = $ret['User']['id'];
- $ret = $this->Auth->login($userid);
- if ($ret == 0) {
- return 'Access denied';
- }
-
- return false;
- }
-
- /**
- * Checks for compliance to LTI specs
- *
- * @param array $params - the LTI parameters
- *
- * @return - false if params are LTI compliant, a string describing the
- * error otherwise
- * */
-
- public function checkParams($params)
- {
- // Perform basic LTI validation by checking that all
- // required fields are present
- $lti_ver = $params['lti_version'];
- if (strcmp($lti_ver, 'LTI-1p0') != 0) {
- return 'Incompatible or missing lti_version.';
- }
- $lti_type = $params['lti_message_type'];
- if (strcmp($lti_type, 'basic-lti-launch-request') != 0) {
- return 'Incompatible or missing basic lti request.';
- }
- $lti_resource = $params['resource_link_id'];
- if (empty($lti_resource)) {
- return 'Missing resource link id.';
- }
-
- // Check that oauth parameters have been transmitted
- $oauth_key = $params['oauth_consumer_key'];
- if (empty($oauth_key)) {
- return 'Missing oauth parameter: oauth_consumer_key.';
- }
- $oauth_method = $params['oauth_signature_method'];
- if (strcmp($oauth_method, "HMAC-SHA1") != 0) {
- return 'Incompatible oauth signature method, only HMAC-SHA1 is supported.';
- }
- $oauth_time = $params['oauth_timestamp'];
- if (abs($oauth_time - time()) > $this->timestamptimeout) {
- return 'Failed oauth timestamp verification.';
- }
- $oauth_nonce = $params['oauth_nonce'];
- if (empty($oauth_nonce)) {
- return 'Missing oauth nonce.';
- }
- $oauth_version = $params['oauth_version'];
- if (strcmp($oauth_version, "1.0") != 0) {
- return 'Incompatible OAuth version.';
- }
-
- // Check that messages haven't been tampered with using OAuth
- $secret = $this->getSecret($oauth_key);
- if (empty($secret)) {
- return "Missing secret, key '$oauth_key' not found in keystore.";
- }
- $hmac = $this->getHMAC($params, $secret);
- $oauth_signature = $params['oauth_signature'];
- if (strcmp($hmac, $oauth_signature) != 0) {
- return 'Message integrity could not be verified.';
- }
-
- return false;
- }
-
- /**
- * Reads the LTI parameters and return an array containing
- * information about the course.
- *
- * @param array $params - the LTI request parameters
- *
- * @return false if the LTI request is missing course information, the
- * array containing two keys 'course' and 'title' otherwise.
- * */
-
- public function getCourseInfo($params)
- {
- $ret = array();
- $ret['course'] = $params['context_label'];
- $ret['title'] = $params['context_title'];
- if ($ret['course'] && $ret['title']) {
- return $ret;
- }
- return false;
- }
-
- /**
- * Given a key, check the keystore for the corresponding secret.
- *
- * Currently, the store is just a hard coded array.
- *
- * @param string $key - the key used to access the secret
- *
- * @return false if the secret was not found, a string containing the
- * secret if found
- * */
-
- public function getSecret($key)
- {
- if (isset($this->store[$key])) {
- return $this->store[$key];
- }
- return false;
- }
-
- /**
- * Calculate the HMAC value according to OAuth specs.
- *
- * @param array $params - the array of POST parameters of the LTI request
- * @param string $secret - the secret string
- * @param string $url - the url which is receiving the LTI request, if left
- *
- * blank, defaults to the URL that the current script is executing on
- *
- * @return the resulting hash string
- * */
-
- public function getHMAC($params, $secret, $url = '')
- {
- $secret .= '&';
- $input = $this->getHashInput($params, $url);
- return $this->hash($input, $secret);
- }
-
- /**
- * Given a set of data and a secret, generate a hash and
- * base64 encode it.
- *
- * @param array $data - the data to be hashed
- * @param string $secret - the secret used to salt the data
- *
- * @return base64 encodeded hash
- * */
-
- private function hash($data, $secret)
- {
- return base64_encode(hash_hmac("sha1", $data, $secret, true));
- }
-
- /**
- * Convert the LTI params into the proper data format
- * to pass into the hash function.
- *
- * @param array $params - the LTI parameters
- * @param string $url - the URL of the page receiving the LTI request. Defaults to
- * a blank string. If left blank, will use the URL of the current page
- * that the php scrip is running on.
- *
- * @return A correctly formatted data string suitable for use in calculating
- * the OAuth HMac.
- * */
-
- private function getHashInput($params, $url = '')
- {
- $ret = "POST&";
- if (empty($url)) {
- $ret .= $this->rfc3986($this->getURL()) . '&';
- } else {
- $ret .= $this->rfc3986($url) . '&';
- }
- $ret .= $this->rfc3986($this->convertParams($params));
- return $ret;
- }
-
- /**
- * Convert each key-value pair into the correct RFC 3986 encoding
- * required by OAuth.
- *
- * @param array $params - the LTI parameters
- *
- * @return A string containing all the key-value pairs of $param
- * delimited by an ampersand and encoded into RFC 3986
- * */
-
- private function convertParams($params)
- {
- $tmp = array();
- foreach ($params as $key => $val) {
- $tmp[$this->rfc3986($key)] = $this->rfc3986($val);
- }
- $params = $tmp;
-
- // sort by byte order
- uksort($params, 'strcmp');
-
- $tmp = array();
- foreach ($params as $parameter => $value) {
- if (strcmp($parameter, "oauth_signature") == 0) {
- continue;
- }
- array_push($tmp, $parameter . '=' . $value);
- }
- return implode('&', $tmp);
- }
-
- /**
- * Convert a string into rfc3986 compliant encoding
- *
- * @param string $input - the string to be converted
- *
- * @return The rfc3986 compliant string
- * */
- private function rfc3986($input)
- {
- // Note workaround for:
- // - Prior to PHP 5.3.0, rawurlencode encoded tildes (~) per rfc1738.
- return str_replace('%7E', '~', rawurlencode($input));
- }
-
- /**
- * Get the URL of the current page that PHP is being executed on.
- *
- * @return The URL of the current page that PHP is being executed on.
- * */
- private function getURL()
- {
- $pageURL = 'http';
- if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on") {
- $pageURL .= "s";
- }
- $pageURL .= "://";
- if ($_SERVER["SERVER_PORT"] != "80") {
- $pageURL .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"]
- . $_SERVER["REQUEST_URI"];
- } else {
- $pageURL .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
- }
- return $pageURL;
- }
-}
diff --git a/app/controllers/courses_controller.php b/app/controllers/courses_controller.php
index edd6f526d..677a1c104 100644
--- a/app/controllers/courses_controller.php
+++ b/app/controllers/courses_controller.php
@@ -12,7 +12,7 @@ class CoursesController extends AppController
{
public $name = 'Courses';
public $uses = array('GroupEvent', 'Course', 'Personalize', 'UserCourse',
- 'UserEnrol', 'Group', 'Event', 'User', 'UserFaculty', 'Department',
+ 'UserEnrol', 'Group', 'Event', 'User', 'UserFaculty', 'Department', 'LtiContext',
'CourseDepartment', 'EvaluationSubmission', 'SurveyInput', 'UserTutor', 'SysParameter');
public $helpers = array('Html', 'Ajax', 'excel', 'Javascript', 'Time',
'Js' => array('Prototype'), 'FileUpload.FileUpload');
@@ -203,10 +203,19 @@ function home($id)
$this->redirect('index');
return;
}
+ $lti_contexts = $this->LtiContext->getByCourseId($id);
+ $ltiNrpsEnabled = false;
+ foreach ($lti_contexts as $lti_context) {
+ if (!empty($lti_context['LtiContext']['nrps_context_memberships_url'])) {
+ $ltiNrpsEnabled = true;
+ break;
+ }
+ }
$this->set('data', $course);
$this->set('title_for_layout', $course['Course']['full_name']);
$this->set('canvasEnabled', in_array($this->SysParameter->get('system.canvas_enabled', 'false'), array('1', 'true', 'yes')));
+ $this->set('ltiNrpsEnabled', $ltiNrpsEnabled);
//Setup the courseId to session
$this->Session->write('ipeerSession.courseId', $id);
diff --git a/app/controllers/lti_controller.php b/app/controllers/lti_controller.php
index f12ca4844..02550ff87 100644
--- a/app/controllers/lti_controller.php
+++ b/app/controllers/lti_controller.php
@@ -1,229 +1,176 @@
- * @copyright 2012 All rights reserved.
+ * @author Steven Marshall
+ * @copyright 2019 All rights reserved.
* @license MIT {@link http://www.opensource.org/licenses/MIT}
+ * @link https://www.imsglobal.org/spec/security/v1p0/#fig_oidcflow
*/
class LtiController extends AppController
{
- public $name = "Lti";
- public $uses = array('User', 'Course', 'Role');
- public $components = array('LtiVerifier', 'LtiRequester');
+ public $uses = array('LtiContext', 'LtiResourceLink', 'LtiUser',
+ 'User', 'Course');
+
+ public function __construct()
+ {
+ parent::__construct();
+ }
/**
* beforeFilter
*
- *
* @access public
* @return void
*/
function beforeFilter()
{
- $this->Auth->allow('index');
+ //ensure the user is logged out of iPeer when starting the login/launch actions
+ if (!empty($this->params['action']) && in_array($this->params['action'], ['login', 'launch'])) {
+ if ($this->Auth->isAuthorized()) {
+ $this->Auth->logout();
+ }
+ }
+ $this->Auth->allow('login', 'launch');
+ parent::beforeFilter();
}
+ /**
+ * OIDC login action called by platform.
+ */
+ public function login()
+ {
+ try {
+ $login = LTI_OIDC_Login::new(
+ new LTIDatabase(),
+ new LTICache(),
+ new LTICookie()
+ );
+ $url = Router::url('/lti/launch', true);
+ $redirect = $login->do_oidc_login_redirect($url);
+ // fix `die` call issue for testing by redirecting manually using framework
+ $this->redirect($redirect->get_redirect_url());
+ } catch (OIDC_Exception $e) {
+ $this->Session->setFlash(sprintf("Error doing OIDC login: %s", $e->getMessage()));
+ $this->redirect('/home/index');
+ }
+ }
/**
- * index
- *
- *
- * @access public
- * @return void
+ * Launch action called by platform.
*/
- public function index()
+ public function launch()
{
- // First verify that this is a legit LTI request
- $ret = $this->LtiVerifier->checkParams($this->params['form']);
- if ($ret) {
- // param check failed
- $this->set('invalidlti', $ret);
- return;
+ // fixes potential warning when state/id_token param is missing
+ // (will still properly error out in validation)
+ if (empty($_POST['state'])) {
+ $_POST['state'] = null;
+ }
+ if (empty($_POST['id_token'])) {
+ $_POST['id_token'] = null;
}
- // Request the class roster
- $roster = $this->LtiRequester->requestRoster($this->params['form']);
- if (!is_array($roster)) {
- $this->set('invalidlti', $roster);
+ $launch = LTI_Message_Launch::new(
+ new LTIDatabase(),
+ new LTICache(),
+ new LTICookie()
+ );
+ try {
+ $launch->validate();
+ } catch (LTI_Exception $e) {
+ $this->Session->setFlash($e->getMessage());
+ $this->redirect('/logout');
return;
}
- // Get course information
- $ret = $this->LtiVerifier->getCourseInfo($this->params['form']);
- if (!$ret) {
- // failed to get course info
- $this->set('invalidlti', "Missing course info in LTI request");
+ if (!$launch->is_resource_launch()) {
+ $this->Session->setFlash("Not an LTI Launch.");
+ $this->redirect('/logout');
return;
}
+ $launch_data = $launch->get_launch_data();
+ $launch_data_parser = new LaunchDataParser($launch_data);
- // APP SPECIFIC CODE STARTS HERE
- // Check whether the course already exists
- $course = $this->Course->find(
- 'first',
- array('conditions' => array('Course.course' => $ret['course']),)
- );
- if (empty($course)) {
- // Non-existing course, create course
- $this->data = array();
- $this->data['course'] = $ret['course'];
- $this->data['title'] = $ret['title'];
- $this->data['record_status'] = Course::STATUS_ACTIVE;
- $this->data = $this->Course->save($this->data);
- if (!$this->data) {
- $this->set('invalidlti', "Unable to add course");
- return;
- }
+ $this->log(json_encode($launch_data, 448), 'lti/launch');
- // Create users, if needed, and enrol them to the course
- foreach ($roster as $person) {
- $this->addUser($person, $this->Course->id);
- }
+ // automatically create Faculty if needed
+ $faculty = $this->LtiContext->syncFaculty($launch_data_parser);
+ $faculty_id = $faculty['Faculty']['id'];
- } else {
- // Existing course, update course
- // Get current roster in iPeer
- $courseid = $course['Course']['id'];
- $ipeerroster = $this->User->getEnrolledStudents($courseid);
- // Compare with roster from LTI
- // Remove users that are on both lists
- foreach ($roster as $ltikey => $ltiuser) {
- foreach ($ipeerroster as $ipeerkey => $ipeeruser) {
- if ($ltiuser['user_id'] == $ipeeruser['User']['lti_id']) {
- unset($roster[$ltikey]);
- unset($ipeerroster[$ipeerkey]);
- continue;
- }
- }
- }
- // Remaining users in ipeerroster needs to be dropped
- foreach ($ipeerroster as $ipeeruser) {
- $this->User->removeStudent(
- $ipeeruser['User']['id'], $courseid);
- }
- // Remaining users in roster needs to be added
- foreach ($roster as $person) {
- if (!$this->isLTIInstructor($person)) {
- $this->addUser($person, $courseid);
- }
- }
- }
- // END APP SPECIFIC CODE
-
- // Let's try logging in:
- $ret = $this->LtiVerifier->login($this->params['form'], $this->User);
- if ($ret) {
- $this->set('invalidlti', $ret);
- return;
- }
+ // automatically create/update lti context + course
+ $lti_context = $this->LtiContext->syncLaunchContext($launch_data_parser);
+ $lti_context_id = $lti_context['LtiContext']['id'];
+ $course_id = $lti_context['Course']['id'];
- // APP SPECIFIC CODE BELOW
- $this->redirect('/home');
+ // automatically create/update lti resource link + assignment (skipping assignment for now)
+ $lti_resource_link = $this->LtiResourceLink->syncLaunchResourceLink($launch_data_parser, $lti_context_id);
- }
+ // automatically create/update lti user + user
+ $lti_user = $this->LtiUser->syncUser(
+ $launch_data_parser->lti_tool_registration['id'],
+ $launch_data_parser->getParam('sub'),
+ $launch_data_parser->getUserData()
+ );
+ $user_id = $lti_user['User']['id'];
+ $role_id = $launch_data_parser->getCourseRole();
+ // automatically update user enrollment
+ $this->LtiUser->syncUserEnrollment($course_id, $user_id, $faculty_id, $role_id);
- /**
- * addUser
- *
- * @param mixed $info info
- * @param mixed $courseid course id
- *
- * @access private
- * @return void
- */
- private function addUser($info, $courseid)
- {
- $first = $info['person_name_given'];
- $last = $info['person_name_family'];
- $email = $info['person_contact_email_primary'];
- $lti_id = $info['user_id'];
- $instructor = $this->isLTIInstructor($info);
-
- // Prepare user data
- $cdata = array();
- $cdata['User']['username'] = $first . $last;
- $cdata['User']['first_name'] = $first;
- $cdata['User']['last_name'] = $last;
- $cdata['User']['email'] = $email;
- $cdata['User']['send_email_notification'] = false;
- $cdata['User']['lti_id'] = $lti_id;
- // TODO USER_TYPE_STUDENT needs to change to const instead of public later
- $cdata['Role']['RolesUser']['role_id'] = $this->User->USER_TYPE_STUDENT;
- $cdata['User']['created'] = date('Y-m-d H:i:s');
- if ($instructor !== false) {
- // this guy is a prof
- $cdata['Role']['RolesUser']['role_id'] = $this->User->USER_TYPE_INSTRUCTOR;
+ // Automatic user login and log
+ $this->Auth->login($user_id);
+ if (method_exists($this, '_afterLogin')) {
+ $this->_afterLogin(false);
}
- // Check if user already exists
- $user = $this->User->getByUsername($cdata['User']['username']);
- if (!empty($user)) {
- // pre-existing user, just need to add them to course
- $this->addUserToCourse($user['User']['id'], $courseid, $instructor);
- // user might not have an lti_id, so save one
- $user['User']['lti_id'] = $lti_id;
- $this->User->save($user);
- return false;
- }
+ $this->log($lti_user['User'], 'lti/user');
- // Need to create a new user
- $this->User->create();
- if ($this->User->save($cdata)) {
- // User enrolment
- $this->addUserToCourse($this->User->id, $courseid, $instructor);
- return false;
+ $this->Session->setFlash(__('LTI launch success', true), 'good');
+ if (in_array($role_id, [$this->User->USER_TYPE_ADMIN, $this->User->USER_TYPE_INSTRUCTOR, $this->User->USER_TYPE_TA])) {
+ // Redirect to course page is instructor/admin
+ $this->redirect("/courses/home/$course_id");
} else {
- return $cdata['User']['username'];
+ // else redirect to home page for students
+ $this->redirect('/home/index');
}
}
-
/**
- * addUserToCourse
- *
- * @param mixed $userid user id
- * @param mixed $courseid course id
- * @param mixed $instructor instructor
+ * Update roster by course ID from platform.
*
- * @access private
- * @return void
+ * Called by tool, not platform.
+ * @param string $course_id
*/
- private function addUserToCourse($userid, $courseid, $instructor)
+ public function roster($course_id)
{
- // TODO use Role methods instead of this if possible
- $student_role_id = $this->Role->field('id', array('name =' => 'student'));
- $instructor_role_id = $this->Role->field(
- 'id', array('name' => 'instructor'));
-
- if ($instructor === false) {
- $this->User->registerRole($userid, $student_role_id);
- $this->User->UserEnrol->insertCourses($userid, array($courseid));
- } else {
- $this->User->registerRole($userid, $instructor_role_id);
- $this->Course->addInstructor($courseid, $userid);
+ if (!User::hasPermission('controllers/Lti/roster')) {
+ return;
}
- }
+ $names_and_roles_service = new NamesAndRolesService($course_id);
+ try
+ {
+ $names_and_roles_service->sync_membership();
+ $this->Session->setFlash(__('Imported Users from LMS', true), 'good');
+ $this->redirect("/courses/home/$course_id");
- /**
- * isLTIInstructor
- *
- * @param mixed $info
- *
- * @access private
- * @return void
- */
- private function isLTIInstructor($info)
- {
- $instructor = stripos($info['roles'], 'Instructor');
- // note that !== is required, we MUST compare type since
- // stripos() may return 0 for a valid match
- if ($instructor === false) {
- return false;
+ } catch (LTI_Exception $e) {
+ $this->Session->setFlash($e->getMessage());
+ $this->redirect("/courses/home/$course_id");
}
- return true;
}
}
diff --git a/app/controllers/ltitoolregistrations_controller.php b/app/controllers/ltitoolregistrations_controller.php
new file mode 100644
index 000000000..4c01391f6
--- /dev/null
+++ b/app/controllers/ltitoolregistrations_controller.php
@@ -0,0 +1,130 @@
+
+ * @copyright 2019 All rights reserved.
+ * @license MIT {@link http://www.opensource.org/licenses/MIT}
+ * @link https://www.imsglobal.org/spec/security/v1p0/#fig_oidcflow
+ */
+class LtiToolRegistrationsController extends AppController
+{
+ public $name = 'LtiToolRegistrations';
+ public $uses = array('LtiToolRegistration');
+
+ /**
+ * Index action
+ */
+ public function index()
+ {
+ $this->set('title_for_layout', __('Lti 1.3 Tool Registrations',true));
+ $this->set('headings', array('Issuers', 'Settings', 'Actions'));
+
+ $ret = $this->LtiToolRegistration->find('all');
+
+ $registrations = array();
+ foreach ($ret as $registration) {
+ $tmp = array();
+ $tmp['id'] = $registration['LtiToolRegistration']['id'];
+ $tmp['iss'] = $registration['LtiToolRegistration']['iss'];
+ $tmp['client_id'] = $registration['LtiToolRegistration']['client_id'];
+ $registrations[] = $tmp;
+ }
+ $this->set('registrations', $registrations);
+ }
+
+ /**
+ * Add action
+ */
+ public function add()
+ {
+ $this->set('title_for_layout', __('Add Lti 1.3 Tool Registration',true));
+
+ try {
+
+ // POST request
+ if (!empty($this->data)) {
+ // Save all
+ if ($this->LtiToolRegistration->save($this->data)) {
+ $this->Session->setFlash(__('Tool registration has been created', true), 'good');
+ $this->redirect(array('action' => 'index'));
+ }
+ }
+
+ } catch (Exception $e) {
+
+ $this->Session->setFlash($e->getMessage());
+ $this->redirect(array('action'=>'index'));
+
+ }
+ }
+
+ /**
+ * Edit action
+ *
+ * @param mixed $id
+ */
+ public function edit($id = null)
+ {
+ $this->set('title_for_layout', __('Edit Lti 1.3 Tool Registration',true));
+
+ try {
+
+ // POST request
+ if (!empty($this->data)) {
+
+ // Delete associated deployments from dB
+ $id = $this->data['LtiToolRegistration']['id'];
+ $conditions = 'lti_tool_registration_id = ' . $id;
+
+ // Save all
+ if ($this->LtiToolRegistration->save($this->data)) {
+ $this->Session->setFlash(__('Tool registration has been updated', true), 'good');
+ $this->redirect(array('action' => 'index'));
+ }
+
+ } else {
+
+ if (empty($id)) {
+ $this->redirect(array('action' => 'index'));
+ }
+
+ }
+
+ $this->data = $this->LtiToolRegistration->findById($id);
+
+ } catch (Exception $e) {
+
+ $this->Session->setFlash($e->getMessage());
+ $this->redirect(array('action'=>'index'));
+
+ }
+ }
+
+ /**
+ * Delete action
+ *
+ * @param mixed $id
+ */
+ public function delete($id = null)
+ {
+ try {
+
+ if ($this->LtiToolRegistration->delete($id)) {
+ $this->Session->setFlash(__('Tool registration has been deleted', true), 'good');
+ $this->redirect(array('action'=>'index'));
+ }
+ $this->Session->setFlash(__('Tool registration was not deleted', true));
+ $this->redirect(array('action' => 'index'));
+
+ } catch (Exception $e) {
+
+ $this->Session->setFlash($e->getMessage());
+ $this->redirect(array('action'=>'index'));
+
+ }
+ }
+}
diff --git a/app/libs/caliper/entity.php b/app/libs/caliper/entity.php
index c75fc7d56..ef48a2af8 100644
--- a/app/libs/caliper/entity.php
+++ b/app/libs/caliper/entity.php
@@ -142,9 +142,6 @@ public static function membership($course, $user, $roles) {
if (array_key_exists('canvas_id', $course) && $course['canvas_id']) {
$extensions['canvas_course_id'] = $course['canvas_id'];
}
- if (array_key_exists('lti_id', $user) && $user['lti_id']) {
- $extensions['lti_user_id'] = $user['lti_id'];
- }
if (count($extensions) > 0) {
$entity->setExtensions($extensions);
diff --git a/app/libs/lti.php b/app/libs/lti.php
new file mode 100644
index 000000000..c12541673
--- /dev/null
+++ b/app/libs/lti.php
@@ -0,0 +1,24 @@
+LtiToolRegistration = \ClassRegistry::init('LtiToolRegistration');
+ $this->User = \ClassRegistry::init('User');
+ $this->launch_data = $launch_data;
+
+ $iss = $launch_data['iss'];
+ $results = $this->LtiToolRegistration->findByIss($iss);
+ $this->lti_tool_registration = $results['LtiToolRegistration'];
+ return $this;
+ }
+
+ public function getParam($param_name) {
+ if (!isset($this->launch_data)) {
+ return null;
+ }
+ if (!isset($this->launch_data[$param_name])) {
+ return null;
+ }
+ return $this->launch_data[$param_name];
+ }
+
+ public function getClaim($claim_name) {
+ if (!isset($this->launch_data)) {
+ return null;
+ }
+ if (!isset($this->launch_data["https://purl.imsglobal.org/spec/lti/claim/$claim_name"])) {
+ return null;
+ }
+ return $this->launch_data["https://purl.imsglobal.org/spec/lti/claim/$claim_name"];
+ }
+
+ public function getClaimParam($claim_name, $param_name) {
+ $claim = $this->getClaim($claim_name);
+ if (!isset($claim)) {
+ return null;
+ }
+ if (!isset($claim[$param_name])) {
+ return null;
+ }
+ return $claim[$param_name];
+ }
+
+ public function getNrpsClaim() {
+ if (!isset($this->launch_data)) {
+ return null;
+ }
+ if (!isset($this->launch_data["https://purl.imsglobal.org/spec/lti-nrps/claim/namesroleservice"])) {
+ return null;
+ }
+ return $this->launch_data["https://purl.imsglobal.org/spec/lti-nrps/claim/namesroleservice"];
+ }
+
+ public function getNrpsClaimParam($param_name) {
+ $claim = $this->getNrpsClaim();
+ if (!isset($claim)) {
+ return null;
+ }
+ if (!isset($claim[$param_name])) {
+ return null;
+ }
+ return $claim[$param_name];
+ }
+
+ public function getAgsClaim() {
+ if (!isset($this->launch_data)) {
+ return null;
+ }
+ if (!isset($this->launch_data["https://purl.imsglobal.org/spec/lti-ags/claim/endpoint"])) {
+ return null;
+ }
+ return $this->launch_data["https://purl.imsglobal.org/spec/lti-ags/claim/endpoint"];
+ }
+
+ public function getAgsClaimParam($param_name) {
+ $claim = $this->getAgsClaim();
+ if (!isset($claim)) {
+ return null;
+ }
+ if (!isset($claim[$param_name])) {
+ return null;
+ }
+ return $claim[$param_name];
+ }
+
+ public function hasAgsClaimScope($scope) {
+ $claim = $this->getAgsClaim();
+ if (empty($claim)) {
+ return 0;
+ }
+ if (empty($claim['scope'])) {
+ return 0;
+ }
+ return in_array("https://purl.imsglobal.org/spec/lti-ags/scope/$scope", $claim['scope']) ? 1 : 0;
+ }
+
+ public function getUserData() {
+ return array(
+ 'username' => $this->getUserIdentifierValue(),
+ 'first_name' => $this->getParam('given_name'),
+ 'last_name' => $this->getParam('family_name'),
+ 'student_no' => $this->getStudentNumberValue(),
+ 'email' => $this->getParam('email'),
+ );
+ }
+
+
+ public function getCourseData() {
+ return array(
+ 'course' => $this->getClaimParam('context', 'label'),
+ 'title' => $this->getClaimParam('context', 'title'),
+ 'canvas_id' => $this->getCanvasIdValue(),
+ 'term' => $this->getTermValue(),
+ );
+ }
+
+ # Core context roles
+ # http://purl.imsglobal.org/vocab/lis/v2/membership#Administrator
+ # http://purl.imsglobal.org/vocab/lis/v2/membership#ContentDeveloper
+ # http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor
+ # http://purl.imsglobal.org/vocab/lis/v2/membership#Learner
+ # http://purl.imsglobal.org/vocab/lis/v2/membership#Mentor
+ # Instructor Sub-role
+ # Grader, GuestInstructor, Instructor, Lecturer, PrimaryInstructor
+ # SecondaryInstructor, TeachingAssistant, TeachingAssistantGroup
+ # TeachingAssistantOffering, TeachingAssistantSection, TeachingAssistantTemplate
+ public function getCourseRole() {
+ $roles = $this->getClaim('roles');
+ $is_admin = $is_instructor = $is_student = $is_ta = $is_content_developer = FALSE;
+
+ foreach ($roles as $role) {
+ # supports long and short formats. ex:
+ # http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor
+ # Instructor
+ # http://purl.imsglobal.org/vocab/lis/v2/membership/Instructor#TeachingAssistant
+ # Instructor#TeachingAssistant
+ $short_role = preg_replace('/http\:\/\/purl\.imsglobal\.org\/vocab\/lis\/v2\/membership(\#|\/)/i', '', $role);
+ if ('Administrator' == $short_role) {
+ $is_admin = TRUE;
+ } elseif ('Instructor' == $short_role) {
+ $is_instructor = TRUE;
+ } elseif ('ContentDeveloper' == $short_role) {
+ $is_content_developer = TRUE;
+ } elseif ('Instructor#TeachingAssistant' == $short_role) {
+ $is_ta = TRUE;
+ } elseif ('Learner' == $short_role) {
+ $is_student = TRUE;
+ }
+ }
+
+ if ($is_admin) {
+ return $this->User->USER_TYPE_INSTRUCTOR;
+ } elseif ($is_instructor && !$is_ta) {
+ return $this->User->USER_TYPE_INSTRUCTOR;
+ } elseif ($is_content_developer) {
+ return $this->User->USER_TYPE_INSTRUCTOR;
+ } elseif ($is_ta) {
+ return $this->User->USER_TYPE_TA;
+ } else {
+ return $this->User->USER_TYPE_STUDENT;
+ }
+ }
+
+ private function getDynamicFieldValue($field) {
+ if (empty($field)) {
+ return null;
+ }
+ $data_ref = $this->launch_data;
+ $field_parts = explode("|", $field);
+
+ foreach($field_parts as $field_part) {
+ if (!is_array($data_ref) || empty($data_ref[$field_part])) {
+ return null;
+ }
+ $data_ref = $data_ref[$field_part];
+ }
+ if (is_array($data_ref) || empty($data_ref)) {
+ return null;
+ }
+ return $data_ref;
+ }
+
+ public function getUserIdentifierValue() {
+ if (!empty($this->lti_tool_registration['user_identifier_field'])) {
+ $user_identifier_field = $this->lti_tool_registration['user_identifier_field'];
+
+ $value = $this->getDynamicFieldValue($user_identifier_field);
+ if (!empty($value)) {
+ return $value;
+ }
+ }
+ // default user identifer value
+ return $this->getParam('sub');
+ }
+
+ public function getStudentNumberValue() {
+ if (!empty($this->lti_tool_registration['student_number_field'])) {
+ $student_number_field = $this->lti_tool_registration['student_number_field'];
+
+ $value = $this->getDynamicFieldValue($student_number_field);
+ if (!empty($value)) {
+ return $value;
+ }
+ }
+ // default student number value
+ return null;
+ }
+
+ public function getCanvasIdValue() {
+ if (!empty($this->lti_tool_registration['canvas_id_field'])) {
+ $canvas_id_field = $this->lti_tool_registration['canvas_id_field'];
+
+ $value = $this->getDynamicFieldValue($canvas_id_field);
+ if (!empty($value)) {
+ return $value;
+ }
+ }
+ // default canvas_id value
+ return null;
+ }
+
+ public function getTermValue() {
+ if (!empty($this->lti_tool_registration['term_field'])) {
+ $term_field = $this->lti_tool_registration['term_field'];
+
+ $value = $this->getDynamicFieldValue($term_field);
+ if (!empty($value)) {
+ return $value;
+ }
+ }
+ // default term value
+ return null;
+ }
+
+ public function getFacultyNameValue() {
+ if (!empty($this->lti_tool_registration['faculty_name_field'])) {
+ $faculty_name_field = $this->lti_tool_registration['faculty_name_field'];
+
+ $value = $this->getDynamicFieldValue($faculty_name_field);
+ if (!empty($value)) {
+ return $value;
+ }
+ }
+ // default term value
+ return 'LTI Default Faculty';
+ }
+}
diff --git a/app/libs/lti/lti_cache.php b/app/libs/lti/lti_cache.php
new file mode 100644
index 000000000..bf83f8a69
--- /dev/null
+++ b/app/libs/lti/lti_cache.php
@@ -0,0 +1,47 @@
+LtiNonce = \ClassRegistry::init('LtiNonce');
+ return $this;
+ }
+
+ public function get_launch_data($key) {
+ // do not support launch data in 'cache'
+ return null;
+ }
+
+ public function cache_launch_data($key, $jwt_body) {
+ // do not support launch data in 'cache'
+ return $this;
+ }
+
+ public function cache_nonce($nonce) {
+ $data = array(
+ 'LtiNonce' => array(
+ 'nonce' => $nonce
+ )
+ );
+ $this->LtiNonce->save($data);
+ return $this;
+ }
+
+ public function check_nonce($nonce) {
+ $lti_nonce = $this->LtiNonce->findByNonce($nonce);
+ if (empty($lti_nonce)) {
+ return false;
+ }
+ $this->LtiNonce->deleteAll(array(
+ 'LtiNonce.nonce' => $nonce,
+ ));
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/app/libs/lti/lti_cookie.php b/app/libs/lti/lti_cookie.php
new file mode 100644
index 000000000..576541657
--- /dev/null
+++ b/app/libs/lti/lti_cookie.php
@@ -0,0 +1,37 @@
+ time() + $exp
+ ];
+
+ // SameSite none and secure will be required for tools to work inside iframes
+ $same_site_options = [
+ 'samesite' => 'None',
+ 'secure' => true
+ ];
+
+ if (PHP_VERSION_ID < 70300) {
+ $options += [
+ 'path' => "/",
+ 'domain' => "",
+ 'secure' => false,
+ 'httponly' => false
+ ];
+ extract(array_merge($cookie_options, $options)); // => $expires, $path, $domain, $secure, $httponly
+ @setcookie("LEGACY_" . $name, $value, $expires, $path, $domain, $secure, $httponly);
+ return $this;
+ }
+
+ @setcookie($name, $value, array_merge($cookie_options, $same_site_options, $options));
+
+ // Set a second fallback cookie in the event that "SameSite" is not supported
+ @setcookie("LEGACY_" . $name, $value, array_merge($cookie_options, $options));
+ return $this;
+ }
+}
\ No newline at end of file
diff --git a/app/libs/lti/lti_database.php b/app/libs/lti/lti_database.php
new file mode 100644
index 000000000..2a7df5cb3
--- /dev/null
+++ b/app/libs/lti/lti_database.php
@@ -0,0 +1,53 @@
+LtiToolRegistration = \ClassRegistry::init('LtiToolRegistration');
+ return $this;
+ }
+
+ /**
+ * Find registration by issuer.
+ *
+ * @see vendor/imsglobal/lti-1p3-tool/src/lti/LTI_Registration.php
+ * @param string $iss
+ * @return IMSGlobal\LTI\LTI_Registration
+ */
+ public function find_registration_by_issuer($iss) {
+ $results = $this->LtiToolRegistration->findByIss($iss);
+ if (empty($results)) {
+ return false;
+ }
+ $lti_tool_registration = $results['LtiToolRegistration'];
+ return LTI_Registration::new()
+ ->set_auth_login_url($lti_tool_registration['auth_login_url'])
+ ->set_auth_token_url($lti_tool_registration['auth_token_url'])
+ ->set_client_id($lti_tool_registration['client_id'])
+ ->set_key_set_url($lti_tool_registration['key_set_url'])
+ ->set_issuer($lti_tool_registration['iss'])
+ ->set_tool_private_key($lti_tool_registration['tool_private_key']);
+ }
+
+ /**
+ * Find deployment by deployment_id.
+ *
+ * @see vendor/imsglobal/lti-1p3-tool/src/lti/LTI_Deployment.php
+ * @param string $iss
+ * @param string $deployment_id
+ * @return IMSGlobal\LTI\LTI_Deployment
+ */
+ public function find_deployment($iss, $deployment_id) {
+ // ignore deployment validation (just assume valid)
+ return LTI_Deployment::new()->set_deployment_id($deployment_id);
+ }
+}
diff --git a/app/libs/lti/names_and_roles_service.php b/app/libs/lti/names_and_roles_service.php
new file mode 100644
index 000000000..34c72bfb6
--- /dev/null
+++ b/app/libs/lti/names_and_roles_service.php
@@ -0,0 +1,136 @@
+User = \ClassRegistry::init('User');
+ $this->LtiContext = \ClassRegistry::init('LtiContext');
+ $this->LtiUser = \ClassRegistry::init('LtiUser');
+ $this->course_id = $course_id;
+ $this->service_connectors = array();
+ $this->lti_contexts = array();
+
+ $lti_contexts = $this->LtiContext->getByCourseId($course_id);
+ foreach ($lti_contexts as $lti_context) {
+ if (!empty($lti_context['LtiContext']['nrps_context_memberships_url'])) {
+ $this->lti_contexts []= $lti_context;
+
+ $lti_tool_registration = $lti_context['LtiToolRegistration'];
+ $registration = LTI_Registration::new()
+ ->set_auth_login_url($lti_tool_registration['auth_login_url'])
+ ->set_auth_token_url($lti_tool_registration['auth_token_url'])
+ ->set_client_id($lti_tool_registration['client_id'])
+ ->set_key_set_url($lti_tool_registration['key_set_url'])
+ ->set_issuer($lti_tool_registration['iss'])
+ ->set_tool_private_key($lti_tool_registration['tool_private_key']);
+ $this->service_connectors[$lti_tool_registration['id']] = new LTI_Service_Connector($registration);
+ }
+ }
+ return $this;
+ }
+
+ public function sync_membership() {
+ $instructors = array();
+ $tas = array();
+ $students = array();
+ foreach ($this->lti_contexts as $lti_context) {
+ $lti_tool_registration = $lti_context['LtiToolRegistration'];
+ $service_connector = $this->service_connectors[$lti_tool_registration['id']];
+ $context_memberships_url = $lti_context['LtiContext']['nrps_context_memberships_url'];
+
+ // get resource link to pull membership from
+ $lti_resource_links = $lti_context['LtiResourceLink'];
+ $resource_link_id = $lti_resource_links[0]['resource_link_id'];
+
+ // Canvas HACK: if context_id == resource_link_id then resource link
+ // will have membership for entire class (use these first if available)
+ foreach ($lti_resource_links as $lti_resource_link) {
+ if ($lti_resource_link['resource_link_id'] == $lti_context['LtiContext']['context_id']) {
+ $resource_link_id = $lti_resource_link['resource_link_id'];
+ break;
+ }
+ }
+
+ if (strpos($context_memberships_url, '?') !== false) {
+ $context_memberships_url .= "&rlid=$resource_link_id";
+ } else {
+ $context_memberships_url .= "?rlid=$resource_link_id";
+ }
+
+ $service_data = array('context_memberships_url' => $context_memberships_url);
+ $nrps = new LTI_Names_Roles_Provisioning_Service($service_connector, $service_data);
+
+ $all_members = $nrps->get_members();
+ foreach($all_members as $member_data) {
+ $nrsp_data_parser = new NamesAndRolesServiceDataParser($lti_tool_registration, $member_data);
+ if ($nrsp_data_parser->isActive()) {
+ // automatically create/update lti user + user
+ $lti_user = $this->LtiUser->syncUser(
+ $nrsp_data_parser->lti_tool_registration['id'],
+ $nrsp_data_parser->getParam('user_id'),
+ $nrsp_data_parser->getUserData()
+ );
+ $user_id = $lti_user['User']['id'];
+ $role_id = $nrsp_data_parser->getCourseRole();
+
+ // automatically update user enrollment
+ $this->LtiUser->syncUserEnrollment($this->course_id, $user_id, null, $role_id);
+
+ if (in_array($role_id, [$this->User->USER_TYPE_ADMIN, $this->User->USER_TYPE_INSTRUCTOR])) {
+ $instructors[$user_id] = true;
+ } elseif ($role_id == $this->User->USER_TYPE_TA) {
+ $tas[$user_id] = true;
+ } elseif ($role_id == $this->User->USER_TYPE_STUDENT) {
+ $students[$user_id] = true;
+ }
+ }
+ }
+ }
+
+ // remove old instructors who are no longer present
+ $current_instructor_ids = array_keys($instructors);
+ $existing_instructors = $this->User->getInstructorsByCourse($this->course_id);
+ foreach ($existing_instructors as $instructor) {
+ $user_id = $instructor['User']['id'];
+ if (!in_array($user_id, $current_instructor_ids)) {
+ $this->User->removeInstructor($user_id, $this->course_id);
+ }
+ }
+
+ // remove old tas who are no longer present
+ $current_ta_ids = array_keys($tas);
+ $existing_tas = $this->User->getTutorsByCourse($this->course_id);
+ foreach ($existing_tas as $ta) {
+ $user_id = $ta['User']['id'];
+ if (!in_array($user_id, $current_ta_ids)) {
+ $this->User->removeTutor($user_id, $this->course_id);
+ }
+ }
+
+ // remove old students who are no longer present
+ $current_student_ids = array_keys($students);
+ $existing_students = $this->User->getEnrolledStudents($this->course_id);
+ foreach ($existing_students as $student) {
+ $user_id = $student['User']['id'];
+ if (!in_array($user_id, $current_student_ids)) {
+ $this->User->removeStudent($user_id, $this->course_id);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/libs/lti/names_and_roles_service_data_parser.php b/app/libs/lti/names_and_roles_service_data_parser.php
new file mode 100644
index 000000000..55409000a
--- /dev/null
+++ b/app/libs/lti/names_and_roles_service_data_parser.php
@@ -0,0 +1,144 @@
+User = \ClassRegistry::init('User');
+ $this->member_data = $member_data;
+ $this->lti_tool_registration = $lti_tool_registration;
+ return $this;
+ }
+
+ public function getParam($param_name) {
+ if (!isset($this->member_data)) {
+ return null;
+ }
+ if (!isset($this->member_data[$param_name])) {
+ return null;
+ }
+ return $this->member_data[$param_name];
+ }
+
+ public function isActive() {
+ return $this->getParam('status') == 'Active';
+ }
+
+ public function getUserData() {
+ return array(
+ 'username' => $this->getUserIdentifierValue(),
+ 'first_name' => $this->getParam('given_name'),
+ 'last_name' => $this->getParam('family_name'),
+ 'student_no' => $this->getStudentNumberValue(),
+ 'email' => $this->getParam('email'),
+ );
+ }
+
+ # Core context roles
+ # http://purl.imsglobal.org/vocab/lis/v2/membership#Administrator
+ # http://purl.imsglobal.org/vocab/lis/v2/membership#ContentDeveloper
+ # http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor
+ # http://purl.imsglobal.org/vocab/lis/v2/membership#Learner
+ # http://purl.imsglobal.org/vocab/lis/v2/membership#Mentor
+ # Instructor Sub-role
+ # Grader, GuestInstructor, Instructor, Lecturer, PrimaryInstructor
+ # SecondaryInstructor, TeachingAssistant, TeachingAssistantGroup
+ # TeachingAssistantOffering, TeachingAssistantSection, TeachingAssistantTemplate
+ public function getCourseRole() {
+ $roles = $this->getParam('roles');
+ $is_admin = $is_instructor = $is_student = $is_ta = $is_content_developer = FALSE;
+
+ foreach ($roles as $role) {
+ # supports long and short formats. ex:
+ # http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor
+ # Instructor
+ # http://purl.imsglobal.org/vocab/lis/v2/membership/Instructor#TeachingAssistant
+ # Instructor#TeachingAssistant
+ $short_role = preg_replace('/http\:\/\/purl\.imsglobal\.org\/vocab\/lis\/v2\/membership(\#|\/)/i', '', $role);
+ if ('Administrator' == $short_role) {
+ $is_admin = TRUE;
+ } elseif ('Instructor' == $short_role) {
+ $is_instructor = TRUE;
+ } elseif ('ContentDeveloper' == $short_role) {
+ $is_content_developer = TRUE;
+ } elseif ('Instructor#TeachingAssistant' == $short_role) {
+ $is_ta = TRUE;
+ } elseif ('Learner' == $short_role) {
+ $is_student = TRUE;
+ }
+ }
+
+ if ($is_admin) {
+ return $this->User->USER_TYPE_INSTRUCTOR;
+ } elseif ($is_instructor && !$is_ta) {
+ return $this->User->USER_TYPE_INSTRUCTOR;
+ } elseif ($is_content_developer) {
+ return $this->User->USER_TYPE_INSTRUCTOR;
+ } elseif ($is_ta) {
+ return $this->User->USER_TYPE_TA;
+ } else {
+ return $this->User->USER_TYPE_STUDENT;
+ }
+ }
+
+ private function getDynamicFieldValue($field) {
+ if (empty($field)) {
+ return null;
+ }
+ $field_parts = explode("|", $field);
+ $data_ref = null;
+
+ if (sizeof($field_parts) == 1 && !empty($this->member_data[$field_parts[0]])) {
+ return $this->member_data[$field_parts[0]];
+ }
+
+ foreach ($this->member_data['message'] as $message) {
+ if ($message['https://purl.imsglobal.org/spec/lti/claim/message_type'] != 'LtiResourceLinkRequest') {
+ continue;
+ }
+ $data_ref = $message;
+ foreach($field_parts as $field_part) {
+ if (!is_array($data_ref) || empty($data_ref[$field_part])) {
+ return null;
+ }
+ $data_ref = $data_ref[$field_part];
+ }
+ break;
+ }
+
+ if (is_array($data_ref) || empty($data_ref)) {
+ return null;
+ }
+ return $data_ref;
+ }
+
+ public function getUserIdentifierValue() {
+ if (!empty($this->lti_tool_registration['user_identifier_field'])) {
+ $user_identifier_field = $this->lti_tool_registration['user_identifier_field'];
+
+ $value = $this->getDynamicFieldValue($user_identifier_field);
+ if (!empty($value)) {
+ return $value;
+ }
+ }
+ // default user identifer value
+ return $this->getParam('user_id');
+ }
+
+ public function getStudentNumberValue() {
+ if (!empty($this->lti_tool_registration['student_number_field'])) {
+ $student_number_field = $this->lti_tool_registration['student_number_field'];
+
+ $value = $this->getDynamicFieldValue($student_number_field);
+ if (!empty($value)) {
+ return $value;
+ }
+ }
+ // default student number value
+ return null;
+ }
+}
diff --git a/app/libs/upgrade_scripts/upgrade_349.php b/app/libs/upgrade_scripts/upgrade_349.php
new file mode 100644
index 000000000..9bc5d8c9d
--- /dev/null
+++ b/app/libs/upgrade_scripts/upgrade_349.php
@@ -0,0 +1,58 @@
+fromVersions = array(null, '3.4.8');
+ $this->toVersion = '3.4.9';
+ $this->dbVersion = 18;
+ }
+
+ /**
+ *
+ * @access public
+ * @return bool
+ */
+ public function isUpgradable()
+ {
+ return parent::isUpgradable();
+ }
+
+ /**
+ * up
+ *
+ * @access public
+ * @return boolean
+ */
+ public function up()
+ {
+ $sysparameter = ClassRegistry::init('SysParameter');
+ $dbv = $sysparameter->get('database.version');
+
+ $ret = $this->patchDb($dbv, $this->dbVersion);
+ if ($ret) {
+ $this->errors[] = sprintf(__('Database patching failed: %s', true), $ret);
+ return false;
+ }
+ $sysparameter->reload();
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/app/locale/default.pot b/app/locale/default.pot
index 75d9a8532..a4b39618f 100644
--- a/app/locale/default.pot
+++ b/app/locale/default.pot
@@ -4776,6 +4776,14 @@ msgstr ""
msgid "Compare"
msgstr ""
+#:
+msgid "Updated roster from Canvas"
+msgstr ""
+
+#:
+msgid "LTI 1.3 launch success"
+msgstr ""
+
#: /Users/compass/projects/ipeer/src//users/import.ctp:5
msgid "All fields mandatory, except email and password."
msgstr ""
diff --git a/app/models/course.php b/app/models/course.php
index 33cb075c7..20d09567f 100644
--- a/app/models/course.php
+++ b/app/models/course.php
@@ -35,6 +35,11 @@ class Course extends AppModel
'exclusive' => false,
'finderSql' => ''
),
+ 'LtiContext' => array(
+ 'className' => 'LtiContext',
+ 'foreignKey' => 'course_id',
+ 'dependent' => true
+ ),
'Event' => array(
'className' => 'Event',
'conditions' => 'Event.record_status = "A"',
diff --git a/app/models/event.php b/app/models/event.php
index 1dce64483..46ba95110 100644
--- a/app/models/event.php
+++ b/app/models/event.php
@@ -178,6 +178,11 @@ class Event extends AppModel
'dependent' => true,
'foreignKey' => 'event_id'
),
+ 'LtiResourceLink' => array(
+ 'className' => 'LtiResourceLink',
+ 'foreignKey' => 'event_id',
+ 'dependent' => true
+ ),
);
private $timezone = null;
@@ -1099,9 +1104,13 @@ function importEventsByCsv($courseId,$events,$userId)
$event_date_fields = array('due_date', 'release_date_begin', 'release_date_end', 'result_release_date_begin', 'result_release_date_end');
foreach ($event_date_fields as $eventDate) {
if (is_string($eventData[$eventDate])) {
- $timeStamp = strtotime($eventData[$eventDate]);
- if($timeStamp) {
- $eventData[$eventDate] = date("Y-m-d H:i:s", $timeStamp);
+ if(empty($eventData[$eventDate])) {
+ $eventData[$eventDate] = NULL;
+ } else {
+ $timeStamp = strtotime($eventData[$eventDate]);
+ if($timeStamp) {
+ $eventData[$eventDate] = date("Y-m-d H:i:s", $timeStamp);
+ }
}
}
}
diff --git a/app/models/lti_context.php b/app/models/lti_context.php
new file mode 100644
index 000000000..2efa353fe
--- /dev/null
+++ b/app/models/lti_context.php
@@ -0,0 +1,152 @@
+ array(
+ 'className' => 'Course',
+ 'foreignKey' => 'course_id'
+ ),
+ 'LtiToolRegistration' => array(
+ 'className' => 'LtiToolRegistration',
+ 'foreignKey' => 'lti_tool_registration_id'
+ )
+ );
+ public $hasMany = array(
+ 'LtiResourceLink' => array(
+ 'className' => 'LtiResourceLink',
+ 'foreignKey' => 'lti_context_id',
+ 'dependent' => true
+ ),
+ );
+ public $validate = array(
+ 'lti_tool_registration_id' => array(
+ 'notEmpty' => array(
+ 'rule' => 'notEmpty',
+ 'message' => 'Cannot be blank',
+ 'required' => true,
+ ),
+ ),
+ 'context_id' => array(
+ 'maxLength' => array(
+ 'rule' => array('maxLength', 255),
+ 'message' => 'Maximum 255 characters',
+ 'required' => true,
+ 'allowEmpty' => false,
+ ),
+ 'notEmpty' => array(
+ 'rule' => 'notEmpty',
+ 'message' => 'Cannot be blank',
+ 'required' => true,
+ ),
+ ),
+ );
+
+ public function syncFaculty($launch_data_parser) {
+ $this->Faculty = ClassRegistry::init('Faculty');
+ $name = $launch_data_parser->getFacultyNameValue();
+
+ $faculty = $this->Faculty->find('first', array(
+ 'conditions' => array(
+ 'Faculty.name' => $name
+ )
+ ));
+ if (empty($faculty)) {
+ $faculty = array(
+ 'Faculty' => array(
+ 'name' => $name,
+ )
+ );
+ $this->Faculty->save($faculty);
+
+ // refresh data after save
+ $faculty = $this->Faculty->find('first', array(
+ 'conditions' => array(
+ 'Faculty.name' => $name
+ )
+ ));
+ }
+ return $faculty;
+ }
+
+ public function syncLaunchContext($launch_data_parser)
+ {
+ $this->Course = ClassRegistry::init('Course');
+
+ $lti_tool_registration_id = $launch_data_parser->lti_tool_registration['id'];
+ $context_id = $launch_data_parser->getClaimParam('context', 'id');
+
+ $lti_context = $this->getByRegistrationIdAndContextId($lti_tool_registration_id, $context_id);
+ if (empty($lti_context)) {
+ $lti_context = array(
+ 'LtiContext' => array(
+ 'lti_tool_registration_id' => $lti_tool_registration_id,
+ 'context_id' => $context_id,
+ )
+ );
+ }
+ $lti_context['LtiContext']['nrps_context_memberships_url'] = $launch_data_parser->getNrpsClaimParam('context_memberships_url');
+
+ $course_data = $launch_data_parser->getCourseData();
+ //setup course link if needed
+ if (!isset($lti_context['LtiContext']['course_id'])) {
+ $existing_course = $this->Course->find('first', array(
+ 'conditions' => array('Course.course' => $course_data['course']),
+ 'contain' => false
+ ));
+ if (!empty($existing_course)) {
+ $lti_context['Course'] = $existing_course['Course'];
+ } else {
+ $lti_context['Course'] = $course_data;
+ }
+ }
+ //skip updating course
+ if (!empty($course_data['title'])) {
+ $lti_context['Course']['title'] = $course_data['title'];
+ }
+ if (!empty($course_data['canvas_id'])) {
+ $lti_context['Course']['canvas_id'] = $course_data['canvas_id'];
+ }
+ if (!empty($course_data['term'])) {
+ $lti_context['Course']['term'] = $course_data['term'];
+ }
+ $this->saveAll($lti_context);
+
+ // refresh data after save
+ $lti_context = $this->getByRegistrationIdAndContextId($lti_tool_registration_id, $context_id);
+ return $lti_context;
+ }
+
+ public function getByRegistrationIdAndContextId($lti_tool_registration_id, $context_id)
+ {
+ return $this->find('first', array(
+ 'conditions' => array(
+ 'LtiContext.lti_tool_registration_id' => $lti_tool_registration_id,
+ 'LtiContext.context_id' => $context_id,
+ ),
+ 'contain' => array(
+ 'Course'
+ )
+ ));
+ }
+
+ public function getByCourseId($course_id)
+ {
+ return $this->find('all', array(
+ 'conditions' => array(
+ 'LtiContext.course_id' => $course_id,
+ ),
+ 'contain' => array(
+ 'LtiResourceLink'
+ )
+ ));
+ }
+}
diff --git a/app/models/lti_nonce.php b/app/models/lti_nonce.php
new file mode 100644
index 000000000..fe14bda35
--- /dev/null
+++ b/app/models/lti_nonce.php
@@ -0,0 +1,43 @@
+ array(
+ 'maxLength' => array(
+ 'rule' => array('maxLength', 255),
+ 'message' => 'Maximum 255 characters',
+ 'required' => true,
+ 'allowEmpty' => false,
+ ),
+ 'notEmpty' => array(
+ 'rule' => 'notEmpty',
+ 'message' => 'Cannot be blank',
+ 'required' => true,
+ ),
+ ),
+ );
+
+ /**
+ * Find registration by `iss` in database.
+ *
+ * @param string $iss
+ * @return LtiNonce
+ */
+ public function findByNonce($nonce)
+ {
+ return $this->find('first', array(
+ 'conditions' => array(
+ 'LtiNonce.nonce' => $nonce
+ ),
+ ));
+ }
+}
diff --git a/app/models/lti_resource_link.php b/app/models/lti_resource_link.php
new file mode 100644
index 000000000..d7268c415
--- /dev/null
+++ b/app/models/lti_resource_link.php
@@ -0,0 +1,87 @@
+ array(
+ 'className' => 'LtiContext',
+ 'foreignKey' => 'lti_context_id'
+ ),
+ 'Event' => array(
+ 'className' => 'Event',
+ 'foreignKey' => 'event_id'
+ )
+ );
+ public $validate = array(
+ 'lti_context_id' => array(
+ 'notEmpty' => array(
+ 'rule' => 'notEmpty',
+ 'message' => 'Cannot be blank',
+ 'required' => true,
+ ),
+ ),
+ 'resource_link_id' => array(
+ 'maxLength' => array(
+ 'rule' => array('maxLength', 255),
+ 'message' => 'Maximum 255 characters',
+ 'required' => true,
+ 'allowEmpty' => false,
+ ),
+ 'notEmpty' => array(
+ 'rule' => 'notEmpty',
+ 'message' => 'Cannot be blank',
+ 'required' => true,
+ ),
+ ),
+ );
+
+ public function syncLaunchResourceLink($launch_data_parser, $lti_context_id)
+ {
+ $resource_link_id = $launch_data_parser->getClaimParam('resource_link', 'id');
+ $lti_resource_link = $this->getByLtiContextIdAndResourceLinkId($lti_context_id, $resource_link_id);
+
+ if (empty($lti_resource_link)) {
+ $lti_resource_link = array(
+ 'LtiResourceLink' => array(
+ 'lti_context_id' => $lti_context_id,
+ 'resource_link_id' => $resource_link_id,
+ )
+ );
+ }
+ $lti_resource_link['LtiResourceLink']['lineitems_url'] = $launch_data_parser->getAgsClaimParam('lineitems');
+ $lti_resource_link['LtiResourceLink']['lineitem_url'] = $launch_data_parser->getAgsClaimParam('lineitem');
+ $lti_resource_link['LtiResourceLink']['scope_lineitem'] = $launch_data_parser->hasAgsClaimScope('lineitem');
+ $lti_resource_link['LtiResourceLink']['scope_lineitem_read_only'] = $launch_data_parser->hasAgsClaimScope('lineitem.readonly');
+ $lti_resource_link['LtiResourceLink']['scope_result_readonly'] = $launch_data_parser->hasAgsClaimScope('result.readonly');
+ $lti_resource_link['LtiResourceLink']['scope_result_score'] = $launch_data_parser->hasAgsClaimScope('score');
+
+ // $event_data = $launch_data_parser->getEventData();
+
+ $this->save($lti_resource_link);
+
+ // refresh data after save
+ $lti_resource_link = $this->getByLtiContextIdAndResourceLinkId($lti_context_id, $resource_link_id);
+ return $lti_resource_link;
+ }
+
+ public function getByLtiContextIdAndResourceLinkId($lti_context_id, $resource_link_id)
+ {
+ return $this->find('first', array(
+ 'conditions' => array(
+ 'LtiResourceLink.lti_context_id' => $lti_context_id,
+ 'LtiResourceLink.resource_link_id' => $resource_link_id,
+ ),
+ 'contain' => array(
+ 'Event',
+ )
+ ));
+ }
+}
diff --git a/app/models/lti_tool_registration.php b/app/models/lti_tool_registration.php
new file mode 100644
index 000000000..de299b943
--- /dev/null
+++ b/app/models/lti_tool_registration.php
@@ -0,0 +1,158 @@
+
+ * @license MIT {@link http://www.opensource.org/licenses/MIT}
+ */
+class LtiToolRegistration extends AppModel
+{
+ public $name = 'LtiToolRegistration';
+ public $validate = array(
+ 'iss' => array(
+ 'maxLength' => array(
+ 'rule' => array('maxLength', 255),
+ 'message' => 'Maximum 255 characters',
+ 'required' => true,
+ 'allowEmpty' => false,
+ ),
+ 'notEmpty' => array(
+ 'rule' => 'notEmpty',
+ 'message' => 'Cannot be blank',
+ 'required' => true,
+ ),
+ ),
+ 'client_id' => array(
+ 'maxLength' => array(
+ 'rule' => array('maxLength', 255),
+ 'message' => 'Maximum 255 characters',
+ 'required' => true,
+ 'allowEmpty' => false,
+ ),
+ 'notEmpty' => array(
+ 'rule' => 'notEmpty',
+ 'message' => 'Cannot be blank',
+ 'required' => true,
+ ),
+ ),
+ 'auth_login_url' => array(
+ 'maxLength' => array(
+ 'rule' => array('maxLength', 255),
+ 'message' => 'Maximum 255 characters',
+ 'required' => true,
+ 'allowEmpty' => false,
+ ),
+ 'notEmpty' => array(
+ 'rule' => 'notEmpty',
+ 'message' => 'Cannot be blank',
+ 'required' => true,
+ ),
+ ),
+ 'auth_token_url' => array(
+ 'maxLength' => array(
+ 'rule' => array('maxLength', 255),
+ 'message' => 'Maximum 255 characters',
+ 'required' => true,
+ 'allowEmpty' => false,
+ ),
+ 'notEmpty' => array(
+ 'rule' => 'notEmpty',
+ 'message' => 'Cannot be blank',
+ 'required' => true,
+ ),
+ ),
+ 'key_set_url' => array(
+ 'maxLength' => array(
+ 'rule' => array('maxLength', 255),
+ 'message' => 'Maximum 255 characters',
+ 'required' => true,
+ 'allowEmpty' => false,
+ ),
+ 'notEmpty' => array(
+ 'rule' => 'notEmpty',
+ 'message' => 'Cannot be blank',
+ 'required' => true,
+ ),
+ ),
+ 'tool_private_key' => array(
+ 'notEmpty' => array(
+ 'rule' => 'notEmpty',
+ 'message' => 'Cannot be blank',
+ 'required' => true,
+ ),
+ ),
+ 'tool_public_key' => array(
+ 'notEmpty' => array(
+ 'rule' => 'notEmpty',
+ 'message' => 'Cannot be blank',
+ 'required' => true,
+ ),
+ ),
+ 'user_identifier_field' => array(
+ 'maxLength' => array(
+ 'rule' => array('maxLength', 255),
+ 'message' => 'Maximum 255 characters',
+ 'required' => false,
+ 'allowEmpty' => true,
+ ),
+ ),
+ 'student_number_field' => array(
+ 'maxLength' => array(
+ 'rule' => array('maxLength', 255),
+ 'message' => 'Maximum 255 characters',
+ 'required' => false,
+ 'allowEmpty' => true,
+ ),
+ ),
+ 'term_field' => array(
+ 'maxLength' => array(
+ 'rule' => array('maxLength', 255),
+ 'message' => 'Maximum 255 characters',
+ 'required' => false,
+ 'allowEmpty' => true,
+ ),
+ ),
+ 'canvas_id_field' => array(
+ 'maxLength' => array(
+ 'rule' => array('maxLength', 255),
+ 'message' => 'Maximum 255 characters',
+ 'required' => false,
+ 'allowEmpty' => true,
+ ),
+ ),
+ 'faculty_name_field' => array(
+ 'maxLength' => array(
+ 'rule' => array('maxLength', 255),
+ 'message' => 'Maximum 255 characters',
+ 'required' => false,
+ 'allowEmpty' => true,
+ ),
+ ),
+ );
+
+ public $hasMany = array(
+ 'LtiContext' => array(
+ 'className' => 'LtiContext',
+ 'foreignKey' => 'lti_tool_registration_id',
+ 'dependent' => true
+ ),
+ );
+
+ /**
+ * Find registration by `iss` in database.
+ *
+ * @param string $iss
+ * @return LtiToolRegistration
+ */
+ public function findByIss($iss)
+ {
+ return $this->find('first', array(
+ 'conditions' => array(
+ 'LtiToolRegistration.iss' => $iss
+ ),
+ ));
+ }
+}
diff --git a/app/models/lti_user.php b/app/models/lti_user.php
new file mode 100644
index 000000000..6f932b939
--- /dev/null
+++ b/app/models/lti_user.php
@@ -0,0 +1,162 @@
+ array(
+ 'className' => 'User',
+ 'foreignKey' => 'ipeer_user_id'
+ )
+ );
+ public $validate = array(
+ 'lti_tool_registration_id' => array(
+ 'notEmpty' => array(
+ 'rule' => 'notEmpty',
+ 'message' => 'Cannot be blank',
+ 'required' => true,
+ ),
+ ),
+ 'lti_user_id' => array(
+ 'maxLength' => array(
+ 'rule' => array('maxLength', 255),
+ 'message' => 'Maximum 255 characters',
+ 'required' => true,
+ 'allowEmpty' => false,
+ ),
+ 'notEmpty' => array(
+ 'rule' => 'notEmpty',
+ 'message' => 'Cannot be blank',
+ 'required' => true,
+ ),
+ ),
+ );
+
+ public function syncUser($lti_tool_registration_id, $lti_user_id, $user_data)
+ {
+ $this->User = ClassRegistry::init('User');
+
+ $lti_user = $this->getByRegistrationIdAndLtiUserId($lti_tool_registration_id, $lti_user_id);
+ if (empty($lti_user)) {
+ $lti_user = array(
+ 'LtiUser' => array(
+ 'lti_tool_registration_id' => $lti_tool_registration_id,
+ 'lti_user_id' => $lti_user_id,
+ )
+ );
+ }
+
+ //setup user link if needed
+ if (!isset($lti_user['LtiUser']['ipeer_user_id'])) {
+ $existing_user = $this->User->find('first', array(
+ 'conditions' => array('User.username' => $user_data['username']),
+ 'contain' => false
+ ));
+ if (!empty($existing_user)) {
+ $lti_user['User'] = $existing_user['User'];
+ } else {
+ $lti_user['User'] = $user_data;
+ }
+ }
+ //skip updating username
+ if (!empty($user_data['first_name'])) {
+ $lti_user['User']['first_name'] = $user_data['first_name'];
+ }
+ if (!empty($user_data['last_name'])) {
+ $lti_user['User']['last_name'] = $user_data['last_name'];
+ }
+ if (!empty($user_data['student_no'])) {
+ $lti_user['User']['student_no'] = $user_data['student_no'];
+ }
+ if (!empty($user_data['email'])) {
+ $lti_user['User']['email'] = $user_data['email'];
+ }
+
+ $this->saveAll($lti_user);
+
+ // refresh data after save
+ $lti_user = $this->getByRegistrationIdAndLtiUserId($lti_tool_registration_id, $lti_user_id);
+ return $lti_user;
+ }
+
+ public function syncUserEnrollment($course_id, $user_id, $faculty_id, $role_id)
+ {
+ $this->User = ClassRegistry::init('User');
+ $this->Role = ClassRegistry::init('Role');
+
+ # add new system roles as needed
+ $results = $this->Role->find('all', array(
+ 'conditions' => array('User.id' => $user_id),
+ 'recursive' => 0
+ ));
+ $system_role_ids = Set::extract('/Role/id', $results);
+ if (!in_array($role_id, $system_role_ids)) {
+ $this->User->registerRole($user_id, $role_id);
+ }
+
+ # handle enrollments
+ $results = $this->User->find('first', array(
+ 'conditions' => array('User.id' => $user_id),
+ 'contain' => array(
+ 'Faculty' => array('conditions' => array('Faculty.id' => $faculty_id)),
+ 'Course' => array('conditions' => array('Course.id' => $course_id)),
+ 'Tutor' => array('conditions' => array('Tutor.id' => $course_id)),
+ 'Enrolment' => array('conditions' => array('Enrolment.id' => $course_id)),
+ )
+ ));
+
+ if (in_array($role_id, [$this->User->USER_TYPE_ADMIN, $this->User->USER_TYPE_INSTRUCTOR])) {
+ if (sizeof($results['Course']) == 0) {
+ $this->User->addInstructor($user_id, $course_id);
+ }
+ # ensure user is assigned to a Faculty if instructor or admin
+ if (sizeof($results['Faculty']) == 0 && !empty($faculty_id)) {
+ $this->User->habtmAdd('Faculty', $user_id, $faculty_id);
+ }
+ } else {
+ if (sizeof($results['Course']) > 0) {
+ $this->User->removeInstructor($user_id, $course_id);
+ }
+ }
+
+ if ($role_id == $this->User->USER_TYPE_TA) {
+ if (sizeof($results['Tutor']) == 0) {
+ $this->User->addTutor($user_id, $course_id);
+ }
+ } else {
+ if (sizeof($results['Tutor']) > 0) {
+ $this->User->removeTutor($user_id, $course_id);
+ }
+ }
+
+ if ($role_id == $this->User->USER_TYPE_STUDENT) {
+ if (sizeof($results['Enrolment']) == 0) {
+ $this->User->addStudent($user_id, $course_id);
+ }
+ } else {
+ if (sizeof($results['Enrolment']) > 0) {
+ $this->User->removeStudent($user_id, $course_id);
+ }
+ }
+ }
+
+ public function getByRegistrationIdAndLtiUserId($lti_tool_registration_id, $lti_user_id)
+ {
+ return $this->find('first', array(
+ 'conditions' => array(
+ 'LtiUser.lti_tool_registration_id' => $lti_tool_registration_id,
+ 'LtiUser.lti_user_id' => $lti_user_id,
+ ),
+ 'contain' => array(
+ 'User'
+ )
+ ));
+ }
+}
diff --git a/app/models/user.php b/app/models/user.php
index b95c84344..e51c7027a 100644
--- a/app/models/user.php
+++ b/app/models/user.php
@@ -53,6 +53,11 @@ class User extends AppModel
'className' => 'SurveyGroupMember',
'foreignKey' => 'user_id',
),
+ 'LtiUser' => array(
+ 'className' => 'LtiUser',
+ 'foreignKey' => 'ipeer_user_id',
+ 'dependent' => true
+ ),
);
public $hasAndBelongsToMany = array(
@@ -1499,16 +1504,9 @@ protected function requiredWith($check, $with)
protected function validEmail($check)
{
$email = $check['email'];
- if (function_exists('filter_var')) {
- // filter_var() requires php >= 5.2.0
- if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
- return true;
- }
- } else {
- // really basic fallback validation
- if (preg_match('/.+@.+/', $email)) {
- return true;
- }
+ // really basic fallback validation
+ if (preg_match('/.+@.+/', $email)) {
+ return true;
}
return false;
}
diff --git a/app/tests/cases/caliper/app_controller_hooks.test.php b/app/tests/cases/caliper/app_controller_hooks.test.php
index ad137c3bd..586fa9780 100644
--- a/app/tests/cases/caliper/app_controller_hooks.test.php
+++ b/app/tests/cases/caliper/app_controller_hooks.test.php
@@ -23,6 +23,8 @@ class CaliperAppControllerHooksTest extends CaliperAuthTestCase
{
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/caliper/course_hooks.test.php b/app/tests/cases/caliper/course_hooks.test.php
index a9aec1b4f..765d1ee4b 100644
--- a/app/tests/cases/caliper/course_hooks.test.php
+++ b/app/tests/cases/caliper/course_hooks.test.php
@@ -23,6 +23,8 @@ class CaliperCourseHooksTest extends CaliperAuthTestCase
{
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/caliper/event_mixeval_hooks.test.php b/app/tests/cases/caliper/event_mixeval_hooks.test.php
index 5ea7904cd..78b30702b 100644
--- a/app/tests/cases/caliper/event_mixeval_hooks.test.php
+++ b/app/tests/cases/caliper/event_mixeval_hooks.test.php
@@ -23,6 +23,8 @@ class CaliperEventMixevalHooksTest extends CaliperAuthTestCase
{
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/caliper/event_rubric_hooks.test.php b/app/tests/cases/caliper/event_rubric_hooks.test.php
index fb0f7ce3b..d0ce75ec1 100644
--- a/app/tests/cases/caliper/event_rubric_hooks.test.php
+++ b/app/tests/cases/caliper/event_rubric_hooks.test.php
@@ -23,6 +23,8 @@ class CaliperEventRubricHooksTest extends CaliperAuthTestCase
{
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/caliper/event_simple_evaulation_hooks.test.php b/app/tests/cases/caliper/event_simple_evaulation_hooks.test.php
index c7da7e336..e5cf49425 100644
--- a/app/tests/cases/caliper/event_simple_evaulation_hooks.test.php
+++ b/app/tests/cases/caliper/event_simple_evaulation_hooks.test.php
@@ -23,6 +23,8 @@ class CaliperEventSimpleEvaluationHooksTest extends CaliperAuthTestCase
{
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/caliper/event_survey_hooks.test.php b/app/tests/cases/caliper/event_survey_hooks.test.php
index 62a34b747..491e450bf 100644
--- a/app/tests/cases/caliper/event_survey_hooks.test.php
+++ b/app/tests/cases/caliper/event_survey_hooks.test.php
@@ -23,6 +23,8 @@ class CaliperEventSurveyHooksTest extends CaliperAuthTestCase
{
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/caliper/mixeval_hooks.test.php b/app/tests/cases/caliper/mixeval_hooks.test.php
index 644764cdf..bee3317f8 100644
--- a/app/tests/cases/caliper/mixeval_hooks.test.php
+++ b/app/tests/cases/caliper/mixeval_hooks.test.php
@@ -24,6 +24,8 @@ class CaliperMixevalHooksTest extends CaliperAuthTestCase
{
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/caliper/rubric_hooks.test.php b/app/tests/cases/caliper/rubric_hooks.test.php
index 2b3617c3b..b825026ab 100644
--- a/app/tests/cases/caliper/rubric_hooks.test.php
+++ b/app/tests/cases/caliper/rubric_hooks.test.php
@@ -24,6 +24,8 @@ class CaliperRubricHooksTest extends CaliperAuthTestCase
{
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/caliper/simple_evaluation_hooks.test.php b/app/tests/cases/caliper/simple_evaluation_hooks.test.php
index 738709b3c..93b5028ad 100644
--- a/app/tests/cases/caliper/simple_evaluation_hooks.test.php
+++ b/app/tests/cases/caliper/simple_evaluation_hooks.test.php
@@ -23,6 +23,8 @@ class CaliperSimpleEvaluationHooksTest extends CaliperAuthTestCase
{
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/caliper/survey_hooks.test.php b/app/tests/cases/caliper/survey_hooks.test.php
index 5798957e9..af7a175bc 100644
--- a/app/tests/cases/caliper/survey_hooks.test.php
+++ b/app/tests/cases/caliper/survey_hooks.test.php
@@ -23,6 +23,8 @@ class CaliperSurveyHooksTest extends CaliperAuthTestCase
{
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/components/evaluation_component.test.php b/app/tests/cases/components/evaluation_component.test.php
index f4bab43fb..ec0280c78 100644
--- a/app/tests/cases/components/evaluation_component.test.php
+++ b/app/tests/cases/components/evaluation_component.test.php
@@ -12,6 +12,8 @@ class EvaluationTestCase extends CakeTestCase
{
public $fixtures = array('app.course', 'app.role', 'app.user', 'app.group', 'app.penalty', 'app.user_grade_penalty',
'app.roles_user', 'app.event', 'app.event_template_type',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.group_event', 'app.evaluation_submission','app.evaluation_mixeval',
'app.survey_group_set', 'app.survey_group', 'app.groups_member',
'app.survey_group_member', 'app.question', 'app.survey_input', 'app.rubrics_lom', 'app.evaluation_rubric', 'app.evaluation_rubric_detail',
@@ -181,7 +183,7 @@ function saveNGetEvalutionRubricDetail()
{
}
-
+
/**
* testGetStudentViewRubricResultDetailReview
*
@@ -361,7 +363,7 @@ function testFormatRubricEvaluationResultsMatrix()
),
);
$this->assertEqual($expected, $result);
-
+
// Tests null instance
$result = Toolkit::formatRubricEvaluationResultsMatrix(null);
$this->assertFalse($result);
@@ -465,7 +467,7 @@ function testSaveNGetEvaluationMixevalDetail()
// Get the grade with real values
$grade = $this->EvaluationComponentTest->saveNGetEvaluationMixevalDetail ($evalMixevalId, $mixeval, $form, $auto_release);
$this->assertEqual($grade, 0.8);
-
+
// Test the method with null values
$grade = $this->EvaluationComponentTest->saveNGetEvaluationMixevalDetail (null, null, null, null);
$this->assertFalse($grade);
@@ -528,7 +530,7 @@ function testGetStudentViewMixevalResultDetailReview()
$this->assertWithinMargin($currentTime, $eval[5][0]['Event']['due_in'], 5);
// Null due_in time since we are doing assertEqual
$eval[5][0]['Event']['due_in'] = null;
-
+
// Set up expected return value
$expected = $this->setUpMixevalResultDetailReview();
$this->assertEqual($eval, $expected);
@@ -539,10 +541,10 @@ function testGetStudentViewMixevalResultDetailReview()
$eval = $this->EvaluationComponentTest->getStudentViewMixevalResultDetailReview(1, null);
$this->assertFalse(!empty($eval));
}
-
+
function testFormatMixevalEvaluationResultsMatrix()
{
-
+
}
@@ -641,19 +643,19 @@ function testFormatSurveyEvaluationSummary()
$survey = $this->EvaluationComponentTest->formatSurveyEvaluationSummary($surveyId, $eventId, $userIds);
$expected = $this->setUpSurveyTestData();
$this->assertEqual($expected, $survey);
-
+
// Testing null and 'random' values
$survey = $this->EvaluationComponentTest->formatSurveyEvaluationSummary(999, $eventId, $userIds);
$this->assertFalse($survey);
// Set up survey results with no responses
$expected = $this->setUpSurveyBlankData();
-
+
$survey = $this->EvaluationComponentTest->formatSurveyEvaluationSummary($surveyId, 999, $userIds);
$this->assertEqual($expected, $survey);
-
+
$survey = $this->EvaluationComponentTest->formatSurveyEvaluationSummary($surveyId, $eventId, array(84, 180, 230));
$this->assertEqual($expected, $survey);
-
+
$survey = $this->EvaluationComponentTest->formatSurveyEvaluationSummary(null, null, null);
$this->assertFalse($survey);
}
diff --git a/app/tests/cases/controllers/accesses_controller.test.php b/app/tests/cases/controllers/accesses_controller.test.php
index 5bd70e779..d24283f23 100644
--- a/app/tests/cases/controllers/accesses_controller.test.php
+++ b/app/tests/cases/controllers/accesses_controller.test.php
@@ -6,7 +6,7 @@
Mock::generatePartial('AccessesController',
'MockAccessesController',
array('isAuthorized', 'render', 'redirect', '_stop', 'header'));
-
+
/**
* AccessesControllerTest Accesses controller test case
*
@@ -16,10 +16,12 @@
class AccessesControllerTest extends ExtendedAuthTestCase
{
public $controller = null;
-
+
public $fixtures = array(
'app.access', 'app.oauth_token', 'app.sys_parameter',
'app.user', 'app.evaluation_submission', 'app.event', 'app.event_template_type',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.course', 'app.group', 'app.group_event', 'app.evaluation_simple',
'app.survey_input', 'app.survey_group_member', 'app.survey_group_set',
'app.survey', 'app.question', 'app.response', 'app.survey_question',
@@ -28,7 +30,7 @@ class AccessesControllerTest extends ExtendedAuthTestCase
'app.department', 'app.course_department', 'app.penalty', 'app.evaluation_rubric',
'app.evaluation_rubric_detail', 'app.evaluation_mixeval', 'app.evaluation_mixeval_detail'
);
-
+
/**
* startCase case startup
*
@@ -45,7 +47,7 @@ public function startCase()
)
);
}
-
+
/**
* endCase case ending
*
@@ -55,7 +57,7 @@ public function startCase()
public function endCase()
{
}
-
+
/**
* startTest prepare tests
* @access public
@@ -66,7 +68,7 @@ public function startTest($method)
echo $method.TEST_LB;
$this->controller = new MockAccessesController();
}
-
+
/**
* @access public
* @return void
@@ -79,12 +81,12 @@ public function endTest($method)
unset($this->controller);
ClassRegistry::flush();
}
-
+
public function getController()
{
return $this->controller;
}
-
+
function testView()
{
//id should not be used since it can change
@@ -96,43 +98,43 @@ function testView()
$this->assertEqual($superadmin['permissions']['controllers/courses/add'], $allow);
$this->assertEqual($superadmin['roleId'], 1);
$this->assertEqual($superadmin['title_for_layout'], 'Permissions Editor > superadmin');
-
+
$admin = $this->testAction('/accesses/view/2', array('return' => 'vars'));
unset($admin['permissions']['controllers/courses/add']["id"]);
$this->assertEqual($admin['permissions']['controllers/courses/add'], $allow);
$this->assertEqual($admin['roleId'], 2);
$this->assertEqual($admin['title_for_layout'], 'Permissions Editor > admin');
-
+
$instructor = $this->testAction('/accesses/view/3', array('return' => 'vars'));
unset($instructor['permissions']['controllers/courses/add']["id"]);
$this->assertEqual($instructor['permissions']['controllers/courses/add'], $allow);
$this->assertEqual($instructor['roleId'], 3);
$this->assertEqual($instructor['title_for_layout'], 'Permissions Editor > instructor');
-
+
$tutor = $this->testAction('/accesses/view/4', array('return' => 'vars'));
unset($tutor['permissions']['controllers/courses/add']["id"]);
$this->assertEqual($tutor['permissions']['controllers/courses/add'], $deny);
$this->assertEqual($tutor['roleId'], 4);
$this->assertEqual($tutor['title_for_layout'], 'Permissions Editor > tutor');
-
+
$student = $this->testAction('/accesses/view/5', array('return' => 'vars'));
unset($student['permissions']['controllers/courses/add']["id"]);
$this->assertEqual($student['permissions']['controllers/courses/add'], $deny);
$this->assertEqual($student['roleId'], 5);
$this->assertEqual($student['title_for_layout'], 'Permissions Editor > student');
}
-
+
function testEdit()
{
$this->Access = ClassRegistry::init('Access');
-
+
// no entry existed before the next test
$result = $this->Access->find('first', array(
'conditions' => array('aro_id' => 2, 'aco_id' => 11)
));
$this->assertEqual($result, array());
-
- // testing allowing access to ALL actions that has no entry in the aros_acos table
+
+ // testing allowing access to ALL actions that has no entry in the aros_acos table
$this->testAction('/accesses/edit/allow/11/2');
$result = $this->Access->find('first', array(
'conditions' => array('aro_id' => 2, 'aco_id' => 11)
@@ -141,7 +143,7 @@ function testEdit()
$this->assertEqual($result['Access']['_read'], 1);
$this->assertEqual($result['Access']['_update'], 1);
$this->assertEqual($result['Access']['_delete'], 1);
-
+
// testing denying access to ALL actions that has an entry in the aros_acos table
$this->testAction('/accesses/edit/deny/11/2');
$result = $this->Access->find('first', array(
@@ -151,15 +153,15 @@ function testEdit()
$this->assertEqual($result['Access']['_read'], -1);
$this->assertEqual($result['Access']['_update'], -1);
$this->assertEqual($result['Access']['_delete'], -1);
-
+
$this->Access->delete($result['Access']['id']);
-
+
// no entry existed before the next test
$result = $this->Access->find('first', array(
'conditions' => array('aro_id' => 2, 'aco_id' => 12)
));
$this->assertEqual($result, array());
-
+
// testing allowing access to ONE action that has no entry in the aros_acos table
$this->testAction('/accesses/edit/allow/12/2/create');
$result = $this->Access->find('first', array(
@@ -169,7 +171,7 @@ function testEdit()
$this->assertEqual($result['Access']['_read'], -1);
$this->assertEqual($result['Access']['_update'], -1);
$this->assertEqual($result['Access']['_delete'], -1);
-
+
// testing denying access to ONE action that has an entry in the aros_acos table
$this->testAction('/accesses/edit/deny/12/2/create');
$result = $this->Access->find('first', array(
@@ -179,7 +181,7 @@ function testEdit()
$this->assertEqual($result['Access']['_read'], -1);
$this->assertEqual($result['Access']['_update'], -1);
$this->assertEqual($result['Access']['_delete'], -1);
-
+
$this->Access->delete($result['Access']['id']);
}
}
diff --git a/app/tests/cases/controllers/courses_controller.test.php b/app/tests/cases/controllers/courses_controller.test.php
index 0bbcfa3ec..69510766e 100644
--- a/app/tests/cases/controllers/courses_controller.test.php
+++ b/app/tests/cases/controllers/courses_controller.test.php
@@ -29,6 +29,8 @@ class CoursesControllerTest extends ExtendedAuthTestCase
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
@@ -137,7 +139,6 @@ class CoursesControllerTest extends ExtendedAuthTestCase
'created' => '2006-06-19 16:25:24',
'updater_id' => null,
'modified' => '2006-06-19 16:25:24',
- 'lti_id' => null,
'full_name' => 'Instructor 1',
'student_no_with_full_name' => 'Instructor 1',
'creator' => 'Super Admin',
@@ -171,7 +172,6 @@ class CoursesControllerTest extends ExtendedAuthTestCase
'created' => '2006-06-20 14:17:02',
'updater_id' => null,
'modified' => '2006-06-20 14:17:02',
- 'lti_id' => null,
'full_name' => 'Instructor 2',
'student_no_with_full_name' => 'Instructor 2',
'creator' => 'Super Admin',
@@ -206,7 +206,6 @@ class CoursesControllerTest extends ExtendedAuthTestCase
'created' => '2006-06-20 14:17:53',
'updater_id' => null,
'modified' => '2006-06-20 14:17:53',
- 'lti_id' => null,
'full_name' => 'Instructor 3',
'student_no_with_full_name' => 'Instructor 3',
'creator' => 'Super Admin',
diff --git a/app/tests/cases/controllers/departments_controller.test.php b/app/tests/cases/controllers/departments_controller.test.php
index ecbdae173..557ab2f8e 100644
--- a/app/tests/cases/controllers/departments_controller.test.php
+++ b/app/tests/cases/controllers/departments_controller.test.php
@@ -19,6 +19,8 @@ function redirect($url, $status = null, $exit = true) {
class DepartmentsControllerTestCase extends ExtendedAuthTestCase {
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/controllers/evaltools_controller.test.php b/app/tests/cases/controllers/evaltools_controller.test.php
index 87df43151..ec25b0251 100644
--- a/app/tests/cases/controllers/evaltools_controller.test.php
+++ b/app/tests/cases/controllers/evaltools_controller.test.php
@@ -21,6 +21,8 @@ class FakeController extends Controller {
class EvaltoolsControllerTest extends CakeTestCase {
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/controllers/evaluations_controller.test.php b/app/tests/cases/controllers/evaluations_controller.test.php
index e7467109f..065cfbdad 100644
--- a/app/tests/cases/controllers/evaluations_controller.test.php
+++ b/app/tests/cases/controllers/evaluations_controller.test.php
@@ -22,6 +22,8 @@ class EvaluationControllerTest extends ExtendedAuthTestCase
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
@@ -163,13 +165,13 @@ function testMakeEvaluationSurveyForStudent()
$result = $this->testAction('/evaluations/makeEvaluation/4', array('return' => 'vars'));
$this->assertEqual($result['eventId'], 4);
$this->assertEqual(count($result['questions']), 2);
- $this->assertEqual($result['questions'][0]['Question']['prompt'],
+ $this->assertEqual($result['questions'][0]['Question']['prompt'],
'What was your GPA last term?');
- $this->assertEqual($result['questions'][1]['Question']['prompt'],
+ $this->assertEqual($result['questions'][1]['Question']['prompt'],
'Do you own a laptop?');
- $this->assertEqual(count($result['questions'][0]['ResponseOptions']),
+ $this->assertEqual(count($result['questions'][0]['ResponseOptions']),
4);
- $this->assertEqual(count($result['questions'][1]['ResponseOptions']),
+ $this->assertEqual(count($result['questions'][1]['ResponseOptions']),
2);
$message = $this->controller->Session->read('Message.flash');
$this->assertEqual($message['message'], '');
diff --git a/app/tests/cases/controllers/events_controller.test.php b/app/tests/cases/controllers/events_controller.test.php
index 5a66851c5..9a86ae8bb 100644
--- a/app/tests/cases/controllers/events_controller.test.php
+++ b/app/tests/cases/controllers/events_controller.test.php
@@ -28,6 +28,8 @@ class EventsControllerTest extends ExtendedAuthTestCase {
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/controllers/faculties_controller.test.php b/app/tests/cases/controllers/faculties_controller.test.php
index 39f8da492..d24c46fa4 100644
--- a/app/tests/cases/controllers/faculties_controller.test.php
+++ b/app/tests/cases/controllers/faculties_controller.test.php
@@ -14,6 +14,8 @@ class FacultiesControllerTestCase extends ExtendedAuthTestCase {
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/controllers/groups_controller.test.php b/app/tests/cases/controllers/groups_controller.test.php
index 743eff19c..6b4b47266 100644
--- a/app/tests/cases/controllers/groups_controller.test.php
+++ b/app/tests/cases/controllers/groups_controller.test.php
@@ -21,6 +21,8 @@ class GroupsControllerTest extends ExtendedAuthTestCase {
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/controllers/home_controller.test.php b/app/tests/cases/controllers/home_controller.test.php
index b35f9294d..3d3743de2 100644
--- a/app/tests/cases/controllers/home_controller.test.php
+++ b/app/tests/cases/controllers/home_controller.test.php
@@ -22,6 +22,8 @@ class HomeControllerTest extends ExtendedAuthTestCase
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
@@ -80,7 +82,7 @@ function testIndex()
$this->assertTrue(
strtotime($result['course_list']['A'][0]['Course']['created']) >
strtotime($result['course_list']['A'][1]['Course']['created']));
-
+
$this->assertEqual(
$result['course_list']['A'][1]['Course']['course'], 'APSC 201');
$this->assertEqual(
diff --git a/app/tests/cases/controllers/lti_controller.test.php b/app/tests/cases/controllers/lti_controller.test.php
new file mode 100644
index 000000000..83c598e3b
--- /dev/null
+++ b/app/tests/cases/controllers/lti_controller.test.php
@@ -0,0 +1,2183 @@
+; rel="current"',
+ '; rel="next"',
+ '; rel="first"',
+ '; rel="last"',
+ );
+ $headers = array(
+ 'HTTP/1.1 200 OK',
+ 'Content-Type: application/vnd.ims.lti-nrps.v2.membershipcontainer+json; charset=utf-8',
+ 'Status: 200 OK',
+ 'Link: ' . implode(',', $links),
+ );
+ $header = implode("\r\n", $headers)."\r\n";
+ $CURL_HEADER_SIZE = strlen($header);
+ return $header . '{
+ "id": "; rel="current"',
+ '; rel="previous"',
+ '; rel="first"',
+ '; rel="last"',
+ );
+ $headers = array(
+ 'HTTP/1.1 200 OK',
+ 'Content-Type: application/vnd.ims.lti-nrps.v2.membershipcontainer+json; charset=utf-8',
+ 'Status: 200 OK',
+ 'Link: ' . implode(',', $links),
+ );
+ $header = implode("\r\n", $headers)."\r\n";
+ $CURL_HEADER_SIZE = strlen($header);
+ return $header . '{
+ "id": "defaultLogin = array(
+ 'User' => array(
+ 'username' => 'root',
+ 'password' => md5('ipeeripeer')
+ )
+ );
+ }
+
+ function endCase() {
+ }
+
+ function startTest($method) {
+ echo $method.TEST_LB;
+ $this->controller = new MockLtiController();
+
+ $this->login_data = array(
+ "iss" => "https://docker-canvas.instructure.com",
+ "login_hint" => "135745",
+ "target_link_uri" => "https://localhost/lti/launch/",
+ "lti_message_hint" => "19481",
+ "lti_deployment_id" => "10000:10000000000013",
+ "client_id" => "10000000000013",
+ );
+ $this->base_launch_data = array(
+ "https://purl.imsglobal.org/spec/lti/claim/message_type" => "LtiResourceLinkRequest",
+ "https://purl.imsglobal.org/spec/lti/claim/resource_link" => [
+ "id" => "19481",
+ "title" => "Test Link",
+ "description" => "N/A"
+ ],
+ "https://purl.imsglobal.org/spec/lti/claim/context" => [
+ "id" => "10045",
+ "label" => "Course 123",
+ "title" => "Test Course",
+ "type" => [
+ "course_offering"
+ ]
+ ],
+ "https://purl.imsglobal.org/spec/lti/claim/tool_platform" => [
+ "name" => "Mock Canvas",
+ "contact_email" => "",
+ "description" => "",
+ "url" => "",
+ "product_family_code" => "",
+ "version" => "1.0",
+ "guid" => 1176
+ ],
+ "https://purl.imsglobal.org/spec/lti-ags/claim/endpoint" => [
+ "scope" => [
+ "https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
+ "https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly",
+ "https://purl.imsglobal.org/spec/lti-ags/scope/score"
+ ],
+ "lineitems" => "https://lti-ri.imsglobal.org/platforms/1176/contexts/10045/line_items"
+ ],
+ "https://purl.imsglobal.org/spec/lti-nrps/claim/namesroleservice" => [
+ "context_memberships_url" => "https://lti-ri.imsglobal.org/platforms/1176/contexts/10045/memberships",
+ "service_versions" => [
+ "2.0"
+ ]
+ ],
+ "iss" => "https://docker-canvas.instructure.com",
+ "aud" => "10000000000013",
+ "iat" => time(),
+ "exp" => time() + (60 * 5), //expires in 5 minutes
+ "nonce" => "04aee25a09294ce3b94f532f90c755d21caf6c5e131e11eba5cd0242ac120005",
+ "https://purl.imsglobal.org/spec/lti/claim/version" => "1.3.0",
+ "locale" => "en-US",
+ "https://purl.imsglobal.org/spec/lti/claim/custom" => [
+ "canvas_course_id" => "1000",
+ "term_name" => "Default Term",
+ "account_name" => "Some Account"
+ ],
+ "https://purl.imsglobal.org/spec/lti/claim/deployment_id" => "10000:10000000000013",
+ "https://purl.imsglobal.org/spec/lti/claim/target_link_uri" => "https://localhost/lti/launch/"
+ );
+
+
+ $this->base_instructor_data = array(
+ "given_name" => "Millie",
+ "family_name" => "Robel",
+ "middle_name" => "Cummerata",
+ "email" => "Millie.Robel@example.org",
+ "name" => "Millie Cummerata Robel",
+ "sub" => "instructor_lti_user_id",
+ "https://purl.imsglobal.org/spec/lti/claim/roles" => [
+ "http://purl.imsglobal.org/vocab/lis/v2/institution/person#Instructor",
+ "http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor"
+ ],
+ "https://purl.imsglobal.org/spec/lti/claim/custom" => [
+ "username" => "lti_instructor",
+ "student_number" => null
+ ],
+ );
+ $this->instructor_launch_data = array_merge_recursive($this->base_launch_data, $this->base_instructor_data);
+
+
+ $this->base_ta_data = array(
+ "given_name" => "Stevie",
+ "family_name" => "PhD",
+ "middle_name" => "Kuhn",
+ "email" => "Stevie.PhD@example.org",
+ "name" => "Stevie Kuhn PhD",
+ "sub" => "ta_lti_user_id",
+ "https://purl.imsglobal.org/spec/lti/claim/roles" => [
+ "http://purl.imsglobal.org/vocab/lis/v2/institution/person#Learner",
+ "http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor",
+ "http://purl.imsglobal.org/vocab/lis/v2/membership/Instructor#TeachingAssistant"
+ ],
+ "https://purl.imsglobal.org/spec/lti/claim/custom" => [
+ "username" => "lti_ta",
+ "student_number" => '1234567890'
+ ],
+ );
+ $this->ta_launch_data = array_merge_recursive($this->base_launch_data, $this->base_ta_data);
+
+
+ $this->base_student_data = array(
+ "given_name" => "Maricela",
+ "family_name" => "Nikolaus",
+ "middle_name" => "Windler",
+ "email" => "Maricela.Nikolaus@example.org",
+ "name" => "Maricela Windler Nikolaus",
+ "sub" => "student_lti_user_id",
+ "https://purl.imsglobal.org/spec/lti/claim/roles" => [
+ "http://purl.imsglobal.org/vocab/lis/v2/institution/person#Learner",
+ "http://purl.imsglobal.org/vocab/lis/v2/membership#Learner"
+ ],
+ "https://purl.imsglobal.org/spec/lti/claim/custom" => [
+ "username" => "lti_student",
+ "student_number" => '0987654321'
+ ],
+ );
+ $this->student_launch_data = array_merge_recursive($this->base_launch_data, $this->base_student_data);
+
+ $this->platform_private_key = '-----BEGIN RSA PRIVATE KEY-----
+MIIJKAIBAAKCAgEAyDQ0JyGesS6gWeO3W0QqlzN0+6ODsbQ86wVvqAsloeSuKYWw
+lvqjuCqrSJMMpRjaT7wDri8Xq2SGLMq9Yi1k9tXExIKqyIgZ8NROybHRhvEXL0rM
+WR++03e7tOK/Kv+ok9crLiKeuaB+7NQWlgXqWpgMPKmk2Spa/qj4I1Xidq2MVxzV
+ub9B/FtDyYulHxg+ifNoSkmIKVP+p7a91bYSvXnF1PJQ1QxrFpr0rn7VGQ4/Jvyk
+YqRwGkJE/uXw5gAMP8JgXdlak+ntg2tljdvpp6kG9Dh3Vra9NmiehB8vPXBYtUo0
+QC/zE31BK4vLCUNEBQN5dGYDTwyjYYRkRMdWEK3S2vaoYi5FTZTpXCH0FgZr/8bZ
+ygq7CaF9o11QHvUA3vjoAUpMf3KAyeDXIhmnpGbg4BcIHeFsgcua64NNXHPCsmXG
+DgjG6Up3RT6Z0nDACTO03TXvcjkjA1WPGJpShzG/0eUN4T6u96pxKlPSQ76j083l
+Q60LOTN9d0wKVw79Xg5OuUx0uW3nQRM157TXjZVad5QZ5Okzcb3kpFhwUqGh0Ufs
+YVt3Io9+jGXN+JFhDYl+VqlTd42eOmno7Kcs9QIUPccqLQGq+tqDAZQWIGUWDdyk
+RC98tJdOOKhVHXrpz7TS2dmEAq21X+NJ62vhzZdGTRbtYG8vS/15wplk6NsCAwEA
+AQKCAgAHKoXdYAuH8w/Ooo3bHfRaUioIodXibqhUOe8WYu5svjyVBDyJwvHznc9g
+uya+OBwEXkn8Gk0XbPM34jqSK5F2xmMTLPbY/l99/9N2zmnIvJN5tWHdeiXrTYNc
+r6sWam1J0W9caOUpPCX0QIkzGIYcH7TRwmQXWTfwRUhl12VSSIGtUpJnN4HbUGxQ
+6Ac34YxyL/zBKqL4O7ycmzgYpg+YqaWxACAa6CVjJevGh91agWiK8uByyXOxH5h2
++UW8rdltD35B4w2mHWmg2nTESvqw7iYaEsquwhQWwPrqPBra8Pez5t06Q50d9aNM
+tZBwcJscL398RknYXVmccXqMqF1GY69RKYiIdHfKLwnhSBdJ1w7BiswnllBSDVZL
+STZA8dyKozSTnxsBq4PoO3cXGEYKdO+1GZy97h6ByTkaCFXZOdclBvPAyi/A4Ee/
+KSsdkUvKryyKfTgzIPXzLsDxhs0hpkI3v7PjKz9uzCvQpq9X3Cd88Gh8Z3MaW4YS
+Q4OHTTEUthCR8205uuHm0DXYCTgWv4NrLRJexG/uy7h/enLKFmAfVCT1NUgKxeIS
+3uq5yo/0McKekBN/JSYLooAomfKKFwFlc5QY9RSX/MmHxxK1X9BEXA3/c6RA37s8
+ymfCq8pKDy4/q3hyux1Tm+kiOikTm1lkPMM0y/qRTab+f3etZQKCAQEA3gxjcKzz
+hpyVUkf+sKU1a6qU3IAxmJ2a5mZO+2IOK1ihZYfPwxnjP5DyIhyoG83Fo0GULRiB
+RyaMn42hFYPM59ovKqSBPXU4rWGhWqXK80Yl+uS92z4/lfY05R7k8Sz2QcuYwf4d
+xyLpjJKEQerrXyHH5MZj6fkJv4WZ2bko/C1H07ac7zcyPx+I/MN2mY1caDVz/2Pw
+B+8m21HyVjY3HK10N5QyWdA+l36dmzfFmzagi1WkGFe/WVJ3BUhqqc5SXbKg9A8B
+L+MXekU2S7jZ1J8esRxYLUzkeH2fk9OquVubdSVQgOnyHHOTvkkHAowXSdWMKGpC
+eHYLAnlkfC55rQKCAQEA5tDCjFOljAptx6Jd5oYfaEEf9KjRajaQsHfAHG2e/UJC
+S77BSVyc+ot4lGfN5AuXCDXkOVOt0useG2KxdEHVRycKSVwuRr1y17EjYZ9M+qB3
+kbqke3JkXWVt1lVcmBGjHpEdTKSvWqvTOtl8BMW6dnXCXlorj0B6NhAmwROrT+bj
+KJNFYQ8O36o7k6NSvlWG55xc7DpLOPeMhym+1liIVwrps+9YI/IlzN+2OhIAjHJn
+tokiBV0TT8tEvjoPbaq7IwccyCttdbAge713/L0wLBFsvkDOF3/Npf8DFYAcuFH2
+d2jWZ3LiJOKOsmQO0Adv3g48imRRXKERqr2QWrTNpwKCAQEAvXwo56BPeJHqwvp5
+F1kES0qYGcqziB8GbpLj15WHrenGYRQScdWHnVkdp4p40rE4dOajghAlUghNfGKq
+EegVVc1U7rjPKRj9Msfbn7VXiV5VTtMgSRXHwTsHTHaevEi4JNGPHAy0cJkUYEcv
+4eiMzvPO1yWNYb6JWQyzi558oSYq4zo0ldauZDuO9NQAQ2zkbHEg+dHYpYypxgMa
+IAPH6AsE3+DxTr9sim8cI7bmRFvLiNueWr+WpKzAsJtpmlpc42RqAZtEUg8im86w
+VNH74Xuf/1fGz3GMjl31bXr1d5P7B26+UiRR3YGrlHhRKRVPUkyPfHWhH5bsMkJR
+Q7+NSQKCAQBy42SDDruvOh2sqeANd6M4dHoggMtEEAbzH5grTlE+BHYVV8zD5Gpq
+t3N8gzLTmQVDW/fOpR03iDqDLRvhH0e20/Ll0xFhurjoLc7Lr8xUT/1UN0/Z9nWI
+m40Ri4m8U8Ma2uZ3mN2Dx1UrzMdTZMxMXI80AbP+6Pwr3tw7bLvv2KAnOS7mgeVI
+ZWakNT5haRbuQEFsgBOjNmzndlr8PDMZCGCNZMw9kDFKiewdeYp2XhfLnvSlMNAE
+/sun2CSH1NyzMb4c0Kj6VIHGted8kPriZIX5KS6sObw2LPnvAMbK5FlG1JMsCN4R
+uAeJOg65c4o2QGXYCNkKv02Y7CRnUemvAoIBADWUCHbCfTJf5duKsSnYBLu2RUFV
+KVtTYOPbS2kqmVcE+dyCFBcBNKgnA28BJf6tbhSe1+M0+6aQQLj6gG//GTNVV093
+B1BVWdrmCX1hf0JmYGfxIkwkgf0e8IcKBKnLOniLtbnWh4O6Cw0PwjF9Wl/W0EL6
+r3uNVCiJIY40Exk7duBvJcuxFARVQHflNPfgI2rvAgF7Fb5GVF65DdydXOz7R4rD
+g82scjMwgLlmPlM17DIbyJEx0bLkqGHue+HUdEEuGkjy/js0jZts3a2ihOXA+mwq
+O+Izt6vChLopGp2MMeJALA12JdUtQa8hmF7GlSWHun5fOAVhcJiSkUNjqM0=
+-----END RSA PRIVATE KEY-----';
+
+ $this->platform_public_key = '-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyDQ0JyGesS6gWeO3W0Qq
+lzN0+6ODsbQ86wVvqAsloeSuKYWwlvqjuCqrSJMMpRjaT7wDri8Xq2SGLMq9Yi1k
+9tXExIKqyIgZ8NROybHRhvEXL0rMWR++03e7tOK/Kv+ok9crLiKeuaB+7NQWlgXq
+WpgMPKmk2Spa/qj4I1Xidq2MVxzVub9B/FtDyYulHxg+ifNoSkmIKVP+p7a91bYS
+vXnF1PJQ1QxrFpr0rn7VGQ4/JvykYqRwGkJE/uXw5gAMP8JgXdlak+ntg2tljdvp
+p6kG9Dh3Vra9NmiehB8vPXBYtUo0QC/zE31BK4vLCUNEBQN5dGYDTwyjYYRkRMdW
+EK3S2vaoYi5FTZTpXCH0FgZr/8bZygq7CaF9o11QHvUA3vjoAUpMf3KAyeDXIhmn
+pGbg4BcIHeFsgcua64NNXHPCsmXGDgjG6Up3RT6Z0nDACTO03TXvcjkjA1WPGJpS
+hzG/0eUN4T6u96pxKlPSQ76j083lQ60LOTN9d0wKVw79Xg5OuUx0uW3nQRM157TX
+jZVad5QZ5Okzcb3kpFhwUqGh0UfsYVt3Io9+jGXN+JFhDYl+VqlTd42eOmno7Kcs
+9QIUPccqLQGq+tqDAZQWIGUWDdykRC98tJdOOKhVHXrpz7TS2dmEAq21X+NJ62vh
+zZdGTRbtYG8vS/15wplk6NsCAwEAAQ==
+-----END PUBLIC KEY-----';
+
+ $this->platform_kid = 'ymMKtYy2-TPvxW1EWO6DKxoDO_SW8QGyNTjBo2WG2EM';
+
+ $this->LtiToolRegistration = ClassRegistry::init('LtiToolRegistration');
+ $this->LtiNonce = ClassRegistry::init('LtiNonce');
+ $this->LtiContext = ClassRegistry::init('LtiContext');
+ $this->LtiResourceLink = ClassRegistry::init('LtiResourceLink');
+ $this->LtiUser = ClassRegistry::init('LtiUser');
+ $this->Role = ClassRegistry::init('Role');
+ $this->User = ClassRegistry::init('User');
+ $this->Course = ClassRegistry::init('Course');
+ $this->Faculty = ClassRegistry::init('Faculty');
+
+ $this->registration_count = $this->LtiToolRegistration->find('count');
+ $this->lti_context_count = $this->LtiContext->find('count');
+ $this->lti_resource_link_count = $this->LtiResourceLink->find('count');
+ $this->lti_user_count = $this->LtiUser->find('count');
+ $this->user_count = $this->User->find('count');
+ $this->course_count = $this->Course->find('count');
+ $this->faculty_count = $this->Faculty->find('count');
+ }
+
+ public function endTest($method)
+ {
+ // defer logout to end of the test as some of the test need check flash
+ // message. After logging out, message is destoryed.
+ if (isset($this->controller->Auth)) {
+ $this->controller->Auth->logout();
+ }
+ unset($this->controller);
+
+ unset($_COOKIE['lti1p3_mocked_state']);
+ unset($_POST['state']);
+ unset($_POST['id_token']);
+
+ unset($_REQUEST['iss']);
+ unset($_REQUEST['login_hint']);
+ unset($_REQUEST['target_link_uri']);
+ unset($_REQUEST['lti_message_hint']);
+ unset($_REQUEST['lti_deployment_id']);
+ unset($_REQUEST['client_id']);
+ ClassRegistry::flush();
+ }
+
+ public function getController()
+ {
+ return $this->controller;
+ }
+
+ function resetLaunchNonce() {
+ $this->LtiNonce->save(array(
+ 'LtiNonce' => array(
+ 'nonce' => $this->base_launch_data['nonce'],
+ )
+ ));
+ }
+
+ function gerenateJWK($payload) {
+ return JWT::encode($payload, $this->platform_private_key, 'RS256', $this->platform_kid);
+ }
+
+ function gerenateInvalidSignatureJWK($payload) {
+ $invalid_private_key = str_replace('a', 'b', $this->platform_private_key);
+ return JWT::encode($payload, $invalid_private_key, 'RS256', $this->platform_kid);
+ }
+
+ function gerenateInvalidKidJWK($payload) {
+ return JWT::encode($payload, $this->platform_private_key, 'RS256', $this->platform_kid."invalid");
+ }
+
+ function setupLoginData($data) {
+ unset($_REQUEST['iss']);
+ unset($_REQUEST['login_hint']);
+ unset($_REQUEST['target_link_uri']);
+ unset($_REQUEST['lti_message_hint']);
+ unset($_REQUEST['lti_deployment_id']);
+ unset($_REQUEST['client_id']);
+ if (!empty($data['iss'])) {
+ $_REQUEST['iss'] = $data['iss'];
+ }
+ if (!empty($data['login_hint'])) {
+ $_REQUEST['login_hint'] = $data['login_hint'];
+ }
+ if (!empty($data['target_link_uri'])) {
+ $_REQUEST['target_link_uri'] = $data['target_link_uri'];
+ }
+ if (!empty($data['lti_message_hint'])) {
+ $_REQUEST['lti_message_hint'] = $data['lti_message_hint'];
+ }
+ if (!empty($data['lti_deployment_id'])) {
+ $_REQUEST['lti_deployment_id'] = $data['lti_deployment_id'];
+ }
+ if (!empty($data['client_id'])) {
+ $_REQUEST['client_id'] = $data['client_id'];
+ }
+ }
+
+ function setupLaunchData($data) {
+ unset($_POST['state']);
+ unset($_POST['id_token']);
+ if (!empty($data['state'])) {
+ $_POST['state'] = $data['state'];
+ }
+ if (!empty($data['id_token'])) {
+ $_POST['id_token'] = $data['id_token'];
+ }
+ }
+
+
+ function testLogin() {
+ // NOTE: its to hard to extract the redirect url and since there are random elements, just going to check *
+ $this->controller->expectOnce('redirect', array('*'));
+ //http://mock_lti.com/api/lti/authorize_redirect?scope=openid&response_type=id_token&response_mode=form_post&prompt=none&client_id=10000000000013&redirect_uri=%2Flti%2Flaunch&state=state-*&nonce=nonce-*&login_hint=135745<i_message_hint=19481
+
+ $this->setupLoginData($this->login_data);
+ $this->testAction(
+ '/lti/login',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertNull($message);
+ }
+
+ function testLoginFailedMissingRequiredParams() {
+ $requiredParams = array(
+ 'iss' => 'Error doing OIDC login: Could not find issuer',
+ 'login_hint' => 'Error doing OIDC login: Could not find login hint',
+ );
+
+ $count = 0;
+ foreach($requiredParams as $requiredParam => $expectedMessage) {
+ $data_copy = $this->login_data;
+ unset($data_copy[$requiredParam]);
+
+ $this->controller->expectCallCount('redirect', ++$count);
+ $this->controller->expectArgumentsAt($count-1, 'redirect', array('/home/index'));
+ $this->setupLoginData($data_copy);
+ $this->testAction(
+ '/lti/login',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], $expectedMessage);
+ }
+ }
+
+ function testLoginSuccessMissingOptionalParams() {
+ $optionalParams = array(
+ 'lti_deployment_id',
+ 'client_id',
+ 'lti_message_hint',
+ 'target_link_uri'
+ );
+
+ $count = 0;
+ foreach($optionalParams as $optionalParam) {
+ $data_copy = $this->login_data;
+ unset($data_copy[$optionalParam]);
+
+ $this->controller->expectCallCount('redirect', ++$count);
+ $this->controller->expectArgumentsAt($count-1, 'redirect', array('*'));
+ $this->setupLoginData($data_copy);
+ $this->testAction(
+ '/lti/login',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertNull($message);
+ }
+ }
+
+ function testInstructorLaunch() {
+ $_COOKIE['lti1p3_mocked_state'] = 'mocked_state';
+ $data = array(
+ 'state' => 'mocked_state',
+ 'id_token' => $this->gerenateJWK($this->instructor_launch_data),
+ );
+
+ //-- TEST 1: Completely new launch
+ $this->resetLaunchNonce();
+ $this->controller->expectOnce('redirect', array('/courses/home/5'));
+ $this->setupLaunchData($data);
+ $this->testAction(
+ '/lti/launch',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'LTI launch success');
+
+ $this->assertEqual($this->registration_count, $this->LtiToolRegistration->find('count'));
+ $this->assertEqual(++$this->lti_context_count, $this->LtiContext->find('count'));
+ $this->assertEqual(++$this->lti_resource_link_count, $this->LtiResourceLink->find('count'));
+ $this->assertEqual(++$this->lti_user_count, $this->LtiUser->find('count'));
+ $this->assertEqual(++$this->user_count, $this->User->find('count'));
+ $this->assertEqual(++$this->course_count, $this->Course->find('count'));
+ $this->assertEqual(++$this->faculty_count, $this->Faculty->find('count'));
+
+ // check faculty
+ $faculties = $this->Faculty->find('all');
+ $faculty = end($faculties)['Faculty'];
+ $this->assertEqual($faculty['name'], 'Some Account');
+
+ // check course
+ $courses = $this->Course->find('all');
+ $course = end($courses)['Course'];
+ $this->assertEqual($course['course'], 'Course 123');
+ $this->assertEqual($course['title'], 'Test Course');
+ $this->assertNull($course['homepage']);
+ $this->assertEqual($course['self_enroll'], 'off');
+ $this->assertNull($course['password']);
+ $this->assertEqual($course['record_status'], 'A');
+ $this->assertEqual($course['canvas_id'], '1000');
+ $this->assertEqual($course['term'], 'Default Term');
+
+ // check user
+ $users = $this->User->find('all');
+ $user = end($users)['User'];
+ $this->assertEqual($user['username'], 'lti_instructor');
+ $this->assertNotNull($user['password']);
+ $this->assertEqual($user['first_name'], 'Millie');
+ $this->assertEqual($user['last_name'], 'Robel');
+ $this->assertNull($user['student_no']);
+ $this->assertEqual($user['title'], '');
+ $this->assertEqual($user['email'], 'Millie.Robel@example.org');
+ $this->assertEqual($user['record_status'], 'A');
+
+ // check user role
+ $roles = $this->Role->find('all', array(
+ 'conditions' => array('User.id' => $user['id']),
+ 'recursive' => 0
+ ));
+ $role_ids = Set::extract('/Role/id', $roles);
+ $this->assertEqual($role_ids, array($this->User->USER_TYPE_INSTRUCTOR));
+
+ // check user enrollment
+ $student_enrollment_course_ids = $this->User->getEnrolledCourses($user['id']);
+ $ta_enrollment_course_ids = $this->User->getTutorCourses($user['id']);
+ $instructor_enrollment_course_ids = $this->User->getInstructorCourses($user['id']);
+ $this->assertEqual($student_enrollment_course_ids, array());
+ $this->assertEqual($ta_enrollment_course_ids, array());
+ $this->assertEqual($instructor_enrollment_course_ids, array($course['id']));
+
+ // check lti context
+ $lti_contexts = $this->LtiContext->find('all');
+ $lti_context = end($lti_contexts)['LtiContext'];
+ $this->assertEqual($lti_context['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_context['context_id'], '10045');
+ $this->assertEqual($lti_context['course_id'], $course['id']);
+ $this->assertEqual($lti_context['nrps_context_memberships_url'], 'https://lti-ri.imsglobal.org/platforms/1176/contexts/10045/memberships');
+
+ // check lti resource link
+ $lti_resource_links = $this->LtiResourceLink->find('all');
+ $lti_resource_link = end($lti_resource_links)['LtiResourceLink'];
+ $this->assertEqual($lti_resource_link['lti_context_id'], $lti_context['id']);
+ $this->assertEqual($lti_resource_link['resource_link_id'], '19481');
+ $this->assertNull($lti_resource_link['event_id']);
+ $this->assertEqual($lti_resource_link['lineitems_url'], 'https://lti-ri.imsglobal.org/platforms/1176/contexts/10045/line_items');
+ $this->assertNull($lti_resource_link['lineitem_url']);
+ $this->assertEqual($lti_resource_link['scope_lineitem'], 1);
+ $this->assertEqual($lti_resource_link['scope_lineitem_read_only'], 0);
+ $this->assertEqual($lti_resource_link['scope_result_readonly'], 1);
+ $this->assertEqual($lti_resource_link['scope_result_score'], 1);
+
+ // check lti user
+ $lti_users = $this->LtiUser->find('all');
+ $lti_user = end($lti_users)['LtiUser'];
+ $this->assertEqual($lti_user['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_user['lti_user_id'], 'instructor_lti_user_id');
+ $this->assertEqual($lti_user['ipeer_user_id'], $user['id']);
+
+ //-- TEST 2: Second launch with zero changes
+ $this->resetLaunchNonce();
+ $this->controller->expectCallCount('redirect', 2);
+ $this->controller->expectArgumentsAt(1, 'redirect', array('/courses/home/5'));
+ $this->setupLaunchData($data);
+ $this->testAction(
+ '/lti/launch',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'LTI launch success');
+
+ $this->assertEqual($this->registration_count, $this->LtiToolRegistration->find('count'));
+ $this->assertEqual($this->lti_context_count, $this->LtiContext->find('count'));
+ $this->assertEqual($this->lti_resource_link_count, $this->LtiResourceLink->find('count'));
+ $this->assertEqual($this->lti_user_count, $this->LtiUser->find('count'));
+ $this->assertEqual($this->user_count, $this->User->find('count'));
+ $this->assertEqual($this->course_count, $this->Course->find('count'));
+ $this->assertEqual($this->faculty_count, $this->Faculty->find('count'));
+
+
+ // check faculty
+ $faculties = $this->Faculty->find('all');
+ $faculty = end($faculties)['Faculty'];
+ $this->assertEqual($faculty['name'], 'Some Account');
+
+ // check course
+ $courses = $this->Course->find('all');
+ $course = end($courses)['Course'];
+ $this->assertEqual($course['course'], 'Course 123');
+ $this->assertEqual($course['title'], 'Test Course');
+ $this->assertNull($course['homepage']);
+ $this->assertEqual($course['self_enroll'], 'off');
+ $this->assertNull($course['password']);
+ $this->assertEqual($course['record_status'], 'A');
+ $this->assertEqual($course['canvas_id'], '1000');
+ $this->assertEqual($course['term'], 'Default Term');
+
+ // check user
+ $users = $this->User->find('all');
+ $user = end($users)['User'];
+ $this->assertEqual($user['username'], 'lti_instructor');
+ $this->assertNotNull($user['password']);
+ $this->assertEqual($user['first_name'], 'Millie');
+ $this->assertEqual($user['last_name'], 'Robel');
+ $this->assertNull($user['student_no']);
+ $this->assertEqual($user['title'], '');
+ $this->assertEqual($user['email'], 'Millie.Robel@example.org');
+ $this->assertEqual($user['record_status'], 'A');
+
+ // check user role
+ $roles = $this->Role->find('all', array(
+ 'conditions' => array('User.id' => $user['id']),
+ 'recursive' => 0
+ ));
+ $role_ids = Set::extract('/Role/id', $roles);
+ $this->assertEqual($role_ids, array($this->User->USER_TYPE_INSTRUCTOR));
+
+ // check user enrollment
+ $student_enrollment_course_ids = $this->User->getEnrolledCourses($user['id']);
+ $ta_enrollment_course_ids = $this->User->getTutorCourses($user['id']);
+ $instructor_enrollment_course_ids = $this->User->getInstructorCourses($user['id']);
+ $this->assertEqual($student_enrollment_course_ids, array());
+ $this->assertEqual($ta_enrollment_course_ids, array());
+ $this->assertEqual($instructor_enrollment_course_ids, array($course['id']));
+
+ // check lti context
+ $lti_contexts = $this->LtiContext->find('all');
+ $lti_context = end($lti_contexts)['LtiContext'];
+ $this->assertEqual($lti_context['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_context['context_id'], '10045');
+ $this->assertEqual($lti_context['course_id'], $course['id']);
+ $this->assertEqual($lti_context['nrps_context_memberships_url'], 'https://lti-ri.imsglobal.org/platforms/1176/contexts/10045/memberships');
+
+ // check lti resource link
+ $lti_resource_links = $this->LtiResourceLink->find('all');
+ $lti_resource_link = end($lti_resource_links)['LtiResourceLink'];
+ $this->assertEqual($lti_resource_link['lti_context_id'], $lti_context['id']);
+ $this->assertEqual($lti_resource_link['resource_link_id'], '19481');
+ $this->assertNull($lti_resource_link['event_id']);
+ $this->assertEqual($lti_resource_link['lineitems_url'], 'https://lti-ri.imsglobal.org/platforms/1176/contexts/10045/line_items');
+ $this->assertNull($lti_resource_link['lineitem_url']);
+ $this->assertEqual($lti_resource_link['scope_lineitem'], 1);
+ $this->assertEqual($lti_resource_link['scope_lineitem_read_only'], 0);
+ $this->assertEqual($lti_resource_link['scope_result_readonly'], 1);
+ $this->assertEqual($lti_resource_link['scope_result_score'], 1);
+
+ // check lti user
+ $lti_users = $this->LtiUser->find('all');
+ $lti_user = end($lti_users)['LtiUser'];
+ $this->assertEqual($lti_user['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_user['lti_user_id'], 'instructor_lti_user_id');
+ $this->assertEqual($lti_user['ipeer_user_id'], $user['id']);
+
+
+ //-- TEST 3: Third launch with many changes (course and user)
+ $this->instructor_launch_data = array_replace($this->instructor_launch_data, array(
+ // user data
+ "given_name" => "MillieAAA",
+ "family_name" => "RobelBBB",
+ "middle_name" => "CummerataCCC",
+ "email" => "MillieAAA.RobelBBB@example.org",
+ "name" => "MillieAAA CummerataCCC RobelBBB",
+ "https://purl.imsglobal.org/spec/lti/claim/roles" => [
+ "http://purl.imsglobal.org/vocab/lis/v2/institution/person#Learner",
+ "http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor",
+ "http://purl.imsglobal.org/vocab/lis/v2/membership/Instructor#TeachingAssistant"
+ ],
+ "https://purl.imsglobal.org/spec/lti/claim/custom" => [
+ "username" => "lti_instructor",
+ "student_number" => '123454321',
+ //course
+ "canvas_course_id" => "1010",
+ "term_name" => "Default Term 2",
+ "account_name" => "Some Other Account"
+ ],
+ // course
+ "https://purl.imsglobal.org/spec/lti/claim/context" => [
+ "id" => "10045",
+ "label" => "Course 456", //doesn't change in ipeer if changes in LMS
+ "title" => "Test Course 2",
+ "type" => [
+ "course_offering"
+ ]
+ ],
+ "https://purl.imsglobal.org/spec/lti-ags/claim/endpoint" => [
+ "scope" => [
+ "https://purl.imsglobal.org/spec/lti-ags/scope/lineitem.readonly"
+ ],
+ "lineitems" => "https://some_other_url.com",
+ "lineitem" => "https://some_other_url2.com",
+ ],
+ "https://purl.imsglobal.org/spec/lti-nrps/claim/namesroleservice" => [
+ "context_memberships_url" => "https://some_other_url3.com",
+ "service_versions" => [
+ "2.0"
+ ]
+ ],
+ ));
+ $data['id_token'] = $this->gerenateJWK($this->instructor_launch_data);
+ $this->resetLaunchNonce();
+ $this->controller->expectCallCount('redirect', 3);
+ $this->controller->expectArgumentsAt(2, 'redirect', array('/courses/home/5'));
+ $this->setupLaunchData($data);
+ $this->testAction(
+ '/lti/launch',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'LTI launch success');
+
+ $this->assertEqual($this->registration_count, $this->LtiToolRegistration->find('count'));
+ $this->assertEqual($this->lti_context_count, $this->LtiContext->find('count'));
+ $this->assertEqual($this->lti_resource_link_count, $this->LtiResourceLink->find('count'));
+ $this->assertEqual($this->lti_user_count, $this->LtiUser->find('count'));
+ $this->assertEqual($this->user_count, $this->User->find('count'));
+ $this->assertEqual($this->course_count, $this->Course->find('count'));
+ $this->assertEqual(++$this->faculty_count, $this->Faculty->find('count'));
+
+
+ // check faculty
+ $faculties = $this->Faculty->find('all');
+ $faculty = end($faculties)['Faculty'];
+ $this->assertEqual($faculty['name'], 'Some Other Account');
+
+ // check course
+ $courses = $this->Course->find('all');
+ $course = end($courses)['Course'];
+ $this->assertEqual($course['course'], 'Course 123');
+ $this->assertEqual($course['title'], 'Test Course 2');
+ $this->assertNull($course['homepage']);
+ $this->assertEqual($course['self_enroll'], 'off');
+ $this->assertNull($course['password']);
+ $this->assertEqual($course['record_status'], 'A');
+ $this->assertEqual($course['canvas_id'], '1010');
+ $this->assertEqual($course['term'], 'Default Term 2');
+
+ // check user
+ $users = $this->User->find('all');
+ $user = end($users)['User'];
+ $this->assertEqual($user['username'], 'lti_instructor');
+ $this->assertNotNull($user['password']);
+ $this->assertEqual($user['first_name'], 'MillieAAA');
+ $this->assertEqual($user['last_name'], 'RobelBBB');
+ $this->assertEqual($user['student_no'], '123454321');
+ $this->assertEqual($user['title'], '');
+ $this->assertEqual($user['email'], 'MillieAAA.RobelBBB@example.org');
+ $this->assertEqual($user['record_status'], 'A');
+
+ // check user role
+ $roles = $this->Role->find('all', array(
+ 'conditions' => array('User.id' => $user['id']),
+ 'recursive' => 0
+ ));
+ $role_ids = Set::extract('/Role/id', $roles);
+ $this->assertEqual($role_ids, array($this->User->USER_TYPE_INSTRUCTOR, $this->User->USER_TYPE_TA));
+
+ // check user enrollment
+ $student_enrollment_course_ids = $this->User->getEnrolledCourses($user['id']);
+ $ta_enrollment_course_ids = $this->User->getTutorCourses($user['id']);
+ $instructor_enrollment_course_ids = $this->User->getInstructorCourses($user['id']);
+ $this->assertEqual($student_enrollment_course_ids, array());
+ $this->assertEqual($ta_enrollment_course_ids, array($course['id']));
+ $this->assertEqual($instructor_enrollment_course_ids, array());
+
+ // check lti context
+ $lti_contexts = $this->LtiContext->find('all');
+ $lti_context = end($lti_contexts)['LtiContext'];
+ $this->assertEqual($lti_context['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_context['context_id'], '10045');
+ $this->assertEqual($lti_context['course_id'], $course['id']);
+ $this->assertEqual($lti_context['nrps_context_memberships_url'], 'https://some_other_url3.com');
+
+ // check lti resource link
+ $lti_resource_links = $this->LtiResourceLink->find('all');
+ $lti_resource_link = end($lti_resource_links)['LtiResourceLink'];
+ $this->assertEqual($lti_resource_link['lti_context_id'], $lti_context['id']);
+ $this->assertEqual($lti_resource_link['resource_link_id'], '19481');
+ $this->assertNull($lti_resource_link['event_id']);
+ $this->assertEqual($lti_resource_link['lineitems_url'], 'https://some_other_url.com');
+ $this->assertEqual($lti_resource_link['lineitem_url'], 'https://some_other_url2.com');
+ $this->assertEqual($lti_resource_link['scope_lineitem'], 0);
+ $this->assertEqual($lti_resource_link['scope_lineitem_read_only'], 1);
+ $this->assertEqual($lti_resource_link['scope_result_readonly'], 0);
+ $this->assertEqual($lti_resource_link['scope_result_score'], 0);
+
+ // check lti user
+ $lti_users = $this->LtiUser->find('all');
+ $lti_user = end($lti_users)['LtiUser'];
+ $this->assertEqual($lti_user['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_user['lti_user_id'], 'instructor_lti_user_id');
+ $this->assertEqual($lti_user['ipeer_user_id'], $user['id']);
+ }
+
+
+ function testTaLaunch() {
+ $_COOKIE['lti1p3_mocked_state'] = 'mocked_state';
+ $data = array(
+ 'state' => 'mocked_state',
+ 'id_token' => $this->gerenateJWK($this->ta_launch_data),
+ );
+
+ //-- TEST 1: Completely new launch
+ $this->resetLaunchNonce();
+ $this->controller->expectOnce('redirect', array('/courses/home/5'));
+ $this->setupLaunchData($data);
+ $this->testAction(
+ '/lti/launch',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'LTI launch success');
+
+ $this->assertEqual($this->registration_count, $this->LtiToolRegistration->find('count'));
+ $this->assertEqual(++$this->lti_context_count, $this->LtiContext->find('count'));
+ $this->assertEqual(++$this->lti_resource_link_count, $this->LtiResourceLink->find('count'));
+ $this->assertEqual(++$this->lti_user_count, $this->LtiUser->find('count'));
+ $this->assertEqual(++$this->user_count, $this->User->find('count'));
+ $this->assertEqual(++$this->course_count, $this->Course->find('count'));
+ $this->assertEqual(++$this->faculty_count, $this->Faculty->find('count'));
+
+ // check faculty
+ $faculties = $this->Faculty->find('all');
+ $faculty = end($faculties)['Faculty'];
+ $this->assertEqual($faculty['name'], 'Some Account');
+
+ // check course
+ $courses = $this->Course->find('all');
+ $course = end($courses)['Course'];
+ $this->assertEqual($course['course'], 'Course 123');
+ $this->assertEqual($course['title'], 'Test Course');
+ $this->assertNull($course['homepage']);
+ $this->assertEqual($course['self_enroll'], 'off');
+ $this->assertNull($course['password']);
+ $this->assertEqual($course['record_status'], 'A');
+ $this->assertEqual($course['canvas_id'], '1000');
+ $this->assertEqual($course['term'], 'Default Term');
+
+ // check user
+ $users = $this->User->find('all');
+ $user = end($users)['User'];
+ $this->assertEqual($user['username'], 'lti_ta');
+ $this->assertNotNull($user['password']);
+ $this->assertEqual($user['first_name'], 'Stevie');
+ $this->assertEqual($user['last_name'], 'PhD');
+ $this->assertEqual($user['student_no'], '1234567890');
+ $this->assertEqual($user['title'], '');
+ $this->assertEqual($user['email'], 'Stevie.PhD@example.org');
+ $this->assertEqual($user['record_status'], 'A');
+
+ // check user role
+ $roles = $this->Role->find('all', array(
+ 'conditions' => array('User.id' => $user['id']),
+ 'recursive' => 0
+ ));
+ $role_ids = Set::extract('/Role/id', $roles);
+ $this->assertEqual($role_ids, array($this->User->USER_TYPE_TA));
+
+ // check user enrollment
+ $student_enrollment_course_ids = $this->User->getEnrolledCourses($user['id']);
+ $ta_enrollment_course_ids = $this->User->getTutorCourses($user['id']);
+ $instructor_enrollment_course_ids = $this->User->getInstructorCourses($user['id']);
+ $this->assertEqual($student_enrollment_course_ids, array());
+ $this->assertEqual($ta_enrollment_course_ids, array($course['id']));
+ $this->assertEqual($instructor_enrollment_course_ids, array());
+
+ // check lti context
+ $lti_contexts = $this->LtiContext->find('all');
+ $lti_context = end($lti_contexts)['LtiContext'];
+ $this->assertEqual($lti_context['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_context['context_id'], '10045');
+ $this->assertEqual($lti_context['course_id'], $course['id']);
+ $this->assertEqual($lti_context['nrps_context_memberships_url'], 'https://lti-ri.imsglobal.org/platforms/1176/contexts/10045/memberships');
+
+ // check lti resource link
+ $lti_resource_links = $this->LtiResourceLink->find('all');
+ $lti_resource_link = end($lti_resource_links)['LtiResourceLink'];
+ $this->assertEqual($lti_resource_link['lti_context_id'], $lti_context['id']);
+ $this->assertEqual($lti_resource_link['resource_link_id'], '19481');
+ $this->assertNull($lti_resource_link['event_id']);
+ $this->assertEqual($lti_resource_link['lineitems_url'], 'https://lti-ri.imsglobal.org/platforms/1176/contexts/10045/line_items');
+ $this->assertNull($lti_resource_link['lineitem_url']);
+ $this->assertEqual($lti_resource_link['scope_lineitem'], 1);
+ $this->assertEqual($lti_resource_link['scope_lineitem_read_only'], 0);
+ $this->assertEqual($lti_resource_link['scope_result_readonly'], 1);
+ $this->assertEqual($lti_resource_link['scope_result_score'], 1);
+
+ // check lti user
+ $lti_users = $this->LtiUser->find('all');
+ $lti_user = end($lti_users)['LtiUser'];
+ $this->assertEqual($lti_user['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_user['lti_user_id'], 'ta_lti_user_id');
+ $this->assertEqual($lti_user['ipeer_user_id'], $user['id']);
+
+ //-- TEST 2: Second launch with zero changes
+ $this->resetLaunchNonce();
+ $this->controller->expectCallCount('redirect', 2);
+ $this->controller->expectArgumentsAt(1, 'redirect', array('/courses/home/5'));
+ $this->setupLaunchData($data);
+ $this->testAction(
+ '/lti/launch',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'LTI launch success');
+
+ $this->assertEqual($this->registration_count, $this->LtiToolRegistration->find('count'));
+ $this->assertEqual($this->lti_context_count, $this->LtiContext->find('count'));
+ $this->assertEqual($this->lti_resource_link_count, $this->LtiResourceLink->find('count'));
+ $this->assertEqual($this->lti_user_count, $this->LtiUser->find('count'));
+ $this->assertEqual($this->user_count, $this->User->find('count'));
+ $this->assertEqual($this->course_count, $this->Course->find('count'));
+ $this->assertEqual($this->faculty_count, $this->Faculty->find('count'));
+
+
+ // check faculty
+ $faculties = $this->Faculty->find('all');
+ $faculty = end($faculties)['Faculty'];
+ $this->assertEqual($faculty['name'], 'Some Account');
+
+ // check course
+ $courses = $this->Course->find('all');
+ $course = end($courses)['Course'];
+ $this->assertEqual($course['course'], 'Course 123');
+ $this->assertEqual($course['title'], 'Test Course');
+ $this->assertNull($course['homepage']);
+ $this->assertEqual($course['self_enroll'], 'off');
+ $this->assertNull($course['password']);
+ $this->assertEqual($course['record_status'], 'A');
+ $this->assertEqual($course['canvas_id'], '1000');
+ $this->assertEqual($course['term'], 'Default Term');
+
+ // check user
+ $users = $this->User->find('all');
+ $user = end($users)['User'];
+ $this->assertEqual($user['username'], 'lti_ta');
+ $this->assertNotNull($user['password']);
+ $this->assertEqual($user['first_name'], 'Stevie');
+ $this->assertEqual($user['last_name'], 'PhD');
+ $this->assertEqual($user['student_no'], '1234567890');
+ $this->assertEqual($user['title'], '');
+ $this->assertEqual($user['email'], 'Stevie.PhD@example.org');
+ $this->assertEqual($user['record_status'], 'A');
+
+ // check user role
+ $roles = $this->Role->find('all', array(
+ 'conditions' => array('User.id' => $user['id']),
+ 'recursive' => 0
+ ));
+ $role_ids = Set::extract('/Role/id', $roles);
+ $this->assertEqual($role_ids, array($this->User->USER_TYPE_TA));
+
+ // check user enrollment
+ $student_enrollment_course_ids = $this->User->getEnrolledCourses($user['id']);
+ $ta_enrollment_course_ids = $this->User->getTutorCourses($user['id']);
+ $instructor_enrollment_course_ids = $this->User->getInstructorCourses($user['id']);
+ $this->assertEqual($student_enrollment_course_ids, array());
+ $this->assertEqual($ta_enrollment_course_ids, array($course['id']));
+ $this->assertEqual($instructor_enrollment_course_ids, array());
+
+ // check lti context
+ $lti_contexts = $this->LtiContext->find('all');
+ $lti_context = end($lti_contexts)['LtiContext'];
+ $this->assertEqual($lti_context['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_context['context_id'], '10045');
+ $this->assertEqual($lti_context['course_id'], $course['id']);
+ $this->assertEqual($lti_context['nrps_context_memberships_url'], 'https://lti-ri.imsglobal.org/platforms/1176/contexts/10045/memberships');
+
+ // check lti resource link
+ $lti_resource_links = $this->LtiResourceLink->find('all');
+ $lti_resource_link = end($lti_resource_links)['LtiResourceLink'];
+ $this->assertEqual($lti_resource_link['lti_context_id'], $lti_context['id']);
+ $this->assertEqual($lti_resource_link['resource_link_id'], '19481');
+ $this->assertNull($lti_resource_link['event_id']);
+ $this->assertEqual($lti_resource_link['lineitems_url'], 'https://lti-ri.imsglobal.org/platforms/1176/contexts/10045/line_items');
+ $this->assertNull($lti_resource_link['lineitem_url']);
+ $this->assertEqual($lti_resource_link['scope_lineitem'], 1);
+ $this->assertEqual($lti_resource_link['scope_lineitem_read_only'], 0);
+ $this->assertEqual($lti_resource_link['scope_result_readonly'], 1);
+ $this->assertEqual($lti_resource_link['scope_result_score'], 1);
+
+ // check lti user
+ $lti_users = $this->LtiUser->find('all');
+ $lti_user = end($lti_users)['LtiUser'];
+ $this->assertEqual($lti_user['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_user['lti_user_id'], 'ta_lti_user_id');
+ $this->assertEqual($lti_user['ipeer_user_id'], $user['id']);
+
+
+ //-- TEST 3: Third launch with many changes (course and user)
+ $this->ta_launch_data = array_replace($this->ta_launch_data, array(
+ // user data
+ "given_name" => "StevieAAA",
+ "family_name" => "PhDBBB",
+ "middle_name" => "KuhnCCC",
+ "email" => "StevieAAA.PhDBBB@example.org",
+ "name" => "StevieAAA KuhnCCC PhDBBB",
+ "https://purl.imsglobal.org/spec/lti/claim/roles" => [
+ "http://purl.imsglobal.org/vocab/lis/v2/institution/person#Learner",
+ "http://purl.imsglobal.org/vocab/lis/v2/membership#Learner"
+ ],
+ "https://purl.imsglobal.org/spec/lti/claim/custom" => [
+ "username" => "lti_ta",
+ "student_number" => '543212345',
+ //course
+ "canvas_course_id" => "1010",
+ "term_name" => "Default Term 2",
+ "account_name" => "Some Other Account"
+ ],
+ // course
+ "https://purl.imsglobal.org/spec/lti/claim/context" => [
+ "id" => "10045",
+ "label" => "Course 456", //doesn't change in ipeer if changes in LMS
+ "title" => "Test Course 2",
+ "type" => [
+ "course_offering"
+ ]
+ ],
+ "https://purl.imsglobal.org/spec/lti-ags/claim/endpoint" => [
+ "scope" => [
+ "https://purl.imsglobal.org/spec/lti-ags/scope/lineitem.readonly"
+ ],
+ "lineitems" => "https://some_other_url.com",
+ "lineitem" => "https://some_other_url2.com",
+ ],
+ "https://purl.imsglobal.org/spec/lti-nrps/claim/namesroleservice" => [
+ "context_memberships_url" => "https://some_other_url3.com",
+ "service_versions" => [
+ "2.0"
+ ]
+ ],
+ ));
+ $data['id_token'] = $this->gerenateJWK($this->ta_launch_data);
+ $this->resetLaunchNonce();
+ $this->controller->expectCallCount('redirect', 3);
+ $this->controller->expectArgumentsAt(2, 'redirect', array('/home/index'));
+ $this->setupLaunchData($data);
+ $this->testAction(
+ '/lti/launch',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'LTI launch success');
+
+ $this->assertEqual($this->registration_count, $this->LtiToolRegistration->find('count'));
+ $this->assertEqual($this->lti_context_count, $this->LtiContext->find('count'));
+ $this->assertEqual($this->lti_resource_link_count, $this->LtiResourceLink->find('count'));
+ $this->assertEqual($this->lti_user_count, $this->LtiUser->find('count'));
+ $this->assertEqual($this->user_count, $this->User->find('count'));
+ $this->assertEqual($this->course_count, $this->Course->find('count'));
+ $this->assertEqual(++$this->faculty_count, $this->Faculty->find('count'));
+
+
+ // check faculty
+ $faculties = $this->Faculty->find('all');
+ $faculty = end($faculties)['Faculty'];
+ $this->assertEqual($faculty['name'], 'Some Other Account');
+
+ // check course
+ $courses = $this->Course->find('all');
+ $course = end($courses)['Course'];
+ $this->assertEqual($course['course'], 'Course 123');
+ $this->assertEqual($course['title'], 'Test Course 2');
+ $this->assertNull($course['homepage']);
+ $this->assertEqual($course['self_enroll'], 'off');
+ $this->assertNull($course['password']);
+ $this->assertEqual($course['record_status'], 'A');
+ $this->assertEqual($course['canvas_id'], '1010');
+ $this->assertEqual($course['term'], 'Default Term 2');
+
+ // check user
+ $users = $this->User->find('all');
+ $user = end($users)['User'];
+ $this->assertEqual($user['username'], 'lti_ta');
+ $this->assertNotNull($user['password']);
+ $this->assertEqual($user['first_name'], 'StevieAAA');
+ $this->assertEqual($user['last_name'], 'PhDBBB');
+ $this->assertEqual($user['student_no'], '543212345');
+ $this->assertEqual($user['title'], '');
+ $this->assertEqual($user['email'], 'StevieAAA.PhDBBB@example.org');
+ $this->assertEqual($user['record_status'], 'A');
+
+ // check user role
+ $roles = $this->Role->find('all', array(
+ 'conditions' => array('User.id' => $user['id']),
+ 'recursive' => 0
+ ));
+ $role_ids = Set::extract('/Role/id', $roles);
+ $this->assertEqual($role_ids, array($this->User->USER_TYPE_TA, $this->User->USER_TYPE_STUDENT));
+
+ // check user enrollment
+ $student_enrollment_course_ids = $this->User->getEnrolledCourses($user['id']);
+ $ta_enrollment_course_ids = $this->User->getTutorCourses($user['id']);
+ $instructor_enrollment_course_ids = $this->User->getInstructorCourses($user['id']);
+ $this->assertEqual($student_enrollment_course_ids, array($course['id']));
+ $this->assertEqual($ta_enrollment_course_ids, array());
+ $this->assertEqual($instructor_enrollment_course_ids, array());
+
+ // check lti context
+ $lti_contexts = $this->LtiContext->find('all');
+ $lti_context = end($lti_contexts)['LtiContext'];
+ $this->assertEqual($lti_context['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_context['context_id'], '10045');
+ $this->assertEqual($lti_context['course_id'], $course['id']);
+ $this->assertEqual($lti_context['nrps_context_memberships_url'], 'https://some_other_url3.com');
+
+ // check lti resource link
+ $lti_resource_links = $this->LtiResourceLink->find('all');
+ $lti_resource_link = end($lti_resource_links)['LtiResourceLink'];
+ $this->assertEqual($lti_resource_link['lti_context_id'], $lti_context['id']);
+ $this->assertEqual($lti_resource_link['resource_link_id'], '19481');
+ $this->assertNull($lti_resource_link['event_id']);
+ $this->assertEqual($lti_resource_link['lineitems_url'], 'https://some_other_url.com');
+ $this->assertEqual($lti_resource_link['lineitem_url'], 'https://some_other_url2.com');
+ $this->assertEqual($lti_resource_link['scope_lineitem'], 0);
+ $this->assertEqual($lti_resource_link['scope_lineitem_read_only'], 1);
+ $this->assertEqual($lti_resource_link['scope_result_readonly'], 0);
+ $this->assertEqual($lti_resource_link['scope_result_score'], 0);
+
+ // check lti user
+ $lti_users = $this->LtiUser->find('all');
+ $lti_user = end($lti_users)['LtiUser'];
+ $this->assertEqual($lti_user['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_user['lti_user_id'], 'ta_lti_user_id');
+ $this->assertEqual($lti_user['ipeer_user_id'], $user['id']);
+ }
+
+ function testStudentLaunch() {
+ $_COOKIE['lti1p3_mocked_state'] = 'mocked_state';
+ $data = array(
+ 'state' => 'mocked_state',
+ 'id_token' => $this->gerenateJWK($this->student_launch_data),
+ );
+
+ //-- TEST 1: Completely new launch
+ $this->resetLaunchNonce();
+ $this->controller->expectOnce('redirect', array('/home/index'));
+ $this->setupLaunchData($data);
+ $this->testAction(
+ '/lti/launch',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'LTI launch success');
+
+ $this->assertEqual($this->registration_count, $this->LtiToolRegistration->find('count'));
+ $this->assertEqual(++$this->lti_context_count, $this->LtiContext->find('count'));
+ $this->assertEqual(++$this->lti_resource_link_count, $this->LtiResourceLink->find('count'));
+ $this->assertEqual(++$this->lti_user_count, $this->LtiUser->find('count'));
+ $this->assertEqual(++$this->user_count, $this->User->find('count'));
+ $this->assertEqual(++$this->course_count, $this->Course->find('count'));
+ $this->assertEqual(++$this->faculty_count, $this->Faculty->find('count'));
+
+ // check faculty
+ $faculties = $this->Faculty->find('all');
+ $faculty = end($faculties)['Faculty'];
+ $this->assertEqual($faculty['name'], 'Some Account');
+
+ // check course
+ $courses = $this->Course->find('all');
+ $course = end($courses)['Course'];
+ $this->assertEqual($course['course'], 'Course 123');
+ $this->assertEqual($course['title'], 'Test Course');
+ $this->assertNull($course['homepage']);
+ $this->assertEqual($course['self_enroll'], 'off');
+ $this->assertNull($course['password']);
+ $this->assertEqual($course['record_status'], 'A');
+ $this->assertEqual($course['canvas_id'], '1000');
+ $this->assertEqual($course['term'], 'Default Term');
+
+ // check user
+ $users = $this->User->find('all');
+ $user = end($users)['User'];
+ $this->assertEqual($user['username'], 'lti_student');
+ $this->assertNotNull($user['password']);
+ $this->assertEqual($user['first_name'], 'Maricela');
+ $this->assertEqual($user['last_name'], 'Nikolaus');
+ $this->assertEqual($user['student_no'], '0987654321');
+ $this->assertEqual($user['title'], '');
+ $this->assertEqual($user['email'], 'Maricela.Nikolaus@example.org');
+ $this->assertEqual($user['record_status'], 'A');
+
+ // check user role
+ $roles = $this->Role->find('all', array(
+ 'conditions' => array('User.id' => $user['id']),
+ 'recursive' => 0
+ ));
+ $role_ids = Set::extract('/Role/id', $roles);
+ $this->assertEqual($role_ids, array($this->User->USER_TYPE_STUDENT));
+
+ // check user enrollment
+ $student_enrollment_course_ids = $this->User->getEnrolledCourses($user['id']);
+ $ta_enrollment_course_ids = $this->User->getTutorCourses($user['id']);
+ $instructor_enrollment_course_ids = $this->User->getInstructorCourses($user['id']);
+ $this->assertEqual($student_enrollment_course_ids, array($course['id']));
+ $this->assertEqual($ta_enrollment_course_ids, array());
+ $this->assertEqual($instructor_enrollment_course_ids, array());
+
+ // check lti context
+ $lti_contexts = $this->LtiContext->find('all');
+ $lti_context = end($lti_contexts)['LtiContext'];
+ $this->assertEqual($lti_context['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_context['context_id'], '10045');
+ $this->assertEqual($lti_context['course_id'], $course['id']);
+ $this->assertEqual($lti_context['nrps_context_memberships_url'], 'https://lti-ri.imsglobal.org/platforms/1176/contexts/10045/memberships');
+
+ // check lti resource link
+ $lti_resource_links = $this->LtiResourceLink->find('all');
+ $lti_resource_link = end($lti_resource_links)['LtiResourceLink'];
+ $this->assertEqual($lti_resource_link['lti_context_id'], $lti_context['id']);
+ $this->assertEqual($lti_resource_link['resource_link_id'], '19481');
+ $this->assertNull($lti_resource_link['event_id']);
+ $this->assertEqual($lti_resource_link['lineitems_url'], 'https://lti-ri.imsglobal.org/platforms/1176/contexts/10045/line_items');
+ $this->assertNull($lti_resource_link['lineitem_url']);
+ $this->assertEqual($lti_resource_link['scope_lineitem'], 1);
+ $this->assertEqual($lti_resource_link['scope_lineitem_read_only'], 0);
+ $this->assertEqual($lti_resource_link['scope_result_readonly'], 1);
+ $this->assertEqual($lti_resource_link['scope_result_score'], 1);
+
+ // check lti user
+ $lti_users = $this->LtiUser->find('all');
+ $lti_user = end($lti_users)['LtiUser'];
+ $this->assertEqual($lti_user['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_user['lti_user_id'], 'student_lti_user_id');
+ $this->assertEqual($lti_user['ipeer_user_id'], $user['id']);
+
+ //-- TEST 2: Second launch with zero changes
+ $this->resetLaunchNonce();
+ $this->controller->expectCallCount('redirect', 2);
+ $this->controller->expectArgumentsAt(1, 'redirect', array('/home/index'));
+ $this->setupLaunchData($data);
+ $this->testAction(
+ '/lti/launch',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'LTI launch success');
+
+ $this->assertEqual($this->registration_count, $this->LtiToolRegistration->find('count'));
+ $this->assertEqual($this->lti_context_count, $this->LtiContext->find('count'));
+ $this->assertEqual($this->lti_resource_link_count, $this->LtiResourceLink->find('count'));
+ $this->assertEqual($this->lti_user_count, $this->LtiUser->find('count'));
+ $this->assertEqual($this->user_count, $this->User->find('count'));
+ $this->assertEqual($this->course_count, $this->Course->find('count'));
+ $this->assertEqual($this->faculty_count, $this->Faculty->find('count'));
+
+
+ // check faculty
+ $faculties = $this->Faculty->find('all');
+ $faculty = end($faculties)['Faculty'];
+ $this->assertEqual($faculty['name'], 'Some Account');
+
+ // check course
+ $courses = $this->Course->find('all');
+ $course = end($courses)['Course'];
+ $this->assertEqual($course['course'], 'Course 123');
+ $this->assertEqual($course['title'], 'Test Course');
+ $this->assertNull($course['homepage']);
+ $this->assertEqual($course['self_enroll'], 'off');
+ $this->assertNull($course['password']);
+ $this->assertEqual($course['record_status'], 'A');
+ $this->assertEqual($course['canvas_id'], '1000');
+ $this->assertEqual($course['term'], 'Default Term');
+
+ // check user
+ $users = $this->User->find('all');
+ $user = end($users)['User'];
+ $this->assertEqual($user['username'], 'lti_student');
+ $this->assertNotNull($user['password']);
+ $this->assertEqual($user['first_name'], 'Maricela');
+ $this->assertEqual($user['last_name'], 'Nikolaus');
+ $this->assertEqual($user['student_no'], '0987654321');
+ $this->assertEqual($user['title'], '');
+ $this->assertEqual($user['email'], 'Maricela.Nikolaus@example.org');
+ $this->assertEqual($user['record_status'], 'A');
+
+ // check user role
+ $roles = $this->Role->find('all', array(
+ 'conditions' => array('User.id' => $user['id']),
+ 'recursive' => 0
+ ));
+ $role_ids = Set::extract('/Role/id', $roles);
+ $this->assertEqual($role_ids, array($this->User->USER_TYPE_STUDENT));
+
+ // check user enrollment
+ $student_enrollment_course_ids = $this->User->getEnrolledCourses($user['id']);
+ $ta_enrollment_course_ids = $this->User->getTutorCourses($user['id']);
+ $instructor_enrollment_course_ids = $this->User->getInstructorCourses($user['id']);
+ $this->assertEqual($student_enrollment_course_ids, array($course['id']));
+ $this->assertEqual($ta_enrollment_course_ids, array());
+ $this->assertEqual($instructor_enrollment_course_ids, array());
+
+ // check lti context
+ $lti_contexts = $this->LtiContext->find('all');
+ $lti_context = end($lti_contexts)['LtiContext'];
+ $this->assertEqual($lti_context['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_context['context_id'], '10045');
+ $this->assertEqual($lti_context['course_id'], $course['id']);
+ $this->assertEqual($lti_context['nrps_context_memberships_url'], 'https://lti-ri.imsglobal.org/platforms/1176/contexts/10045/memberships');
+
+ // check lti resource link
+ $lti_resource_links = $this->LtiResourceLink->find('all');
+ $lti_resource_link = end($lti_resource_links)['LtiResourceLink'];
+ $this->assertEqual($lti_resource_link['lti_context_id'], $lti_context['id']);
+ $this->assertEqual($lti_resource_link['resource_link_id'], '19481');
+ $this->assertNull($lti_resource_link['event_id']);
+ $this->assertEqual($lti_resource_link['lineitems_url'], 'https://lti-ri.imsglobal.org/platforms/1176/contexts/10045/line_items');
+ $this->assertNull($lti_resource_link['lineitem_url']);
+ $this->assertEqual($lti_resource_link['scope_lineitem'], 1);
+ $this->assertEqual($lti_resource_link['scope_lineitem_read_only'], 0);
+ $this->assertEqual($lti_resource_link['scope_result_readonly'], 1);
+ $this->assertEqual($lti_resource_link['scope_result_score'], 1);
+
+ // check lti user
+ $lti_users = $this->LtiUser->find('all');
+ $lti_user = end($lti_users)['LtiUser'];
+ $this->assertEqual($lti_user['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_user['lti_user_id'], 'student_lti_user_id');
+ $this->assertEqual($lti_user['ipeer_user_id'], $user['id']);
+
+
+ //-- TEST 3: Third launch with many changes (course and user)
+ $this->student_launch_data = array_replace($this->student_launch_data, array(
+ // user data
+ "given_name" => "MaricelaAAA",
+ "family_name" => "NikolausBBB",
+ "middle_name" => "WindlerCCC",
+ "email" => "MaricelaAAA.NikolausBBB@example.org",
+ "name" => "MaricelaAAA WindlerCCC NikolausBBB",
+ "https://purl.imsglobal.org/spec/lti/claim/roles" => [
+ "http://purl.imsglobal.org/vocab/lis/v2/institution/person#Instructor",
+ "http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor"
+ ],
+ "https://purl.imsglobal.org/spec/lti/claim/custom" => [
+ "username" => "lti_student",
+ "student_number" => null,
+ //course
+ "canvas_course_id" => "1010",
+ "term_name" => "Default Term 2",
+ "account_name" => "Some Other Account"
+ ],
+ // course
+ "https://purl.imsglobal.org/spec/lti/claim/context" => [
+ "id" => "10045",
+ "label" => "Course 456", //doesn't change in ipeer if changes in LMS
+ "title" => "Test Course 2",
+ "type" => [
+ "course_offering"
+ ]
+ ],
+ "https://purl.imsglobal.org/spec/lti-ags/claim/endpoint" => [
+ "scope" => [
+ "https://purl.imsglobal.org/spec/lti-ags/scope/lineitem.readonly"
+ ],
+ "lineitems" => "https://some_other_url.com",
+ "lineitem" => "https://some_other_url2.com",
+ ],
+ "https://purl.imsglobal.org/spec/lti-nrps/claim/namesroleservice" => [
+ "context_memberships_url" => "https://some_other_url3.com",
+ "service_versions" => [
+ "2.0"
+ ]
+ ],
+ ));
+ $data['id_token'] = $this->gerenateJWK($this->student_launch_data);
+ $this->resetLaunchNonce();
+ $this->controller->expectCallCount('redirect', 3);
+ $this->controller->expectArgumentsAt(2, 'redirect', array('/courses/home/5'));
+ $this->setupLaunchData($data);
+ $this->testAction(
+ '/lti/launch',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'LTI launch success');
+
+ $this->assertEqual($this->registration_count, $this->LtiToolRegistration->find('count'));
+ $this->assertEqual($this->lti_context_count, $this->LtiContext->find('count'));
+ $this->assertEqual($this->lti_resource_link_count, $this->LtiResourceLink->find('count'));
+ $this->assertEqual($this->lti_user_count, $this->LtiUser->find('count'));
+ $this->assertEqual($this->user_count, $this->User->find('count'));
+ $this->assertEqual($this->course_count, $this->Course->find('count'));
+ $this->assertEqual(++$this->faculty_count, $this->Faculty->find('count'));
+
+
+ // check faculty
+ $faculties = $this->Faculty->find('all');
+ $faculty = end($faculties)['Faculty'];
+ $this->assertEqual($faculty['name'], 'Some Other Account');
+
+ // check course
+ $courses = $this->Course->find('all');
+ $course = end($courses)['Course'];
+ $this->assertEqual($course['course'], 'Course 123');
+ $this->assertEqual($course['title'], 'Test Course 2');
+ $this->assertNull($course['homepage']);
+ $this->assertEqual($course['self_enroll'], 'off');
+ $this->assertNull($course['password']);
+ $this->assertEqual($course['record_status'], 'A');
+ $this->assertEqual($course['canvas_id'], '1010');
+ $this->assertEqual($course['term'], 'Default Term 2');
+
+ // check user
+ $users = $this->User->find('all');
+ $user = end($users)['User'];
+ $this->assertEqual($user['username'], 'lti_student');
+ $this->assertNotNull($user['password']);
+ $this->assertEqual($user['first_name'], 'MaricelaAAA');
+ $this->assertEqual($user['last_name'], 'NikolausBBB');
+ $this->assertEqual($user['student_no'], '0987654321'); //values aren't changed if they are missing from launch
+ $this->assertEqual($user['title'], '');
+ $this->assertEqual($user['email'], 'MaricelaAAA.NikolausBBB@example.org');
+ $this->assertEqual($user['record_status'], 'A');
+
+ // check user role
+ $roles = $this->Role->find('all', array(
+ 'conditions' => array('User.id' => $user['id']),
+ 'recursive' => 0
+ ));
+ $role_ids = Set::extract('/Role/id', $roles);
+ $this->assertEqual($role_ids, array($this->User->USER_TYPE_STUDENT, $this->User->USER_TYPE_INSTRUCTOR));
+
+ // check user enrollment
+ $student_enrollment_course_ids = $this->User->getEnrolledCourses($user['id']);
+ $ta_enrollment_course_ids = $this->User->getTutorCourses($user['id']);
+ $instructor_enrollment_course_ids = $this->User->getInstructorCourses($user['id']);
+ $this->assertEqual($student_enrollment_course_ids, array());
+ $this->assertEqual($ta_enrollment_course_ids, array());
+ $this->assertEqual($instructor_enrollment_course_ids, array($course['id']));
+
+ // check lti context
+ $lti_contexts = $this->LtiContext->find('all');
+ $lti_context = end($lti_contexts)['LtiContext'];
+ $this->assertEqual($lti_context['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_context['context_id'], '10045');
+ $this->assertEqual($lti_context['course_id'], $course['id']);
+ $this->assertEqual($lti_context['nrps_context_memberships_url'], 'https://some_other_url3.com');
+
+ // check lti resource link
+ $lti_resource_links = $this->LtiResourceLink->find('all');
+ $lti_resource_link = end($lti_resource_links)['LtiResourceLink'];
+ $this->assertEqual($lti_resource_link['lti_context_id'], $lti_context['id']);
+ $this->assertEqual($lti_resource_link['resource_link_id'], '19481');
+ $this->assertNull($lti_resource_link['event_id']);
+ $this->assertEqual($lti_resource_link['lineitems_url'], 'https://some_other_url.com');
+ $this->assertEqual($lti_resource_link['lineitem_url'], 'https://some_other_url2.com');
+ $this->assertEqual($lti_resource_link['scope_lineitem'], 0);
+ $this->assertEqual($lti_resource_link['scope_lineitem_read_only'], 1);
+ $this->assertEqual($lti_resource_link['scope_result_readonly'], 0);
+ $this->assertEqual($lti_resource_link['scope_result_score'], 0);
+
+ // check lti user
+ $lti_users = $this->LtiUser->find('all');
+ $lti_user = end($lti_users)['LtiUser'];
+ $this->assertEqual($lti_user['lti_tool_registration_id'], 1);
+ $this->assertEqual($lti_user['lti_user_id'], 'student_lti_user_id');
+ $this->assertEqual($lti_user['ipeer_user_id'], $user['id']);
+ }
+
+
+ function testInvalidLaunch() {
+ $data = array(
+ 'state' => 'mocked_state',
+ 'id_token' => $this->gerenateJWK($this->student_launch_data),
+ );
+ $count = 0;
+
+ //-- TEST 1: Missing state Cookie
+ $this->resetLaunchNonce();
+ $this->controller->expectCallCount('redirect', ++$count);
+ $this->controller->expectArgumentsAt($count-1, 'redirect', array('/logout'));
+ $this->setupLaunchData($data);
+ $this->testAction(
+ '/lti/launch',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'State not found');
+
+
+ //-- TEST 2: miss matching states
+ $_COOKIE['lti1p3_mocked_state'] = 'incorrect_state';
+ $invalid_data = $data;
+ unset($invalid_data['state']);
+ $this->resetLaunchNonce();
+ $this->controller->expectCallCount('redirect', ++$count);
+ $this->controller->expectArgumentsAt($count-1, 'redirect', array('/logout'));
+ $this->setupLaunchData($invalid_data);
+ $this->testAction(
+ '/lti/launch',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'State not found');
+
+
+ // set valid cookie for future tests
+ $_COOKIE['lti1p3_mocked_state'] = 'mocked_state';
+
+
+ //-- TEST 3: missing state post param
+ $invalid_data = $data;
+ unset($invalid_data['state']);
+ $this->resetLaunchNonce();
+ $this->controller->expectCallCount('redirect', ++$count);
+ $this->controller->expectArgumentsAt($count-1, 'redirect', array('/logout'));
+ $this->setupLaunchData($invalid_data);
+ $this->testAction(
+ '/lti/launch',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'State not found');
+
+
+ //-- TEST 4: missing id_token post param
+ $invalid_data = $data;
+ unset($invalid_data['id_token']);
+ $this->resetLaunchNonce();
+ $this->controller->expectCallCount('redirect', ++$count);
+ $this->controller->expectArgumentsAt($count-1, 'redirect', array('/logout'));
+ $this->setupLaunchData($invalid_data);
+ $this->testAction(
+ '/lti/launch',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'Missing id_token');
+
+ // NOTE Can't test at the moment since library error is thrown
+ // Fatal error: Uncaught Error: Class 'Firebase\JWT\SignatureInvalidException' not found in /var/www/html/vendor/fproject/php-jwt/src/JWT.php on line 113
+
+ // //-- TEST 5: invalid signature
+ // $invalid_data = $data;
+ // $invalid_data['id_token'] = $this->gerenateInvalidSignatureJWK($this->student_launch_data);
+ // $this->controller->expectCallCount('redirect', ++$count);
+ // $this->controller->expectArgumentsAt($count-1, 'redirect', array('/logout'));
+ // $this->setupLaunchData($invalid_data);
+ // $this->testAction(
+ // '/lti/launch',
+ // array('fixturize' => true, 'method' => 'post')
+ // );
+ // $message = $this->controller->Session->read('Message.flash');
+ // $this->assertEqual($message['message'], 'LTI launch success');
+
+ //-- TEST 6: invalid Kid
+ $invalid_data = $data;
+ $invalid_data['id_token'] = $this->gerenateInvalidKidJWK($this->student_launch_data);
+ $this->resetLaunchNonce();
+ $this->controller->expectCallCount('redirect', ++$count);
+ $this->controller->expectArgumentsAt($count-1, 'redirect', array('/logout'));
+ $this->setupLaunchData($invalid_data);
+ $this->testAction(
+ '/lti/launch',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'Unable to find public key');
+
+
+ //-- TEST 6: invalid nonce
+ $invalid_student_data = $this->student_launch_data;
+ $invalid_student_data['nonce'] = 'some_invalid_nonce';
+ $invalid_data = array(
+ 'state' => 'mocked_state',
+ 'id_token' => $this->gerenateJWK($invalid_student_data),
+ );
+ $this->resetLaunchNonce();
+ $this->controller->expectCallCount('redirect', ++$count);
+ $this->controller->expectArgumentsAt($count-1, 'redirect', array('/logout'));
+ $this->setupLaunchData($invalid_data);
+ $this->testAction(
+ '/lti/launch',
+ array('fixturize' => true, 'method' => 'post')
+ );
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'Invalid Nonce');
+ }
+
+
+ function testAdminRoster() {
+ $course = $this->Course->findById(1);
+
+ $initial_instructor_ids = [2];
+ $current_instructor_ids = Set::extract('/Instructor/id', $course);
+ $initial_tutor_ids = [35,36];
+ $current_tutor_ids = Set::extract('/Tutor/id', $course);
+ $initial_student_ids = [5, 6, 7, 13, 15, 17, 19, 21, 26, 28, 31, 32, 33];
+ $current_student_ids = Set::extract('/Enrol/id', $course);
+
+ $this->assertEqual($initial_instructor_ids, $current_instructor_ids);
+ $this->assertEqual($initial_tutor_ids, $current_tutor_ids);
+ $this->assertEqual($initial_student_ids, $current_student_ids);
+
+ $this->controller->expectOnce('redirect', array('/courses/home/1'));
+ $this->testAction('/lti/roster/1');
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'Imported Users from LMS');
+
+ $users = $this->User->find('all');
+ $new_users = array_slice($users, sizeof($users) - 3);
+ $new_instructor = $new_users[0];
+ $new_tutor = $new_users[1];
+ $new_student = $new_users[2];
+
+ $course = $this->Course->findById(1);
+
+ # verify expected enrollments
+ $expected_instructor_ids = [2, $new_instructor['User']['id'], 5];
+ $current_instructor_ids = Set::extract('/Instructor/id', $course);
+ $expected_tutor_ids = [35, $new_tutor['User']['id'], 6];
+ $current_tutor_ids = Set::extract('/Tutor/id', $course);
+ $expected_student_ids = [7, $new_student['User']['id']];
+ $current_student_ids = Set::extract('/Enrol/id', $course);
+
+ $this->assertEqual($expected_instructor_ids, $current_instructor_ids);
+ $this->assertEqual($expected_tutor_ids, $current_tutor_ids);
+ $this->assertEqual($current_student_ids, $current_student_ids);
+
+ # verify expected user data
+
+ # instructors
+ $user = $this->User->findById(2);
+ $this->assertEqual($user['User']['username'], 'instructor1');
+ $this->assertNotNull($user['User']['password']);
+ $this->assertEqual($user['User']['first_name'], 'Instructor.changed');
+ $this->assertEqual($user['User']['last_name'], '1.changed');
+ $this->assertNull($user['User']['student_no']);
+ $this->assertEqual($user['User']['email'], 'instructor1.changed@email');
+
+ $this->assertEqual($user['LtiUser'][0]['lti_tool_registration_id'], 1);
+ $this->assertEqual($user['LtiUser'][0]['lti_user_id'], 'mock_lti_user_id_instructor');
+
+ $user = $new_instructor;
+ $this->assertEqual($user['User']['username'], 'new_instructor');
+ $this->assertNotNull($user['User']['password']);
+ $this->assertEqual($user['User']['first_name'], 'Instructor');
+ $this->assertEqual($user['User']['last_name'], 'New');
+ $this->assertNull($user['User']['student_no']);
+ $this->assertEqual($user['User']['email'], 'instructor.new@email');
+
+ $this->assertEqual($user['LtiUser'][0]['lti_tool_registration_id'], 1);
+ $this->assertEqual($user['LtiUser'][0]['lti_user_id'], 'mocked_lti_user_id_new_instructor');
+
+ $user = $this->User->findById(5);
+ $this->assertEqual($user['User']['username'], 'redshirt0001');
+ $this->assertNotNull($user['User']['password']);
+ $this->assertEqual($user['User']['first_name'], 'Ed');
+ $this->assertEqual($user['User']['last_name'], 'Student (now instructor)');
+ $this->assertEqual($user['User']['student_no'], '65498451');
+ $this->assertEqual($user['User']['email'], '');
+
+ $this->assertEqual($user['LtiUser'][0]['lti_tool_registration_id'], 1);
+ $this->assertEqual($user['LtiUser'][0]['lti_user_id'], 'mocked_lti_user_id_redshirt0001');
+
+ # tutors
+ $user = $this->User->findById(35);
+ $this->assertEqual($user['User']['username'], 'tutor1');
+ $this->assertNotNull($user['User']['password']);
+ $this->assertEqual($user['User']['first_name'], 'Tutor');
+ $this->assertEqual($user['User']['last_name'], '1');
+ $this->assertEqual($user['User']['student_no'], '');
+ $this->assertEqual($user['User']['email'], '');
+
+ $this->assertEqual($user['LtiUser'][0]['lti_tool_registration_id'], 1);
+ $this->assertEqual($user['LtiUser'][0]['lti_user_id'], 'mocked_lti_user_id_tutor1');
+
+ $user = $new_tutor;
+ $this->assertEqual($user['User']['username'], 'new_tutor');
+ $this->assertNotNull($user['User']['password']);
+ $this->assertEqual($user['User']['first_name'], 'Tutor');
+ $this->assertEqual($user['User']['last_name'], 'New');
+ $this->assertNull($user['User']['student_no']);
+ $this->assertEqual($user['User']['email'], 'tutor.new@email');
+
+ $this->assertEqual($user['LtiUser'][0]['lti_tool_registration_id'], 1);
+ $this->assertEqual($user['LtiUser'][0]['lti_user_id'], 'mocked_lti_user_id_new_tutor');
+
+ $user = $this->User->findById(6);
+ $this->assertEqual($user['User']['username'], 'redshirt0002');
+ $this->assertNotNull($user['User']['password']);
+ $this->assertEqual($user['User']['first_name'], 'Alex');
+ $this->assertEqual($user['User']['last_name'], 'Student (now tutor)');
+ $this->assertEqual($user['User']['student_no'], '65468188');
+ $this->assertEqual($user['User']['email'], '');
+
+ $this->assertEqual($user['LtiUser'][0]['lti_tool_registration_id'], 1);
+ $this->assertEqual($user['LtiUser'][0]['lti_user_id'], 'mocked_lti_user_id_redshirt0002');
+
+
+ # students
+ $user = $this->User->findById(7);
+ $this->assertEqual($user['User']['username'], 'redshirt0003');
+ $this->assertNotNull($user['User']['password']);
+ $this->assertEqual($user['User']['first_name'], 'Matt');
+ $this->assertEqual($user['User']['last_name'], 'Student');
+ $this->assertEqual($user['User']['student_no'], '98985481');
+ $this->assertEqual($user['User']['email'], '');
+
+ $this->assertEqual($user['LtiUser'][0]['lti_tool_registration_id'], 1);
+ $this->assertEqual($user['LtiUser'][0]['lti_user_id'], 'mocked_lti_user_id_redshirt0003');
+
+ $user = $new_student;
+ $this->assertEqual($user['User']['username'], 'new_student');
+ $this->assertNotNull($user['User']['password']);
+ $this->assertEqual($user['User']['first_name'], 'New');
+ $this->assertEqual($user['User']['last_name'], 'Student');
+ $this->assertEqual($user['User']['student_no'], '999999999999');
+ $this->assertEqual($user['User']['email'], 'student.new@email');
+
+ $this->assertEqual($user['LtiUser'][0]['lti_tool_registration_id'], 1);
+ $this->assertEqual($user['LtiUser'][0]['lti_user_id'], 'mocked_lti_user_id_new_student');
+ }
+
+
+ function testInstructorRoster() {
+ $this->login = array(
+ 'User' => array(
+ 'username' => 'instructor1',
+ 'password' => md5('ipeeripeer')
+ )
+ );
+ $course = $this->Course->findById(1);
+
+ $initial_instructor_ids = [2];
+ $current_instructor_ids = Set::extract('/Instructor/id', $course);
+ $initial_tutor_ids = [35,36];
+ $current_tutor_ids = Set::extract('/Tutor/id', $course);
+ $initial_student_ids = [5, 6, 7, 13, 15, 17, 19, 21, 26, 28, 31, 32, 33];
+ $current_student_ids = Set::extract('/Enrol/id', $course);
+
+ $this->assertEqual($initial_instructor_ids, $current_instructor_ids);
+ $this->assertEqual($initial_tutor_ids, $current_tutor_ids);
+ $this->assertEqual($initial_student_ids, $current_student_ids);
+
+ $this->controller->expectOnce('redirect', array('/courses/home/1'));
+ $this->testAction('/lti/roster/1');
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'Imported Users from LMS');
+
+ $users = $this->User->find('all');
+ $new_users = array_slice($users, sizeof($users) - 3);
+ $new_instructor = $new_users[0];
+ $new_tutor = $new_users[1];
+ $new_student = $new_users[2];
+
+ $course = $this->Course->findById(1);
+
+ # verify expected enrollments
+ $expected_instructor_ids = [2, $new_instructor['User']['id'], 5];
+ $current_instructor_ids = Set::extract('/Instructor/id', $course);
+ $expected_tutor_ids = [35, $new_tutor['User']['id'], 6];
+ $current_tutor_ids = Set::extract('/Tutor/id', $course);
+ $expected_student_ids = [7, $new_student['User']['id']];
+ $current_student_ids = Set::extract('/Enrol/id', $course);
+
+ $this->assertEqual($expected_instructor_ids, $current_instructor_ids);
+ $this->assertEqual($expected_tutor_ids, $current_tutor_ids);
+ $this->assertEqual($current_student_ids, $current_student_ids);
+
+ # verify expected user data
+
+ # instructors
+ $user = $this->User->findById(2);
+ $this->assertEqual($user['User']['username'], 'instructor1');
+ $this->assertNotNull($user['User']['password']);
+ $this->assertEqual($user['User']['first_name'], 'Instructor.changed');
+ $this->assertEqual($user['User']['last_name'], '1.changed');
+ $this->assertNull($user['User']['student_no']);
+ $this->assertEqual($user['User']['email'], 'instructor1.changed@email');
+
+ $this->assertEqual($user['LtiUser'][0]['lti_tool_registration_id'], 1);
+ $this->assertEqual($user['LtiUser'][0]['lti_user_id'], 'mock_lti_user_id_instructor');
+
+ $user = $new_instructor;
+ $this->assertEqual($user['User']['username'], 'new_instructor');
+ $this->assertNotNull($user['User']['password']);
+ $this->assertEqual($user['User']['first_name'], 'Instructor');
+ $this->assertEqual($user['User']['last_name'], 'New');
+ $this->assertNull($user['User']['student_no']);
+ $this->assertEqual($user['User']['email'], 'instructor.new@email');
+
+ $this->assertEqual($user['LtiUser'][0]['lti_tool_registration_id'], 1);
+ $this->assertEqual($user['LtiUser'][0]['lti_user_id'], 'mocked_lti_user_id_new_instructor');
+
+ $user = $this->User->findById(5);
+ $this->assertEqual($user['User']['username'], 'redshirt0001');
+ $this->assertNotNull($user['User']['password']);
+ $this->assertEqual($user['User']['first_name'], 'Ed');
+ $this->assertEqual($user['User']['last_name'], 'Student (now instructor)');
+ $this->assertEqual($user['User']['student_no'], '65498451');
+ $this->assertEqual($user['User']['email'], '');
+
+ $this->assertEqual($user['LtiUser'][0]['lti_tool_registration_id'], 1);
+ $this->assertEqual($user['LtiUser'][0]['lti_user_id'], 'mocked_lti_user_id_redshirt0001');
+
+ # tutors
+ $user = $this->User->findById(35);
+ $this->assertEqual($user['User']['username'], 'tutor1');
+ $this->assertNotNull($user['User']['password']);
+ $this->assertEqual($user['User']['first_name'], 'Tutor');
+ $this->assertEqual($user['User']['last_name'], '1');
+ $this->assertEqual($user['User']['student_no'], '');
+ $this->assertEqual($user['User']['email'], '');
+
+ $this->assertEqual($user['LtiUser'][0]['lti_tool_registration_id'], 1);
+ $this->assertEqual($user['LtiUser'][0]['lti_user_id'], 'mocked_lti_user_id_tutor1');
+
+ $user = $new_tutor;
+ $this->assertEqual($user['User']['username'], 'new_tutor');
+ $this->assertNotNull($user['User']['password']);
+ $this->assertEqual($user['User']['first_name'], 'Tutor');
+ $this->assertEqual($user['User']['last_name'], 'New');
+ $this->assertNull($user['User']['student_no']);
+ $this->assertEqual($user['User']['email'], 'tutor.new@email');
+
+ $this->assertEqual($user['LtiUser'][0]['lti_tool_registration_id'], 1);
+ $this->assertEqual($user['LtiUser'][0]['lti_user_id'], 'mocked_lti_user_id_new_tutor');
+
+ $user = $this->User->findById(6);
+ $this->assertEqual($user['User']['username'], 'redshirt0002');
+ $this->assertNotNull($user['User']['password']);
+ $this->assertEqual($user['User']['first_name'], 'Alex');
+ $this->assertEqual($user['User']['last_name'], 'Student (now tutor)');
+ $this->assertEqual($user['User']['student_no'], '65468188');
+ $this->assertEqual($user['User']['email'], '');
+
+ $this->assertEqual($user['LtiUser'][0]['lti_tool_registration_id'], 1);
+ $this->assertEqual($user['LtiUser'][0]['lti_user_id'], 'mocked_lti_user_id_redshirt0002');
+
+
+ # students
+ $user = $this->User->findById(7);
+ $this->assertEqual($user['User']['username'], 'redshirt0003');
+ $this->assertNotNull($user['User']['password']);
+ $this->assertEqual($user['User']['first_name'], 'Matt');
+ $this->assertEqual($user['User']['last_name'], 'Student');
+ $this->assertEqual($user['User']['student_no'], '98985481');
+ $this->assertEqual($user['User']['email'], '');
+
+ $this->assertEqual($user['LtiUser'][0]['lti_tool_registration_id'], 1);
+ $this->assertEqual($user['LtiUser'][0]['lti_user_id'], 'mocked_lti_user_id_redshirt0003');
+
+ $user = $new_student;
+ $this->assertEqual($user['User']['username'], 'new_student');
+ $this->assertNotNull($user['User']['password']);
+ $this->assertEqual($user['User']['first_name'], 'New');
+ $this->assertEqual($user['User']['last_name'], 'Student');
+ $this->assertEqual($user['User']['student_no'], '999999999999');
+ $this->assertEqual($user['User']['email'], 'student.new@email');
+
+ $this->assertEqual($user['LtiUser'][0]['lti_tool_registration_id'], 1);
+ $this->assertEqual($user['LtiUser'][0]['lti_user_id'], 'mocked_lti_user_id_new_student');
+ }
+
+
+ function testTutorRoster() {
+ $this->login = array(
+ 'User' => array(
+ 'username' => 'tutor1',
+ 'password' => md5('ipeeripeer')
+ )
+ );
+
+ $course = $this->Course->findById(1);
+
+ $initial_instructor_ids = [2];
+ $current_instructor_ids = Set::extract('/Instructor/id', $course);
+ $initial_tutor_ids = [35,36];
+ $current_tutor_ids = Set::extract('/Tutor/id', $course);
+ $initial_student_ids = [5, 6, 7, 13, 15, 17, 19, 21, 26, 28, 31, 32, 33];
+ $current_student_ids = Set::extract('/Enrol/id', $course);
+
+ $this->assertEqual($initial_instructor_ids, $current_instructor_ids);
+ $this->assertEqual($initial_tutor_ids, $current_tutor_ids);
+ $this->assertEqual($initial_student_ids, $current_student_ids);
+
+ $this->controller->expectOnce('redirect', array('/home'));
+ $this->testAction('/lti/roster/1');
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'Error: You do not have permission to access the page.');
+
+ // roster should be unchanged
+ $course = $this->Course->findById(1);
+ $current_instructor_ids = Set::extract('/Instructor/id', $course);
+ $current_tutor_ids = Set::extract('/Tutor/id', $course);
+ $current_student_ids = Set::extract('/Enrol/id', $course);
+
+ $this->assertEqual($initial_instructor_ids, $current_instructor_ids);
+ $this->assertEqual($initial_tutor_ids, $current_tutor_ids);
+ $this->assertEqual($initial_student_ids, $current_student_ids);
+ }
+
+
+ function testStudentRoster() {
+ $this->login = array(
+ 'User' => array(
+ 'username' => 'redshirt0001',
+ 'password' => md5('ipeeripeer')
+ )
+ );
+
+ $course = $this->Course->findById(1);
+
+ $initial_instructor_ids = [2];
+ $current_instructor_ids = Set::extract('/Instructor/id', $course);
+ $initial_tutor_ids = [35,36];
+ $current_tutor_ids = Set::extract('/Tutor/id', $course);
+ $initial_student_ids = [5, 6, 7, 13, 15, 17, 19, 21, 26, 28, 31, 32, 33];
+ $current_student_ids = Set::extract('/Enrol/id', $course);
+
+ $this->assertEqual($initial_instructor_ids, $current_instructor_ids);
+ $this->assertEqual($initial_tutor_ids, $current_tutor_ids);
+ $this->assertEqual($initial_student_ids, $current_student_ids);
+
+ $this->controller->expectOnce('redirect', array('/home'));
+ $this->testAction('/lti/roster/1');
+ $message = $this->controller->Session->read('Message.flash');
+ $this->assertEqual($message['message'], 'Error: You do not have permission to access the page.');
+
+ // roster should be unchanged
+ $course = $this->Course->findById(1);
+ $current_instructor_ids = Set::extract('/Instructor/id', $course);
+ $current_tutor_ids = Set::extract('/Tutor/id', $course);
+ $current_student_ids = Set::extract('/Enrol/id', $course);
+
+ $this->assertEqual($initial_instructor_ids, $current_instructor_ids);
+ $this->assertEqual($initial_tutor_ids, $current_tutor_ids);
+ $this->assertEqual($initial_student_ids, $current_student_ids);
+ }
+}
+
+}
diff --git a/app/tests/cases/controllers/mixevals_controller.test.php b/app/tests/cases/controllers/mixevals_controller.test.php
index 2daf25800..2caeaa269 100644
--- a/app/tests/cases/controllers/mixevals_controller.test.php
+++ b/app/tests/cases/controllers/mixevals_controller.test.php
@@ -21,6 +21,8 @@ class MixevalsControllerTest extends ExtendedAuthTestCase {
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group', 'app.roles_user',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.event', 'app.event_template_type', 'app.group_event',
'app.evaluation_submission', 'app.survey_group_set',
'app.survey_group', 'app.survey_group_member', 'app.question',
diff --git a/app/tests/cases/controllers/oauth_clients_controller.test.php b/app/tests/cases/controllers/oauth_clients_controller.test.php
index a75d24d67..447ae9943 100644
--- a/app/tests/cases/controllers/oauth_clients_controller.test.php
+++ b/app/tests/cases/controllers/oauth_clients_controller.test.php
@@ -13,6 +13,8 @@ class OauthClientsControllerTestCase extends ExtendedAuthTestCase {
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/controllers/oauth_tokens_controller.test.php b/app/tests/cases/controllers/oauth_tokens_controller.test.php
index 9cfe611b7..2cca795cc 100644
--- a/app/tests/cases/controllers/oauth_tokens_controller.test.php
+++ b/app/tests/cases/controllers/oauth_tokens_controller.test.php
@@ -13,6 +13,8 @@ class OauthTokensControllerTestCase extends ExtendedAuthTestCase {
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/controllers/rubrics_controller.test.php b/app/tests/cases/controllers/rubrics_controller.test.php
index d0fa64dde..b5f6b68fd 100644
--- a/app/tests/cases/controllers/rubrics_controller.test.php
+++ b/app/tests/cases/controllers/rubrics_controller.test.php
@@ -21,6 +21,8 @@ class RubricsControllerTest extends ExtendedAuthTestCase {
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
@@ -76,37 +78,37 @@ function testIndex() {
$result = $this->testAction('/rubrics/index', array('connection' => 'test_suite', 'return' => 'contents'));
//$this->assertEqual($result['paramsForList']['data']['entries'][0]['Course']['course'], 'Math303');
}
-
+
function testPostProcess() {
-
+
}
-
+
function testSetUpAjaxList() {
-
+
}
-
+
function testAjaxList() {
-
+
}
-
+
function testView() {
-
+
}
-
+
function testAdd() {
$result = $this->testAction('/rubrics/add', array('connection' => 'test_suite', 'return' => 'vars'));
}
-
+
function testEdit() {
-
+
}
-
+
function testCopy() {
-
+
}
-
+
function testDelete() {
-
+
}
}
diff --git a/app/tests/cases/controllers/searchs_controller.test.php b/app/tests/cases/controllers/searchs_controller.test.php
index 088e86ff2..d3310ba35 100644
--- a/app/tests/cases/controllers/searchs_controller.test.php
+++ b/app/tests/cases/controllers/searchs_controller.test.php
@@ -12,6 +12,8 @@
class SearchsControllerTest extends CakeTestCase {
var $fixtures = array('app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type', 'app.rubrics_lom',
'app.group_event', 'app.evaluation_submission', 'app.rubrics_criteria_comment',
'app.survey_group_set', 'app.survey_group', 'app.rubrics_criteria',
diff --git a/app/tests/cases/controllers/simpleevaluations_controller.test.php b/app/tests/cases/controllers/simpleevaluations_controller.test.php
index 842f4612f..e753f132f 100644
--- a/app/tests/cases/controllers/simpleevaluations_controller.test.php
+++ b/app/tests/cases/controllers/simpleevaluations_controller.test.php
@@ -21,6 +21,8 @@ class SimpleevaluationsControllerTest extends ExtendedAuthTestCase {
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/controllers/surveygroups_controller.test.php b/app/tests/cases/controllers/surveygroups_controller.test.php
index 8d3b0451f..2cf3242d0 100644
--- a/app/tests/cases/controllers/surveygroups_controller.test.php
+++ b/app/tests/cases/controllers/surveygroups_controller.test.php
@@ -21,6 +21,8 @@ class SurveygroupsControllerTest extends ExtendedAuthTestCase {
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/controllers/surveys_controller.test.php b/app/tests/cases/controllers/surveys_controller.test.php
index 60c2b4073..4ed2f815b 100644
--- a/app/tests/cases/controllers/surveys_controller.test.php
+++ b/app/tests/cases/controllers/surveys_controller.test.php
@@ -21,6 +21,8 @@ class SurveyControllerTest extends ExtendedAuthTestCase {
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/controllers/sysparameters_controller.test.php b/app/tests/cases/controllers/sysparameters_controller.test.php
index db47e2a6c..73e1c91ff 100644
--- a/app/tests/cases/controllers/sysparameters_controller.test.php
+++ b/app/tests/cases/controllers/sysparameters_controller.test.php
@@ -21,6 +21,8 @@ class SysparametersControllerTest extends ExtendedAuthTestCase {
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/controllers/v1_controller.test.php b/app/tests/cases/controllers/v1_controller.test.php
index 5d549ecc5..bd48675d8 100644
--- a/app/tests/cases/controllers/v1_controller.test.php
+++ b/app/tests/cases/controllers/v1_controller.test.php
@@ -2,6 +2,8 @@
class V1ControllerTest extends CakeTestCase {
public $fixtures = array(
'app.evaluation_mixeval', 'app.evaluation_rubric',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.evaluation_simple', 'app.course', 'app.role', 'app.user',
'app.group', 'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission', 'app.survey_group_set',
@@ -1011,7 +1013,7 @@ function testUsersEvents()
'id' => '10',
),
);
-
+
$expectedSubmittableEvents = array(
array(
'title' => 'Term 1 Evaluation',
@@ -1082,7 +1084,7 @@ function testUsersEvents()
'id' => '5',
)
);
-
+
$expectedResultReleasedEvents = array(
array(
'title' => 'simple evaluation 4',
@@ -1113,7 +1115,7 @@ function testUsersEvents()
'id' => '9',
)
);
-
+
$expectedFilteredEvents = array(
array(
'title' => 'Term 1 Evaluation',
@@ -1212,7 +1214,7 @@ function testUsersEvents()
'id' => '9',
)
);
-
+
// get ALL events for redshirt0001
$url = $this->_getURL('/v1/users/redshirt0001/events/sub/0/results/0');
$actualEvents = $this->_oauthReq("$url");
@@ -1224,19 +1226,19 @@ function testUsersEvents()
$courseUserEvents = $this->_oauthReq("$url");
$events = Set::sort(json_decode($courseUserEvents, true), '{n}.id', 'asc');
$this->assertEqual($expectedEvents, $events);
-
+
// get events for redshirt0001 available for submissions
$url = $this->_getURL('/v1/users/redshirt0001/events/sub/1/results/0');
$eventsSubmittable = $this->_oauthReq("$url");
$events = Set::sort(json_decode($eventsSubmittable, true), '{n}.id', 'asc');
$this->assertEqual($expectedSubmittableEvents, $events);
-
+
// get events for redshirt0001 that have results released
$url = $this->_getURL('/v1/users/redshirt0001/events/sub/0/results/1');
$eventsResult = $this->_oauthReq("$url");
$events = Set::sort(json_decode($eventsResult, true), '{n}.id', 'asc');
$this->assertEqual($expectedResultReleasedEvents, $events);
-
+
// get events for redshirt0001 available for submissions OR have results released
$url = $this->_getURL('/v1/users/redshirt0001/events/sub/1/results/1');
$filteredEvents = $this->_oauthReq("$url");
@@ -1248,25 +1250,25 @@ function testUsersEvents()
$eventsSubmittable = $this->_oauthReq("$url");
$events = Set::sort(json_decode($eventsSubmittable, true), '{n}.id', 'asc');
$this->assertEqual($expectedSubmittableEvents, $events);
-
+
// get events in course id 1 for redshirt0001 that have results released
$url = $this->_getURL('/v1/courses/1/users/redshirt0001/events/sub/0/results/1');
$eventsResult = $this->_oauthReq("$url");
$events = Set::sort(json_decode($eventsResult, true), '{n}.id', 'asc');
$this->assertEqual($expectedResultReleasedEvents, $events);
-
+
// get events in course id 1 for redshirt0001 available for submissions OR have results released
$url = $this->_getURL('/v1/courses/1/users/redshirt0001/events/sub/1/results/1');
$filteredEvents = $this->_oauthReq("$url");
$events = Set::sort(json_decode($filteredEvents, true), '{n}.id', 'asc');
$this->assertEqual($expectedFilteredEvents, $events);
-
+
// get ALL events for redshirt0001 - no filters
$url = $this->_getURL('/v1/users/redshirt0001/events');
$events = $this->_oauthReq("$url");
$events = Set::sort(json_decode($events, true), '{n}.id', 'asc');
$this->assertEqual($expectedEvents, $events);
-
+
// get ALL events in course id 1 for redshirt0001 - no filters
$url = $this->_getURL('/v1/courses/1/users/redshirt0001/events');
$events = $this->_oauthReq("$url");
diff --git a/app/tests/cases/models/access.test.php b/app/tests/cases/models/access.test.php
index 89bdc398e..fcd3d42bb 100644
--- a/app/tests/cases/models/access.test.php
+++ b/app/tests/cases/models/access.test.php
@@ -5,6 +5,8 @@ class AccessTestCase extends CakeTestCase {
public $name = 'Access';
public $fixtures = array('app.access', 'app.oauth_token', 'app.sys_parameter',
'app.user', 'app.evaluation_submission', 'app.event', 'app.event_template_type',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.course', 'app.group', 'app.group_event', 'app.evaluation_simple',
'app.survey_input', 'app.survey_group_member', 'app.survey_group_set',
'app.survey', 'app.question', 'app.response', 'app.survey_question',
@@ -12,35 +14,35 @@ class AccessTestCase extends CakeTestCase {
'app.user_course', 'app.user_tutor', 'app.user_enrol','app.groups_member',
'app.department', 'app.course_department', 'app.penalty');
public $Access = null;
-
+
function startCase()
{
echo "Start Access model test.\n";
$this->Access = ClassRegistry::init('Access');
}
-
+
function endCase()
{
}
-
+
function startTest($method)
{
}
-
+
function endTest($method)
{
}
-
+
function testAccessInstance()
{
$this->assertTrue(is_a($this->Access, 'Access'));
}
-
+
function testLoadPermissions()
{
$this->Aco = ClassRegistry::init('Aco');
$this->Aro = ClassRegistry::init('Aro');
-
+
//id should not be used since it can change
$allow = array('create' => 1, 'read' => 1, 'update' => 1, 'delete' => 1);
$deny = array('create' => -1, 'read' => -1, 'update' => -1, 'delete' => -1);
@@ -51,31 +53,31 @@ function testLoadPermissions()
$superadmin = $this->Access->loadPermissions($acos, $group_aro);
unset($superadmin["controllers/users/add"]["id"]);
$this->assertEqual($superadmin['controllers/users/add'], $allow);
-
+
// Testing for admin role
$group_aro = $this->Aro->find('threaded', array('conditions'=>array('Aro.foreign_key'=>2, 'Aro.model'=>'Role')));
$admin = $this->Access->loadPermissions($acos, $group_aro);
unset($admin["controllers/users/add"]["id"]);
$this->assertEqual($admin['controllers/users/add'], $allow);
-
+
// Testing for instructor role
$group_aro = $this->Aro->find('threaded', array('conditions'=>array('Aro.foreign_key'=>3, 'Aro.model'=>'Role')));
$instructor = $this->Access->loadPermissions($acos, $group_aro);
unset($instructor["controllers/users/add"]["id"]);
$this->assertEqual($instructor['controllers/users/add'], $allow);
-
+
// Testing for tutor role
$group_aro = $this->Aro->find('threaded', array('conditions'=>array('Aro.foreign_key'=>4, 'Aro.model'=>'Role')));
$tutor = $this->Access->loadPermissions($acos, $group_aro);
unset($tutor["controllers/users/add"]["id"]);
$this->assertEqual($tutor['controllers/users/add'], $deny);
-
+
// Testing for student role
$group_aro = $this->Aro->find('threaded', array('conditions'=>array('Aro.foreign_key'=>5, 'Aro.model'=>'Role')));
$student = $this->Access->loadPermissions($acos, $group_aro);
unset($student["controllers/users/add"]["id"]);
$this->assertEqual($student['controllers/users/add'], $deny);
-
+
// Testing for invalid role
$group_aro = $this->Aro->find('threaded', array('conditions'=>array('Aro.foreign_key'=>999, 'Aro.model'=>'Role')));
$invalid = $this->Access->loadPermissions($acos, $group_aro);
diff --git a/app/tests/cases/models/course.test.php b/app/tests/cases/models/course.test.php
index 6a878a17e..e35d10aa0 100644
--- a/app/tests/cases/models/course.test.php
+++ b/app/tests/cases/models/course.test.php
@@ -4,6 +4,8 @@
class CourseTestCase extends CakeTestCase {
public $name = 'Course';
public $fixtures = array('app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/course_department.test.php b/app/tests/cases/models/course_department.test.php
index c1c24dece..dc3997d38 100644
--- a/app/tests/cases/models/course_department.test.php
+++ b/app/tests/cases/models/course_department.test.php
@@ -3,7 +3,16 @@
App::import('Model', 'CourseDepartment');
class CourseDepartmentTestCase extends CakeTestCase {
- var $fixtures = array('app.course_department', 'app.course', 'app.group', 'app.user', 'app.evaluation_submission', 'app.event', 'app.event_template_type', 'app.group_event', 'app.user_faculty', 'app.faculty', 'app.department', 'app.user_course', 'app.user_enrol', 'app.groups_member', 'app.role', 'app.roles_user', 'app.survey', 'app.survey_group_set', 'app.survey_group', 'app.survey_group_member', 'app.question', 'app.response', 'app.survey_question');
+ var $fixtures = array(
+ 'app.course_department', 'app.course', 'app.group', 'app.user',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
+ 'app.evaluation_submission', 'app.event', 'app.event_template_type',
+ 'app.group_event', 'app.user_faculty', 'app.faculty', 'app.department',
+ 'app.user_course', 'app.user_enrol', 'app.groups_member', 'app.role',
+ 'app.roles_user', 'app.survey', 'app.survey_group_set', 'app.survey_group',
+ 'app.survey_group_member', 'app.question', 'app.response', 'app.survey_question'
+ );
function startTest($method) {
echo "Start CourseDepartment model test.\n";
@@ -11,7 +20,7 @@ function startTest($method) {
function endTest($method) {
}
-
+
function testinsertCourses() {
//TODO
}
diff --git a/app/tests/cases/models/department.test.php b/app/tests/cases/models/department.test.php
index 482361889..b94a2a2ac 100644
--- a/app/tests/cases/models/department.test.php
+++ b/app/tests/cases/models/department.test.php
@@ -6,6 +6,8 @@ class DepartmentTestCase extends CakeTestCase {
public $name = 'Department';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/email_merge.test.php b/app/tests/cases/models/email_merge.test.php
index 3a1254df7..6f7184086 100644
--- a/app/tests/cases/models/email_merge.test.php
+++ b/app/tests/cases/models/email_merge.test.php
@@ -5,6 +5,8 @@ class EmailMergeTestCase extends CakeTestCase
{
public $name = 'EmailMerge';
public $fixtures = array('app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/email_schedule.test.php b/app/tests/cases/models/email_schedule.test.php
index 53bee70b7..55e56ea31 100644
--- a/app/tests/cases/models/email_schedule.test.php
+++ b/app/tests/cases/models/email_schedule.test.php
@@ -5,6 +5,8 @@ class EmailScheduleTestCase extends CakeTestCase
{
public $name = 'EmailSchedule';
public $fixtures = array('app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/email_template.test.php b/app/tests/cases/models/email_template.test.php
index 4dd4da273..7cead6bfd 100644
--- a/app/tests/cases/models/email_template.test.php
+++ b/app/tests/cases/models/email_template.test.php
@@ -6,6 +6,8 @@ class EmailTemplateTestCase extends CakeTestCase
public $name = 'EmailTemplate';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/evaluation_mixeval.test.php b/app/tests/cases/models/evaluation_mixeval.test.php
index 7055b8101..db70fc8c0 100644
--- a/app/tests/cases/models/evaluation_mixeval.test.php
+++ b/app/tests/cases/models/evaluation_mixeval.test.php
@@ -5,6 +5,8 @@ class EvaluationMixevalTestCase extends CakeTestCase
{
public $name = 'EvaluationMixeval';
public $fixtures = array('app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
@@ -168,7 +170,7 @@ function testSetAllEventGradeRelease()
$this->assertEqual($searched[1]['EvaluationMixeval']['grade_release'], 0);
$this->assertEqual($searched[2]['EvaluationMixeval']['grade_release'], 0);
}
-
+
function testGetResultsByEvaluateesAndEvaluators()
{
// TODO
diff --git a/app/tests/cases/models/evaluation_mixeval_detail.test.php b/app/tests/cases/models/evaluation_mixeval_detail.test.php
index 9775585df..9ee099f2c 100644
--- a/app/tests/cases/models/evaluation_mixeval_detail.test.php
+++ b/app/tests/cases/models/evaluation_mixeval_detail.test.php
@@ -4,6 +4,8 @@
class EvaluationMixevalDetailTestCase extends CakeTestCase {
public $name = 'EvaluationMixevalDetail';
public $fixtures = array('app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/evaluation_rubric.test.php b/app/tests/cases/models/evaluation_rubric.test.php
index dff0e9cf2..21db2e03e 100644
--- a/app/tests/cases/models/evaluation_rubric.test.php
+++ b/app/tests/cases/models/evaluation_rubric.test.php
@@ -5,6 +5,8 @@ class EvaluationRubricTestCase extends CakeTestCase
{
public $name = 'EvaluationRubric';
public $fixtures = array('app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/evaluation_rubric_detail.test.php b/app/tests/cases/models/evaluation_rubric_detail.test.php
index 82ee30d91..ebd045591 100644
--- a/app/tests/cases/models/evaluation_rubric_detail.test.php
+++ b/app/tests/cases/models/evaluation_rubric_detail.test.php
@@ -6,6 +6,8 @@ class EvaluationRubricDetailTestCase extends CakeTestCase
public $name = 'EvaluationRubricDetail';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/evaluation_simple.test.php b/app/tests/cases/models/evaluation_simple.test.php
index fd1d6552a..35cb81c7a 100644
--- a/app/tests/cases/models/evaluation_simple.test.php
+++ b/app/tests/cases/models/evaluation_simple.test.php
@@ -6,6 +6,8 @@ class EvaluationSimpleTestCase extends CakeTestCase
public $name = 'EvaluationSimple';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/evaluation_submission.test.php b/app/tests/cases/models/evaluation_submission.test.php
index 849a056bc..e8c925c1c 100644
--- a/app/tests/cases/models/evaluation_submission.test.php
+++ b/app/tests/cases/models/evaluation_submission.test.php
@@ -5,6 +5,8 @@ class EvaluationSubmissionTestCase extends CakeTestCase
{
public $name = 'EvaluationSimple';
public $fixtures = array('app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/event.test.php b/app/tests/cases/models/event.test.php
index c6fe40eb8..cdfeef493 100644
--- a/app/tests/cases/models/event.test.php
+++ b/app/tests/cases/models/event.test.php
@@ -6,6 +6,8 @@ class EventTestCase extends CakeTestCase
public $name = 'Event';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/event_template_type.test.php b/app/tests/cases/models/event_template_type.test.php
index f2c198015..c8b7fde71 100644
--- a/app/tests/cases/models/event_template_type.test.php
+++ b/app/tests/cases/models/event_template_type.test.php
@@ -5,6 +5,8 @@ class EventTemplateTypeTestCase extends CakeTestCase {
public $name = 'EventTemplateType';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/faculty.test.php b/app/tests/cases/models/faculty.test.php
index 6f7f15026..cc37e3302 100644
--- a/app/tests/cases/models/faculty.test.php
+++ b/app/tests/cases/models/faculty.test.php
@@ -3,7 +3,16 @@
App::import('Model', 'Faculty');
class FacultyTestCase extends CakeTestCase {
- var $fixtures = array('app.faculty', 'app.department', 'app.course_department', 'app.course', 'app.group', 'app.user', 'app.evaluation_submission', 'app.event', 'app.event_template_type', 'app.group_event', 'app.user_faculty', 'app.user_course', 'app.user_enrol', 'app.groups_member', 'app.role', 'app.roles_user', 'app.survey', 'app.survey_group_set', 'app.survey_group', 'app.survey_group_member', 'app.question', 'app.response', 'app.survey_question');
+ var $fixtures = array(
+ 'app.faculty', 'app.department', 'app.course_department', 'app.course',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
+ 'app.group', 'app.user', 'app.evaluation_submission', 'app.event',
+ 'app.event_template_type', 'app.group_event', 'app.user_faculty',
+ 'app.user_course', 'app.user_enrol', 'app.groups_member', 'app.role',
+ 'app.roles_user', 'app.survey', 'app.survey_group_set', 'app.survey_group',
+ 'app.survey_group_member', 'app.question', 'app.response', 'app.survey_question'
+ );
function startTest($method) {
echo "Start Faculty model test.\n";
diff --git a/app/tests/cases/models/group.test.php b/app/tests/cases/models/group.test.php
index 302d75345..e211859a0 100644
--- a/app/tests/cases/models/group.test.php
+++ b/app/tests/cases/models/group.test.php
@@ -5,6 +5,8 @@ class GroupTestCase extends CakeTestCase
{
public $name = 'Group';
public $fixtures = array('app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/group_event.test.php b/app/tests/cases/models/group_event.test.php
index 10ecef4fa..7cee2c3fc 100644
--- a/app/tests/cases/models/group_event.test.php
+++ b/app/tests/cases/models/group_event.test.php
@@ -5,6 +5,8 @@ class GroupEventTestCase extends CakeTestCase {
public $name = 'GroupEvent';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/groups_members.test.php b/app/tests/cases/models/groups_members.test.php
index 005caafc4..d9b640276 100644
--- a/app/tests/cases/models/groups_members.test.php
+++ b/app/tests/cases/models/groups_members.test.php
@@ -6,6 +6,8 @@ class GroupsMembersTestCase extends CakeTestCase
public $name = 'GroupsMembers';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/lti_tool_registration.test.php b/app/tests/cases/models/lti_tool_registration.test.php
new file mode 100644
index 000000000..ee89a412d
--- /dev/null
+++ b/app/tests/cases/models/lti_tool_registration.test.php
@@ -0,0 +1,66 @@
+
+ * @copyright 2019 All rights reserved.
+ * @license MIT {@link http://www.opensource.org/licenses/MIT}
+ */
+class LtiToolRegistrationTestCase extends CakeTestCase
+{
+ public $fixtures = array(
+ 'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
+ 'app.roles_user', 'app.event', 'app.event_template_type',
+ 'app.group_event', 'app.evaluation_submission',
+ 'app.survey', 'app.oauth_token',
+ 'app.survey_group_set', 'app.survey_group',
+ 'app.survey_group_member', 'app.question',
+ 'app.response', 'app.survey_question', 'app.user_course',
+ 'app.user_enrol', 'app.groups_member', 'app.mixeval',
+ 'app.mixeval_question', 'app.mixeval_question_desc', 'app.faculty',
+ 'app.user_faculty', 'app.department', 'app.course_department',
+ 'app.sys_parameter', 'app.user_tutor', 'app.penalty',
+ 'app.evaluation_simple', 'app.survey_input',
+ 'app.mixeval_question_type', 'app.evaluation_rubric', 'app.evaluation_rubric_detail',
+ 'app.evaluation_mixeval', 'app.evaluation_mixeval_detail'
+ );
+ public $LtiToolRegistration;
+
+ function startCase()
+ {
+ $this->LtiToolRegistration = ClassRegistry::init('LtiToolRegistration');
+ }
+
+ function test_findByIss()
+ {
+
+ $ret = $this->LtiToolRegistration->findByIss('https://docker-canvas.instructure.com');
+ $this->assertEqual($ret['LtiToolRegistration'], array(
+ 'id' => 1,
+ 'iss' => 'https://docker-canvas.instructure.com',
+ 'client_id' => '10000000000013',
+ 'auth_login_url' => 'http://mock_lti.com/api/lti/authorize_redirect',
+ 'auth_token_url' => 'http://mock_lti.com/login/oauth2/token',
+ 'key_set_url' => 'http://mock_lti.com/api/lti/security/jwks',
+ 'tool_private_key' => "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEApBK2zJCDg9s8QDeci6E4QWlTSGav3qh5edjbXULo5Mv0KxN7\nqLyC05QfRrs/I+P5a6D18S/ecAGYPH5xQKuPvqOEotPrRhHCkJB5PtLDsF4ZZbr/\nwWLWG5OYhCkY/H2Wip9rsx1GjKG73EMMTqT2p14K+GW4dg8/HbxQLA4yGeNnGr4D\nd87A+n9wUvMZYAxoCiHiSFD7x0hVIg/q4VXoWHBGEnnqCMC9Gtd7g7HZtQzbYMm4\nm2uY5JHhs+MXS8YKf6Ftc58sJHK5fMtjs9vMVOCkAlrEiEEn+tEHOjSNlzMg+P03\nUU79Lt/MDjXv3mtEPVmPjpJevT4Kjf1HxCSUNQIDAQABAoIBAF5Jmt9IFSwLKz7E\nNqRPS+LbQk8TI/JS4yxQoQ+hSfFh+7ldguzfGFe6gZbGOGzJsCZX475tAelgITpy\nd2bwsLSfh7ODEWu8/RDS1bpyqJ6MFRBPPHbH8775POaGL6O6EG8tWlkec9KRh0H3\nDfWL+2sHMkq5Oh4ueNj/xRrsNYKGLsD0bJMS9eFswDCpvL3fscu/JrrQT+CltBTJ\nj8lTHmGRIF9UOg0Ef1kEgOxcR+AZ2djP3d+zkKZxMATLKWnA1HRFPb7XpJQfjA+k\nsismB4FuhvTSN6IRaci1U5qASHUnIjbTMfFsqJ3h17RivQmSEz1r28OE1HyD/tdE\nIIy3WikCgYEAz6r27/MfEWXgOAwloKJAQi0sqa/0VkWQcNPN3jSgO+AN0iqPLSuj\nAlrLqlLcRlyYAfe7t6B/8SAklJtdy0x9uBaJXrmHhby4jeBksyycQULUzTUhGdbW\nGDfR+XbvNoGUaH1q+vIpglz2jw3N1/M6B/i16wd6Q81UO5WYxQj1j7sCgYEAykJW\nIq4A4UQmtM6gdsXXranV80NOlcH0p521Ec6wpU0dxfI+qVVbT4FxqxfB9Pq5N4V0\nreEYN1ALbjLi3fvChbx8P+lg6k/Tuhn7oiH3kado8iUUR00KyRwWeaMbVwUzU9sQ\nUhB/XfR3J7l3inN/dAlfdSsYbnQJN2U88CKEVM8CgYBfM2UZAz+O3kE38HmfdkI3\nFDaRY9SDaEibML4Dy+RZDpHHczNH5eVIww7y+iF5MCGPZV5tA+sjQzUB22fYNyy7\nI7m97xetu6JviBsh+KV5VYXwvRZ7nf1wBMcBsgBf4G+Ep1pPyIw28x8k3ZMsGJjV\n5rKfGEJ4qryexCnQyhao2QKBgCel71qm/3cpM+k3pA8EY24gn9cq94m11q7Q5IDU\nIp6UymRWQ2BQYjDosA6Y/qV2TL6Mg73eJTAamdMFWKGpS42J0FV6+0uTUG7nzwMO\nY4iC57in+hysBpQ71FAN4DsjwtcKV12u7DjPxlfcLInQcEif2b2PMB/e0Tuxtcth\nCM3TAoGAM+z4u7mi5jxyW9teAYtx3Yb6RGeuly7XvlknV0Lwf2438P2HNZiOa4SE\nSXHZir6LWNv8HOdGapYxUlDfmeNneo4D9B8lBpVs/FsuQF1aOI6B299SlVLPmF+a\nl88qKzXKv7M1pcOv74GK1AIVDF8XJvt1PyaQX92M14q2Ga8Jdjk=\n-----END RSA PRIVATE KEY-----",
+ 'tool_public_key' => "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApBK2zJCDg9s8QDeci6E4\nQWlTSGav3qh5edjbXULo5Mv0KxN7qLyC05QfRrs/I+P5a6D18S/ecAGYPH5xQKuP\nvqOEotPrRhHCkJB5PtLDsF4ZZbr/wWLWG5OYhCkY/H2Wip9rsx1GjKG73EMMTqT2\np14K+GW4dg8/HbxQLA4yGeNnGr4Dd87A+n9wUvMZYAxoCiHiSFD7x0hVIg/q4VXo\nWHBGEnnqCMC9Gtd7g7HZtQzbYMm4m2uY5JHhs+MXS8YKf6Ftc58sJHK5fMtjs9vM\nVOCkAlrEiEEn+tEHOjSNlzMg+P03UU79Lt/MDjXv3mtEPVmPjpJevT4Kjf1HxCSU\nNQIDAQAB\n-----END PUBLIC KEY-----",
+ 'user_identifier_field' => 'https://purl.imsglobal.org/spec/lti/claim/custom|username',
+ 'student_number_field' => 'https://purl.imsglobal.org/spec/lti/claim/custom|student_number',
+ 'term_field' => 'https://purl.imsglobal.org/spec/lti/claim/custom|term_name',
+ 'canvas_id_field' => 'https://purl.imsglobal.org/spec/lti/claim/custom|canvas_course_id',
+ 'faculty_name_field' => 'https://purl.imsglobal.org/spec/lti/claim/custom|account_name',
+ ));
+
+ $ret = $this->LtiToolRegistration->findByIss('');
+ $this->assertEqual($ret, array());
+ }
+}
diff --git a/app/tests/cases/models/mixeval.test.php b/app/tests/cases/models/mixeval.test.php
index 87298a8ad..b8d66919f 100644
--- a/app/tests/cases/models/mixeval.test.php
+++ b/app/tests/cases/models/mixeval.test.php
@@ -6,6 +6,8 @@ class MixevalTestCase extends CakeTestCase
public $name = 'Mixeval';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey', 'app.oauth_token',
@@ -16,7 +18,7 @@ class MixevalTestCase extends CakeTestCase
'app.mixeval_question', 'app.mixeval_question_desc', 'app.faculty',
'app.user_faculty', 'app.department', 'app.course_department',
'app.sys_parameter', 'app.user_tutor', 'app.penalty',
- 'app.evaluation_simple', 'app.survey_input',
+ 'app.evaluation_simple', 'app.survey_input',
'app.mixeval_question_type', 'app.evaluation_rubric', 'app.evaluation_rubric_detail',
'app.evaluation_mixeval', 'app.evaluation_mixeval_detail'
);
diff --git a/app/tests/cases/models/mixeval_question.test.php b/app/tests/cases/models/mixeval_question.test.php
index ca915ee6e..145c46c33 100644
--- a/app/tests/cases/models/mixeval_question.test.php
+++ b/app/tests/cases/models/mixeval_question.test.php
@@ -6,12 +6,14 @@ class MixevalQuestionTestCase extends CakeTestCase
public $name = 'MixevalQuestion';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission', 'app.oauth_token',
'app.survey_group_set', 'app.survey_group', 'app.sys_parameter',
'app.survey_group_member', 'app.question', 'app.evaluation_simple',
'app.response', 'app.survey_question', 'app.user_course',
- 'app.user_enrol', 'app.groups_member', 'app.mixeval',
+ 'app.user_enrol', 'app.groups_member', 'app.mixeval',
'app.mixeval_question', 'app.mixeval_question_desc', 'app.survey_input',
'app.survey', 'app.faculty', 'app.user_faculty', 'app.user_tutor',
'app.department', 'app.course_department', 'app.penalty',
diff --git a/app/tests/cases/models/mixeval_question_desc.test.php b/app/tests/cases/models/mixeval_question_desc.test.php
index 1ea03ed72..32d36c5ce 100644
--- a/app/tests/cases/models/mixeval_question_desc.test.php
+++ b/app/tests/cases/models/mixeval_question_desc.test.php
@@ -6,14 +6,16 @@ class MixevalQuestionDescTestCase extends CakeTestCase
public $name = 'MixevalQuestionDesc';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission', 'app.oauth_token',
'app.survey_group_set', 'app.survey_group', 'app.sys_parameter',
'app.survey_group_member', 'app.question', 'app.evaluation_simple',
'app.response', 'app.survey_question', 'app.user_course',
- 'app.user_enrol', 'app.groups_member', 'app.mixeval',
+ 'app.user_enrol', 'app.groups_member', 'app.mixeval',
'app.mixeval_question', 'app.user_faculty', 'app.user_tutor',
- 'app.mixeval_question_desc', 'app.survey_input', 'app.faculty',
+ 'app.mixeval_question_desc', 'app.survey_input', 'app.faculty',
'app.department', 'app.course_department', 'app.penalty',
'app.mixeval_question_type'
);
diff --git a/app/tests/cases/models/oauth_client.test.php b/app/tests/cases/models/oauth_client.test.php
index bfbd1a99b..84562f6a9 100644
--- a/app/tests/cases/models/oauth_client.test.php
+++ b/app/tests/cases/models/oauth_client.test.php
@@ -3,7 +3,17 @@
App::import('Model', 'OauthClient');
class OauthClientTestCase extends CakeTestCase {
- var $fixtures = array('app.oauth_client', 'app.user', 'app.evaluation_submission', 'app.event', 'app.event_template_type', 'app.course', 'app.group', 'app.group_event', 'app.groups_member', 'app.survey', 'app.survey_group_set', 'app.survey_group', 'app.survey_group_member', 'app.question', 'app.response', 'app.survey_question', 'app.user_course', 'app.user_tutor', 'app.user_enrol', 'app.department', 'app.faculty', 'app.course_department', 'app.penalty', 'app.user_faculty', 'app.role', 'app.roles_user');
+ var $fixtures = array(
+ 'app.oauth_client', 'app.user', 'app.evaluation_submission', 'app.event',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
+ 'app.event_template_type', 'app.course', 'app.group', 'app.group_event',
+ 'app.groups_member', 'app.survey', 'app.survey_group_set', 'app.survey_group',
+ 'app.survey_group_member', 'app.question', 'app.response', 'app.survey_question',
+ 'app.user_course', 'app.user_tutor', 'app.user_enrol', 'app.department',
+ 'app.faculty', 'app.course_department', 'app.penalty', 'app.user_faculty',
+ 'app.role', 'app.roles_user'
+ );
function startTest($method) {
$this->OauthClient =& ClassRegistry::init('OauthClient');
diff --git a/app/tests/cases/models/oauth_token.test.php b/app/tests/cases/models/oauth_token.test.php
index 96cac1ce4..16949a314 100644
--- a/app/tests/cases/models/oauth_token.test.php
+++ b/app/tests/cases/models/oauth_token.test.php
@@ -3,7 +3,17 @@
App::import('Model', 'OauthToken');
class OauthTokenTestCase extends CakeTestCase {
- var $fixtures = array('app.oauth_token', 'app.user', 'app.evaluation_submission', 'app.event', 'app.event_template_type', 'app.course', 'app.group', 'app.group_event', 'app.groups_member', 'app.survey', 'app.survey_group_set', 'app.survey_group', 'app.survey_group_member', 'app.question', 'app.response', 'app.survey_question', 'app.user_course', 'app.user_tutor', 'app.user_enrol', 'app.department', 'app.faculty', 'app.course_department', 'app.penalty', 'app.user_faculty', 'app.role', 'app.roles_user');
+ var $fixtures = array(
+ 'app.oauth_token', 'app.user', 'app.evaluation_submission', 'app.event',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
+ 'app.event_template_type', 'app.course', 'app.group', 'app.group_event',
+ 'app.groups_member', 'app.survey', 'app.survey_group_set', 'app.survey_group',
+ 'app.survey_group_member', 'app.question', 'app.response', 'app.survey_question',
+ 'app.user_course', 'app.user_tutor', 'app.user_enrol', 'app.department',
+ 'app.faculty', 'app.course_department', 'app.penalty', 'app.user_faculty',
+ 'app.role', 'app.roles_user'
+ );
function startTest($method) {
$this->OauthToken =& ClassRegistry::init('OauthToken');
diff --git a/app/tests/cases/models/penalty.test.php b/app/tests/cases/models/penalty.test.php
index fa60553bd..1c9cf23aa 100644
--- a/app/tests/cases/models/penalty.test.php
+++ b/app/tests/cases/models/penalty.test.php
@@ -5,6 +5,8 @@ class PenaltyTestCase extends CakeTestCase
{
public $name = 'Penalty';
public $fixtures = array('app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
@@ -16,7 +18,7 @@ class PenaltyTestCase extends CakeTestCase
'app.evaluation_simple', 'app.survey_input', 'app.oauth_token',
'app.evaluation_rubric', 'app.evaluation_rubric_detail', 'app.evaluation_mixeval',
'app.evaluation_mixeval_detail'
-
+
);
public $Penalty = null;
@@ -111,7 +113,7 @@ function testGetPenaltyDays()
$ret = $this->Penalty->getPenaltyDays(999);
$this->assertEqual($ret, null);
}
-
+
function testGetPenaltyByPenaltiesAndDaysLate()
{
// valid event penalties set
@@ -124,7 +126,7 @@ function testGetPenaltyByPenaltiesAndDaysLate()
$this->assertEqual($penalties['1']['Penalty']['days_late'], 2);
$this->assertEqual($penalties['2']['Penalty']['days_late'], 3);
$this->assertEqual($penalties['3']['Penalty']['days_late'], 4);
-
+
// valid event - right on time
$ret = $this->Penalty->getPenaltyByPenaltiesAndDaysLate($penalties, 0);
$this->assertEqual($ret, null);
@@ -140,11 +142,11 @@ function testGetPenaltyByPenaltiesAndDaysLate()
// valid event - final deduction
$ret = $this->Penalty ->getPenaltyByPenaltiesAndDaysLate($penalties, 5);
$this->assertEqual($ret['Penalty']['percent_penalty'], 60);
-
+
// test inbetween penalties with several days between days late
// 1 day 15% to 4 days 60%
$penalties = array( $penalties['0'], $penalties['3'] );
-
+
// valid event between 1 amd 4 days
$ret = $this->Penalty->getPenaltyByPenaltiesAndDaysLate($penalties, 1);
$this->assertEqual($ret['Penalty']['percent_penalty'], 15);
@@ -156,8 +158,8 @@ function testGetPenaltyByPenaltiesAndDaysLate()
$this->assertEqual($ret['Penalty']['percent_penalty'], 60);
$ret = $this->Penalty->getPenaltyByPenaltiesAndDaysLate($penalties, 4);
$this->assertEqual($ret['Penalty']['percent_penalty'], 60);
-
-
+
+
// valid empty event penalties set
$penalties = $this->Penalty->getPenaltyByEventId(3);
$this->assertEqual(empty($penalties), true);
@@ -241,7 +243,7 @@ function testGetPenaltyByEventAndDaysLate()
$ret = $this->Penalty->getPenaltyByEventAndDaysLate(999, 5);
$this->assertEqual($ret, null);
}
-
+
function testGetPenaltyPercent()
{
//TODO
diff --git a/app/tests/cases/models/personalize.test.php b/app/tests/cases/models/personalize.test.php
index 8ea45f95f..85aba78e2 100644
--- a/app/tests/cases/models/personalize.test.php
+++ b/app/tests/cases/models/personalize.test.php
@@ -6,6 +6,8 @@ class PersonalizeTestCase extends CakeTestCase
public $name = 'Personalize';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/question.test.php b/app/tests/cases/models/question.test.php
index 93a6b0fab..1c2a098c1 100644
--- a/app/tests/cases/models/question.test.php
+++ b/app/tests/cases/models/question.test.php
@@ -6,6 +6,8 @@ class QuestionTestCase extends CakeTestCase
public $name = 'Question';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
@@ -55,7 +57,7 @@ function testGetTypeById()
$this->assertNull($faultyId);
$this->assertNull($nullId);
}
-
+
function testCopyQuestions()
{
}
diff --git a/app/tests/cases/models/response.test.php b/app/tests/cases/models/response.test.php
index a53fc8732..1eec7b797 100644
--- a/app/tests/cases/models/response.test.php
+++ b/app/tests/cases/models/response.test.php
@@ -6,6 +6,8 @@ class ResponseTestCase extends CakeTestCase
public $name = 'Response';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/roles_user.test.php b/app/tests/cases/models/roles_user.test.php
index c98862758..a58da6d4c 100644
--- a/app/tests/cases/models/roles_user.test.php
+++ b/app/tests/cases/models/roles_user.test.php
@@ -3,7 +3,16 @@
App::import('Model', 'RolesUser');
class RolesUserTestCase extends CakeTestCase {
- var $fixtures = array('app.roles_user', 'app.role', 'app.user', 'app.evaluation_submission', 'app.event', 'app.event_template_type', 'app.course', 'app.group', 'app.group_event', 'app.groups_member', 'app.survey', 'app.survey_group_set', 'app.survey_group', 'app.survey_group_member', 'app.question', 'app.response', 'app.survey_question', 'app.user_course', 'app.user_tutor', 'app.user_enrol', 'app.department', 'app.faculty', 'app.course_department', 'app.user_faculty');
+ var $fixtures = array(
+ 'app.roles_user', 'app.role', 'app.user', 'app.evaluation_submission',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
+ 'app.event', 'app.event_template_type', 'app.course', 'app.group',
+ 'app.group_event', 'app.groups_member', 'app.survey', 'app.survey_group_set',
+ 'app.survey_group', 'app.survey_group_member', 'app.question', 'app.response',
+ 'app.survey_question', 'app.user_course', 'app.user_tutor', 'app.user_enrol',
+ 'app.department', 'app.faculty', 'app.course_department', 'app.user_faculty'
+ );
function startTest($method) {
echo "Start RolesUser model test.\n";
diff --git a/app/tests/cases/models/rubric.test.php b/app/tests/cases/models/rubric.test.php
index fcc6bff9a..6b4cfd972 100644
--- a/app/tests/cases/models/rubric.test.php
+++ b/app/tests/cases/models/rubric.test.php
@@ -6,6 +6,8 @@ class RubricTestCase extends CakeTestCase
public $name = 'Rubric';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey',
diff --git a/app/tests/cases/models/rubric_lom.test.php b/app/tests/cases/models/rubric_lom.test.php
index db2476957..849c9a6c1 100644
--- a/app/tests/cases/models/rubric_lom.test.php
+++ b/app/tests/cases/models/rubric_lom.test.php
@@ -7,6 +7,8 @@ class RubricsLomTestCase extends CakeTestCase
public $name = 'RubricsLom';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group', 'app.survey',
diff --git a/app/tests/cases/models/rubrics_criteria.test.php b/app/tests/cases/models/rubrics_criteria.test.php
index 5a1ff61f9..508c476d7 100644
--- a/app/tests/cases/models/rubrics_criteria.test.php
+++ b/app/tests/cases/models/rubrics_criteria.test.php
@@ -7,6 +7,8 @@ class RubricsCriteriaTestCase extends CakeTestCase
public $name = 'RubricsCriteria';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group', 'app.survey',
diff --git a/app/tests/cases/models/rubrics_criteria_comment.test.php b/app/tests/cases/models/rubrics_criteria_comment.test.php
index 52c4ab0f5..c25ecee7e 100644
--- a/app/tests/cases/models/rubrics_criteria_comment.test.php
+++ b/app/tests/cases/models/rubrics_criteria_comment.test.php
@@ -7,6 +7,8 @@ class RubricsCriteriaCommentTestCase extends CakeTestCase
public $name = 'RubricsCriteriaComment';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group', 'app.survey',
diff --git a/app/tests/cases/models/simple_evaluation.test.php b/app/tests/cases/models/simple_evaluation.test.php
index 66d74648c..b9e850c1a 100644
--- a/app/tests/cases/models/simple_evaluation.test.php
+++ b/app/tests/cases/models/simple_evaluation.test.php
@@ -6,12 +6,14 @@ class SimpleEvaluationTestCase extends CakeTestCase
public $name = 'SimpleEvaluation';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
'app.survey_group_member', 'app.question',
'app.response', 'app.survey_question', 'app.user_course',
- 'app.user_enrol', 'app.groups_member', 'app.survey',
+ 'app.user_enrol', 'app.groups_member', 'app.survey',
'app.simple_evaluation', 'app.user_faculty'
);
diff --git a/app/tests/cases/models/survey.test.php b/app/tests/cases/models/survey.test.php
index 44412f5f9..7f6b2a969 100644
--- a/app/tests/cases/models/survey.test.php
+++ b/app/tests/cases/models/survey.test.php
@@ -6,6 +6,8 @@ class SurveyTestCase extends CakeTestCase
public $name = 'Survey';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey',
diff --git a/app/tests/cases/models/survey_group.test.php b/app/tests/cases/models/survey_group.test.php
index 6e8dcdb6c..cf8c67654 100644
--- a/app/tests/cases/models/survey_group.test.php
+++ b/app/tests/cases/models/survey_group.test.php
@@ -5,6 +5,8 @@ class SurveyGroupTestCase extends CakeTestCase {
public $name = 'SurveyGroup';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/survey_group_member.test.php b/app/tests/cases/models/survey_group_member.test.php
index c38f42eb7..3d3f23c29 100644
--- a/app/tests/cases/models/survey_group_member.test.php
+++ b/app/tests/cases/models/survey_group_member.test.php
@@ -6,6 +6,8 @@ class SurveyGroupMemberTestCase extends CakeTestCase
public $name = 'SurveyGroupMember';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/cases/models/survey_group_set.test.php b/app/tests/cases/models/survey_group_set.test.php
index 9322643a9..5d9da9de1 100644
--- a/app/tests/cases/models/survey_group_set.test.php
+++ b/app/tests/cases/models/survey_group_set.test.php
@@ -6,6 +6,8 @@ class SurveyGroupSetTestCase extends CakeTestCase
public $name = 'SurveyGroupSet';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
@@ -16,7 +18,7 @@ class SurveyGroupSetTestCase extends CakeTestCase
'app.faculty', 'app.user_faculty', 'app.department',
'app.course_department', 'app.sys_parameter', 'app.user_tutor',
'app.penalty', 'app.evaluation_simple', 'app.survey_input',
- 'app.oauth_token', 'app.evaluation_mixeval', 'app.evaluation_rubric',
+ 'app.oauth_token', 'app.evaluation_mixeval', 'app.evaluation_rubric',
'app.evaluation_mixeval_detail', 'app.evaluation_rubric_detail'
);
public $SurveyGroupSet = null;
diff --git a/app/tests/cases/models/survey_input.test.php b/app/tests/cases/models/survey_input.test.php
index c3271f541..38ac8e93b 100644
--- a/app/tests/cases/models/survey_input.test.php
+++ b/app/tests/cases/models/survey_input.test.php
@@ -5,6 +5,8 @@ class SurveyInputTestCase extends CakeTestCase
{
public $name = 'SurveyInput';
public $fixtures = array('app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group', 'app.penalty',
diff --git a/app/tests/cases/models/survey_question.test.php b/app/tests/cases/models/survey_question.test.php
index e352b249b..2bf3bf51b 100644
--- a/app/tests/cases/models/survey_question.test.php
+++ b/app/tests/cases/models/survey_question.test.php
@@ -6,6 +6,8 @@ class SurveyQuestionTestCase extends CakeTestCase
public $name = 'SurveyQuestion';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
@@ -136,7 +138,7 @@ function testGetLastSurveyQuestionNum()
$lastQuestionNum = $this->SurveyQuestion->getLastSurveyQuestionNum(1);
$this->assertEqual($lastQuestionNum, 2);
}
-
+
function testAssignNumber()
{
//TODO
diff --git a/app/tests/cases/models/sys_parameter.test.php b/app/tests/cases/models/sys_parameter.test.php
index 63622a6d0..4e9ab16b8 100644
--- a/app/tests/cases/models/sys_parameter.test.php
+++ b/app/tests/cases/models/sys_parameter.test.php
@@ -5,6 +5,8 @@ class SysParameterTestCase extends CakeTestCase
{
public $name = 'EvaluationSimple';
public $fixtures = array('app.course', 'app.role', 'app.user', 'app.group', 'app.sys_parameter',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
@@ -60,19 +62,19 @@ function testGet()
$result = $this->SysParameter->get('non.existing.key', 'default');
$this->assertEqual($result, 'default');
}
-
+
function testNumberSysParam()
{
$result = $this->SysParameter->find('count');
$this->assertEqual($result, 31);
-
+
$result = $this->SysParameter->find('list', array('fields' => array('SysParameter.parameter_code')));
$result_values = array_values($result);
$expected = array(
'system.super_admin', 'system.admin_email', 'display.date_format', 'system.version',
'database.version', 'email.port', 'email.host', 'email.username', 'email.password',
'display.contact_info', 'display.login.header', 'display.login.footer', 'system.absolute_url',
- 'google_analytics.tracking_id', 'google_analytics.domain', 'banner.custom_logo', 'system.timezone',
+ 'google_analytics.tracking_id', 'google_analytics.domain', 'banner.custom_logo', 'system.timezone',
'system.student_number', 'course.creation.instructions', 'system.canvas_enabled',
'system.canvas_baseurl', 'system.canvas_baseurl_ext', 'system.canvas_user_key',
'system.canvas_client_id', 'system.canvas_client_secret', 'system.canvas_force_login',
diff --git a/app/tests/cases/models/user.test.php b/app/tests/cases/models/user.test.php
index bd9966405..39f667a8d 100644
--- a/app/tests/cases/models/user.test.php
+++ b/app/tests/cases/models/user.test.php
@@ -5,6 +5,8 @@
class UserTestCase extends CakeTestCase {
var $fixtures = array(
'app.user', 'app.evaluation_submission', 'app.event',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.event_template_type', 'app.course', 'app.group',
'app.group_event', 'app.groups_member', 'app.survey',
'app.survey_group_set', 'app.survey_group', 'app.survey_group_member',
diff --git a/app/tests/cases/models/user_course.test.php b/app/tests/cases/models/user_course.test.php
index 657b3f0f6..0b55fb7f7 100644
--- a/app/tests/cases/models/user_course.test.php
+++ b/app/tests/cases/models/user_course.test.php
@@ -6,12 +6,14 @@ class UserCourseTestCase extends CakeTestCase
public $name = 'UserEnrol';
public $fixtures = array(
'app.user_course', 'app.user', 'app.evaluation_submission', 'app.event',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.event_template_type', 'app.course', 'app.group', 'app.group_event',
- 'app.evaluation_simple', 'app.survey_input', 'app.faculty',
- 'app.user_faculty', 'app.survey', 'app.survey_group_set',
- 'app.survey_group', 'app.survey_group_member', 'app.question',
+ 'app.evaluation_simple', 'app.survey_input', 'app.faculty',
+ 'app.user_faculty', 'app.survey', 'app.survey_group_set',
+ 'app.survey_group', 'app.survey_group_member', 'app.question',
'app.response', 'app.survey_question', 'app.role', 'app.roles_user',
- 'app.user_tutor', 'app.user_enrol', 'app.groups_member',
+ 'app.user_tutor', 'app.user_enrol', 'app.groups_member',
'app.department', 'app.course_department', 'app.penalty',
'app.oauth_token', 'app.evaluation_mixeval', 'app.evaluation_rubric',
'app.evaluation_mixeval_detail', 'app.evaluation_rubric_detail', 'app.sys_parameter'
diff --git a/app/tests/cases/models/user_enrol.test.php b/app/tests/cases/models/user_enrol.test.php
index 1a2c38b45..d2713d470 100644
--- a/app/tests/cases/models/user_enrol.test.php
+++ b/app/tests/cases/models/user_enrol.test.php
@@ -6,6 +6,8 @@ class UserEnrolTestCase extends CakeTestCase
public $name = 'UserEnrol';
public $fixtures = array(
'app.course', 'app.role', 'app.user', 'app.group',
+ 'app.lti_user', 'app.lti_nonce', 'app.lti_tool_registration',
+ 'app.lti_resource_link', 'app.lti_context',
'app.roles_user', 'app.event', 'app.event_template_type',
'app.group_event', 'app.evaluation_submission',
'app.survey_group_set', 'app.survey_group',
diff --git a/app/tests/fixtures/lti_context_fixture.php b/app/tests/fixtures/lti_context_fixture.php
new file mode 100644
index 000000000..c3f17436b
--- /dev/null
+++ b/app/tests/fixtures/lti_context_fixture.php
@@ -0,0 +1,15 @@
+ 'LtiContext', 'records' => true);
+}
\ No newline at end of file
diff --git a/app/tests/fixtures/lti_nonce_fixture.php b/app/tests/fixtures/lti_nonce_fixture.php
new file mode 100644
index 000000000..e5719e3c2
--- /dev/null
+++ b/app/tests/fixtures/lti_nonce_fixture.php
@@ -0,0 +1,15 @@
+ 'LtiNonce', 'records' => true);
+}
\ No newline at end of file
diff --git a/app/tests/fixtures/lti_resource_link_fixture.php b/app/tests/fixtures/lti_resource_link_fixture.php
new file mode 100644
index 000000000..c61b73fc2
--- /dev/null
+++ b/app/tests/fixtures/lti_resource_link_fixture.php
@@ -0,0 +1,15 @@
+ 'LtiResourceLink', 'records' => true);
+}
\ No newline at end of file
diff --git a/app/tests/fixtures/lti_tool_registration_fixture.php b/app/tests/fixtures/lti_tool_registration_fixture.php
new file mode 100644
index 000000000..5bf95c15c
--- /dev/null
+++ b/app/tests/fixtures/lti_tool_registration_fixture.php
@@ -0,0 +1,16 @@
+
+ * @license MIT {@link http://www.opensource.org/licenses/MIT}
+ */
+class LtiToolRegistrationFixture extends CakeTestFixture
+{
+ public $name = 'LtiToolRegistration';
+
+ public $import = array('model' => 'LtiToolRegistration', 'records' => true);
+}
\ No newline at end of file
diff --git a/app/tests/fixtures/lti_user_fixture.php b/app/tests/fixtures/lti_user_fixture.php
new file mode 100644
index 000000000..200abead7
--- /dev/null
+++ b/app/tests/fixtures/lti_user_fixture.php
@@ -0,0 +1,15 @@
+ 'LtiUser', 'records' => true);
+}
\ No newline at end of file
diff --git a/app/views/courses/home.ctp b/app/views/courses/home.ctp
index 969982ec0..4a2f89991 100644
--- a/app/views/courses/home.ctp
+++ b/app/views/courses/home.ctp
@@ -50,7 +50,6 @@ $submenuTitle = __('Students', true);
$params = array('submenu'=>$submenu, 'submenuTitle'=>$submenuTitle, 'course_id'=>$data['Course']['id']);
echo $this->element('courses/submenu', $params);
-
$submenu = 'Group';
$submenuTitle = __('Groups', true);
$params = array('controller'=>'courses', 'submenu'=>$submenu, 'submenuTitle'=>$submenuTitle, 'course_id'=>$data['Course']['id']);
@@ -68,11 +67,18 @@ if (User::hasPermission('controllers/Surveys')) {
echo $this->element('courses/submenu', $params);
}
+if ($ltiNrpsEnabled) {
+ $submenu = 'LTI';
+ $submenuTitle = __('LTI', true);
+ $params = array('controller'=>'courses', 'submenu'=>$submenu, 'submenuTitle'=>$submenuTitle, 'course_id'=>$data['Course']['id']);
+ echo $this->element('courses/submenu', $params);
+}
+
if ($canvasEnabled) {
- $submenu = 'Canvas';
- $submenuTitle = __('Canvas', true);
- $params = array('controller'=>'courses', 'submenu'=>$submenu, 'submenuTitle'=>$submenuTitle, 'course_id'=>$data['Course']['id']);
- echo $this->element('courses/submenu', $params);
+ $submenu = 'Canvas';
+ $submenuTitle = __('Canvas', true);
+ $params = array('controller'=>'courses', 'submenu'=>$submenu, 'submenuTitle'=>$submenuTitle, 'course_id'=>$data['Course']['id']);
+ echo $this->element('courses/submenu', $params);
}
?>
diff --git a/app/views/elements/courses/submenu.ctp b/app/views/elements/courses/submenu.ctp
index a72e6d99f..d1b774325 100644
--- a/app/views/elements/courses/submenu.ctp
+++ b/app/views/elements/courses/submenu.ctp
@@ -90,6 +90,13 @@ switch($submenu) {
// array('name' => 'Sync Canvas Groups', 'link' => "/groups/syncCanvas/$course_id")
// );
}
+ case "LTI":
+ if ($ltiNrpsEnabled){
+ array_push(
+ $items,
+ array('name' => 'Sync Users from LMS Course Roster', 'link' => "/lti/roster/$course_id")
+ );
+ }
break;
}
?>
diff --git a/app/views/lti/index.ctp b/app/views/lti/index.ctp
deleted file mode 100644
index d7ab116e2..000000000
--- a/app/views/lti/index.ctp
+++ /dev/null
@@ -1,10 +0,0 @@
-LTI Request failure: $invalidlti
";
-}
-else
-{
- echo "The LTI request completed successfully, but the app failed to redirect for some reason. Try clicking here to see if you're properly logged in.
";
-}
-?>
diff --git a/app/views/lti_tool_registrations/add.ctp b/app/views/lti_tool_registrations/add.ctp
new file mode 100644
index 000000000..4fc60bd14
--- /dev/null
+++ b/app/views/lti_tool_registrations/add.ctp
@@ -0,0 +1,70 @@
+
+
diff --git a/app/views/lti_tool_registrations/edit.ctp b/app/views/lti_tool_registrations/edit.ctp
new file mode 100644
index 000000000..911d6516f
--- /dev/null
+++ b/app/views/lti_tool_registrations/edit.ctp
@@ -0,0 +1,70 @@
+
diff --git a/app/views/lti_tool_registrations/index.ctp b/app/views/lti_tool_registrations/index.ctp
new file mode 100644
index 000000000..9d992e74f
--- /dev/null
+++ b/app/views/lti_tool_registrations/index.ctp
@@ -0,0 +1,47 @@
+
+
+
diff --git a/app/views/pages/admin.ctp b/app/views/pages/admin.ctp
index 83d3024d7..91eb53522 100644
--- a/app/views/pages/admin.ctp
+++ b/app/views/pages/admin.ctp
@@ -24,6 +24,15 @@ if (User::hasPermission('controllers/departments')) {
echo '';
}
+if (User::hasPermission('controllers/ltitoolregistrations')) {
+ echo '';
+ echo $this->Html->link(
+ __('LTI 1.3 Tool Registrations',true),
+ array('controller' => 'ltitoolregistrations')
+ );
+ echo '';
+}
+
if (User::hasPermission('functions/user/superadmin')) {
echo "";
echo $this->Html->link(
diff --git a/build/sqlclean/superadmin.sql b/build/sqlclean/superadmin.sql
index 51ee34879..d6f1e26e3 100644
--- a/build/sqlclean/superadmin.sql
+++ b/build/sqlclean/superadmin.sql
@@ -1,4 +1,4 @@
-INSERT INTO `users` (`id`, `username`, `password`, `first_name`, `last_name`, `student_no`, `title`, `email`, `last_login`, `last_logout`, `last_accessed`, `record_status`, `creator_id`, `created`, `updater_id`, `modified`, `lti_id`) VALUES
-(1, 'root', 'cbbde255cc20cb7a566d4c7f12298729', 'Super', 'Admin', NULL, NULL, '', NULL, NULL, NULL, 'A', 0, '2012-07-17 11:01:37', NULL, NULL, NULL);
+INSERT INTO `users` (`id`, `username`, `password`, `first_name`, `last_name`, `student_no`, `title`, `email`, `last_login`, `last_logout`, `last_accessed`, `record_status`, `creator_id`, `created`, `updater_id`, `modified`) VALUES
+(1, 'root', 'cbbde255cc20cb7a566d4c7f12298729', 'Super', 'Admin', NULL, NULL, '', NULL, NULL, NULL, 'A', 0, '2012-07-17 11:01:37', NULL, NULL);
INSERT INTO `roles_users` (`id`, `role_id`, `user_id`, `created`, `modified`) VALUES
(37, 1, 1, '2012-07-17 11:14:51', '2012-07-17 11:14:51');
diff --git a/composer.json b/composer.json
index 4b0dbf2d9..1bfab0e86 100644
--- a/composer.json
+++ b/composer.json
@@ -1,36 +1,41 @@
{
- "repositories": [
- {
- "type": "git",
- "url": "https://github.com/IMSGlobal/caliper-php"
+ "repositories": [
+ {
+ "type": "git",
+ "url": "https://github.com/IMSGlobal/caliper-php"
+ },
+ {
+ "type": "vcs",
+ "url": "https://github.com/ubc/lti-1-3-php-library"
+ }
+ ],
+ "require": {
+ "compass/cake-guard": "1.0.7",
+ "nategood/httpful": "^0.2.20",
+ "imsglobal/caliper": "dev-develop#c7e34e230abc7bbb647f8f94245cb649f6191bcd as 1.2.0",
+ "imsglobal/lti-1p3-tool": "dev-master#f863ffd3da446b0efcd062e29ccc9d7a280aec98"
+ },
+ "require-dev": {
+ "roave/security-advisories": "dev-master",
+ "phing/phing": "2.*",
+ "pdepend/pdepend": "2.*",
+ "phpmd/phpmd": "@stable",
+ "squizlabs/php_codesniffer": "2.*",
+ "sebastian/phpcpd": "*",
+ "jms/serializer": "1.7.*",
+ "phpdocumentor/phpdocumentor": "^2.9"
+ },
+ "scripts": {
+ "post-install-cmd": [
+ "[ -e app/config/database.php ] || cp app/config/database.php.default app/config/database.php",
+ "[ -L app/plugins/guard ] || [ -d app/plugins/guard ] || ln -s ../../vendor/compass/cake-guard app/plugins/guard",
+ "[ -e app/config/guard.php ] || cp app/plugins/guard/config/guard_default.php app/config/guard.php",
+ "mkdir -p app/tmp && chmod 777 app/tmp"
+ ]
+ },
+ "config": {
+ "platform": {
+ "php": "7.2"
+ }
}
- ],
- "require": {
- "compass/cake-guard": "1.0.7",
- "nategood/httpful": "^0.2.20",
- "imsglobal/caliper": "dev-develop#c7e34e230abc7bbb647f8f94245cb649f6191bcd as 1.2.0"
- },
- "require-dev": {
- "roave/security-advisories": "dev-master",
- "phing/phing": "2.*",
- "pdepend/pdepend" : "2.*",
- "phpmd/phpmd" : "@stable",
- "squizlabs/php_codesniffer": "2.*",
- "sebastian/phpcpd": "*",
- "jms/serializer": "1.7.*",
- "phpdocumentor/phpdocumentor": "^2.9"
- },
- "scripts": {
- "post-install-cmd": [
- "[ -e app/config/database.php ] || cp app/config/database.php.default app/config/database.php",
- "[ -L app/plugins/guard ] || [ -d app/plugins/guard ] || ln -s ../../vendor/compass/cake-guard app/plugins/guard",
- "[ -e app/config/guard.php ] || cp app/plugins/guard/config/guard_default.php app/config/guard.php",
- "mkdir -p app/tmp && chmod 777 app/tmp"
- ]
- },
- "config": {
- "platform": {
- "php": "7.2"
- }
- }
}
diff --git a/composer.lock b/composer.lock
index f35b9300c..db92b0bce 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "4b335c58c09584e5b513ed9b738fef15",
+ "content-hash": "05fb266e75551e6c83f2e83b9febc226",
"packages": [
{
"name": "compass/cake-guard",
@@ -37,6 +37,57 @@
"description": "Authentication Plugin for CakePHP 1.3",
"time": "2020-07-17T21:49:24+00:00"
},
+ {
+ "name": "fproject/php-jwt",
+ "version": "4.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/fproject/php-jwt.git",
+ "reference": "91047b202bbe7d966e8fce67ab16ebca8bdcb6b7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/fproject/php-jwt/zipball/91047b202bbe7d966e8fce67ab16ebca8bdcb6b7",
+ "reference": "91047b202bbe7d966e8fce67ab16ebca8bdcb6b7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.8.36"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Firebase\\JWT\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Neuman Vong",
+ "email": "neuman+pear@twilio.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Anant Narayanan",
+ "email": "anant@php.net",
+ "role": "Developer"
+ },
+ {
+ "name": "Bui Sy Nguyen",
+ "email": "nguyenbs@gmail.com",
+ "role": "Developer"
+ }
+ ],
+ "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Support several key types including JWK.",
+ "homepage": "https://github.com/fproject/php-jwt",
+ "time": "2018-04-02T10:36:30+00:00"
+ },
{
"name": "imsglobal/caliper",
"version": "dev-develop",
@@ -76,6 +127,41 @@
],
"time": "2020-01-22T19:01:21+00:00"
},
+ {
+ "name": "imsglobal/lti-1p3-tool",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ubc/lti-1-3-php-library.git",
+ "reference": "f863ffd3da446b0efcd062e29ccc9d7a280aec98"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ubc/lti-1-3-php-library/zipball/f863ffd3da446b0efcd062e29ccc9d7a280aec98",
+ "reference": "f863ffd3da446b0efcd062e29ccc9d7a280aec98",
+ "shasum": ""
+ },
+ "require": {
+ "fproject/php-jwt": "^4.0",
+ "phpseclib/phpseclib": "^2.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "IMSGlobal\\LTI\\": "src/lti"
+ }
+ },
+ "authors": [
+ {
+ "name": "Martin Lenord",
+ "email": "ims.m@rtin.dev"
+ }
+ ],
+ "support": {
+ "source": "https://github.com/ubc/lti-1-3-php-library/tree/master"
+ },
+ "time": "2020-10-21T22:59:08+00:00"
+ },
{
"name": "nategood/httpful",
"version": "0.2.20",
@@ -125,6 +211,111 @@
"restful"
],
"time": "2015-10-26T16:11:30+00:00"
+ },
+ {
+ "name": "phpseclib/phpseclib",
+ "version": "2.0.29",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpseclib/phpseclib.git",
+ "reference": "497856a8d997f640b4a516062f84228a772a48a8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/497856a8d997f640b4a516062f84228a772a48a8",
+ "reference": "497856a8d997f640b4a516062f84228a772a48a8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phing/phing": "~2.7",
+ "phpunit/phpunit": "^4.8.35|^5.7|^6.0",
+ "squizlabs/php_codesniffer": "~2.0"
+ },
+ "suggest": {
+ "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
+ "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
+ "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
+ "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "phpseclib/bootstrap.php"
+ ],
+ "psr-4": {
+ "phpseclib\\": "phpseclib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jim Wigginton",
+ "email": "terrafrost@php.net",
+ "role": "Lead Developer"
+ },
+ {
+ "name": "Patrick Monnerat",
+ "email": "pm@datasphere.ch",
+ "role": "Developer"
+ },
+ {
+ "name": "Andreas Fischer",
+ "email": "bantu@phpbb.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Hans-Jürgen Petrich",
+ "email": "petrich@tronic-media.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Graham Campbell",
+ "email": "graham@alt-three.com",
+ "role": "Developer"
+ }
+ ],
+ "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
+ "homepage": "http://phpseclib.sourceforge.net",
+ "keywords": [
+ "BigInteger",
+ "aes",
+ "asn.1",
+ "asn1",
+ "blowfish",
+ "crypto",
+ "cryptography",
+ "encryption",
+ "rsa",
+ "security",
+ "sftp",
+ "signature",
+ "signing",
+ "ssh",
+ "twofish",
+ "x.509",
+ "x509"
+ ],
+ "funding": [
+ {
+ "url": "https://github.com/terrafrost",
+ "type": "github"
+ },
+ {
+ "url": "https://www.patreon.com/phpseclib",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-09-08T04:24:43+00:00"
}
],
"packages-dev": [
@@ -248,16 +439,16 @@
},
{
"name": "composer/ca-bundle",
- "version": "1.2.7",
+ "version": "1.2.8",
"source": {
"type": "git",
"url": "https://github.com/composer/ca-bundle.git",
- "reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd"
+ "reference": "8a7ecad675253e4654ea05505233285377405215"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/ca-bundle/zipball/95c63ab2117a72f48f5a55da9740a3273d45b7fd",
- "reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd",
+ "url": "https://api.github.com/repos/composer/ca-bundle/zipball/8a7ecad675253e4654ea05505233285377405215",
+ "reference": "8a7ecad675253e4654ea05505233285377405215",
"shasum": ""
},
"require": {
@@ -305,25 +496,29 @@
"url": "https://packagist.com",
"type": "custom"
},
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
"type": "tidelift"
}
],
- "time": "2020-04-08T08:27:21+00:00"
+ "time": "2020-08-23T12:54:47+00:00"
},
{
"name": "composer/xdebug-handler",
- "version": "1.4.2",
+ "version": "1.4.4",
"source": {
"type": "git",
"url": "https://github.com/composer/xdebug-handler.git",
- "reference": "fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51"
+ "reference": "6e076a124f7ee146f2487554a94b6a19a74887ba"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51",
- "reference": "fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51",
+ "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6e076a124f7ee146f2487554a94b6a19a74887ba",
+ "reference": "6e076a124f7ee146f2487554a94b6a19a74887ba",
"shasum": ""
},
"require": {
@@ -368,7 +563,7 @@
"type": "tidelift"
}
],
- "time": "2020-06-04T11:16:35+00:00"
+ "time": "2020-10-24T12:39:10+00:00"
},
{
"name": "container-interop/container-interop",
@@ -404,16 +599,16 @@
},
{
"name": "doctrine/annotations",
- "version": "1.10.3",
+ "version": "1.11.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
- "reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d"
+ "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/annotations/zipball/5db60a4969eba0e0c197a19c077780aadbc43c5d",
- "reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d",
+ "url": "https://api.github.com/repos/doctrine/annotations/zipball/ce77a7ba1770462cd705a91a151b6c3746f9c6ad",
+ "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad",
"shasum": ""
},
"require": {
@@ -423,12 +618,14 @@
},
"require-dev": {
"doctrine/cache": "1.*",
- "phpunit/phpunit": "^7.5"
+ "doctrine/coding-standard": "^6.0 || ^8.1",
+ "phpstan/phpstan": "^0.12.20",
+ "phpunit/phpunit": "^7.5 || ^9.1.5"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.9.x-dev"
+ "dev-master": "1.11.x-dev"
}
},
"autoload": {
@@ -463,13 +660,13 @@
}
],
"description": "Docblock Annotations Parser",
- "homepage": "http://www.doctrine-project.org",
+ "homepage": "https://www.doctrine-project.org/projects/annotations.html",
"keywords": [
"annotations",
"docblock",
"parser"
],
- "time": "2020-05-25T17:24:27+00:00"
+ "time": "2020-10-26T10:28:16+00:00"
},
{
"name": "doctrine/instantiator",
@@ -525,20 +722,6 @@
"constructor",
"instantiate"
],
- "funding": [
- {
- "url": "https://www.doctrine-project.org/sponsorship.html",
- "type": "custom"
- },
- {
- "url": "https://www.patreon.com/phpdoctrine",
- "type": "patreon"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
- "type": "tidelift"
- }
- ],
"time": "2020-05-29T17:27:14+00:00"
},
{
@@ -601,20 +784,6 @@
"parser",
"php"
],
- "funding": [
- {
- "url": "https://www.doctrine-project.org/sponsorship.html",
- "type": "custom"
- },
- {
- "url": "https://www.patreon.com/phpdoctrine",
- "type": "patreon"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer",
- "type": "tidelift"
- }
- ],
"time": "2020-05-25T17:44:05+00:00"
},
{
@@ -834,16 +1003,16 @@
},
{
"name": "monolog/monolog",
- "version": "1.25.4",
+ "version": "1.25.5",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
- "reference": "3022efff205e2448b560c833c6fbbf91c3139168"
+ "reference": "1817faadd1846cd08be9a49e905dc68823bc38c0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Seldaek/monolog/zipball/3022efff205e2448b560c833c6fbbf91c3139168",
- "reference": "3022efff205e2448b560c833c6fbbf91c3139168",
+ "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1817faadd1846cd08be9a49e905dc68823bc38c0",
+ "reference": "1817faadd1846cd08be9a49e905dc68823bc38c0",
"shasum": ""
},
"require": {
@@ -917,7 +1086,7 @@
"type": "tidelift"
}
],
- "time": "2020-05-22T07:31:27+00:00"
+ "time": "2020-07-23T08:35:51+00:00"
},
{
"name": "nikic/php-parser",
@@ -1083,6 +1252,7 @@
"self-update",
"update"
],
+ "abandoned": true,
"time": "2018-03-30T12:52:15+00:00"
},
{
@@ -1130,12 +1300,6 @@
"BSD-3-Clause"
],
"description": "Official version of pdepend to be handled with Composer",
- "funding": [
- {
- "url": "https://tidelift.com/funding/github/packagist/pdepend/pdepend",
- "type": "tidelift"
- }
- ],
"time": "2020-06-20T10:53:13+00:00"
},
{
@@ -1558,16 +1722,16 @@
},
{
"name": "phpmd/phpmd",
- "version": "2.8.2",
+ "version": "2.9.1",
"source": {
"type": "git",
"url": "https://github.com/phpmd/phpmd.git",
- "reference": "714629ed782537f638fe23c4346637659b779a77"
+ "reference": "ce10831d4ddc2686c1348a98069771dd314534a8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpmd/phpmd/zipball/714629ed782537f638fe23c4346637659b779a77",
- "reference": "714629ed782537f638fe23c4346637659b779a77",
+ "url": "https://api.github.com/repos/phpmd/phpmd/zipball/ce10831d4ddc2686c1348a98069771dd314534a8",
+ "reference": "ce10831d4ddc2686c1348a98069771dd314534a8",
"shasum": ""
},
"require": {
@@ -1578,6 +1742,8 @@
},
"require-dev": {
"easy-doc/easy-doc": "0.0.0 || ^1.3.2",
+ "ext-json": "*",
+ "ext-simplexml": "*",
"gregwar/rst": "^1.0",
"mikey179/vfsstream": "^1.6.4",
"phpunit/phpunit": "^4.8.36 || ^5.7.27",
@@ -1624,28 +1790,34 @@
"phpmd",
"pmd"
],
- "time": "2020-02-16T20:15:50+00:00"
+ "funding": [
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpmd/phpmd",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-09-23T22:06:32+00:00"
},
{
"name": "phpoption/phpoption",
- "version": "1.7.4",
+ "version": "1.7.5",
"source": {
"type": "git",
"url": "https://github.com/schmittjoh/php-option.git",
- "reference": "b2ada2ad5d8a32b89088b8adc31ecd2e3a13baf3"
+ "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/b2ada2ad5d8a32b89088b8adc31ecd2e3a13baf3",
- "reference": "b2ada2ad5d8a32b89088b8adc31ecd2e3a13baf3",
+ "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/994ecccd8f3283ecf5ac33254543eb0ac946d525",
+ "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525",
"shasum": ""
},
"require": {
"php": "^5.5.9 || ^7.0 || ^8.0"
},
"require-dev": {
- "bamarni/composer-bin-plugin": "^1.3",
- "phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0 || ^7.0"
+ "bamarni/composer-bin-plugin": "^1.4.1",
+ "phpunit/phpunit": "^4.8.35 || ^5.7.27 || ^6.5.6 || ^7.0 || ^8.0 || ^9.0"
},
"type": "library",
"extra": {
@@ -1689,7 +1861,7 @@
"type": "tidelift"
}
],
- "time": "2020-06-07T10:40:07+00:00"
+ "time": "2020-07-20T17:29:33+00:00"
},
{
"name": "phpunit/php-timer",
@@ -1982,12 +2154,12 @@
"source": {
"type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git",
- "reference": "9f386dba391018e90a5f1e51abeffc6bf27583db"
+ "reference": "327370943772f9917bc2dc2aa4263db2d572a112"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/9f386dba391018e90a5f1e51abeffc6bf27583db",
- "reference": "9f386dba391018e90a5f1e51abeffc6bf27583db",
+ "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/327370943772f9917bc2dc2aa4263db2d572a112",
+ "reference": "327370943772f9917bc2dc2aa4263db2d572a112",
"shasum": ""
},
"conflict": {
@@ -2003,6 +2175,7 @@
"bagisto/bagisto": "<0.1.5",
"barrelstrength/sprout-base-email": "<1.2.7",
"barrelstrength/sprout-forms": "<3.9",
+ "baserproject/basercms": ">=4,<=4.3.6",
"bolt/bolt": "<3.7.1",
"brightlocal/phpwhois": "<=4.2.5",
"buddypress/buddypress": "<5.1.2",
@@ -2016,10 +2189,11 @@
"composer/composer": "<=1-alpha.11",
"contao-components/mediaelement": ">=2.14.2,<2.21.1",
"contao/core": ">=2,<3.5.39",
- "contao/core-bundle": ">=4,<4.4.46|>=4.5,<4.8.6",
+ "contao/core-bundle": ">=4,<4.4.52|>=4.5,<4.9.6|= 4.10.0",
"contao/listing-bundle": ">=4,<4.4.8",
"datadog/dd-trace": ">=0.30,<0.30.2",
"david-garcia/phpwhois": "<=4.3.1",
+ "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1",
"doctrine/annotations": ">=1,<1.2.7",
"doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2",
"doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1",
@@ -2031,8 +2205,8 @@
"doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1",
"dolibarr/dolibarr": "<11.0.4",
"dompdf/dompdf": ">=0.6,<0.6.2",
- "drupal/core": ">=7,<7.72|>=8,<8.8.8|>=8.9,<8.9.1|>=9,<9.0.1",
- "drupal/drupal": ">=7,<7.72|>=8,<8.8.8|>=8.9,<8.9.1|>=9,<9.0.1",
+ "drupal/core": ">=7,<7.73|>=8,<8.8.10|>=8.9,<8.9.6|>=9,<9.0.6",
+ "drupal/drupal": ">=7,<7.73|>=8,<8.8.10|>=8.9,<8.9.6|>=9,<9.0.6",
"endroid/qr-code-bundle": "<3.4.2",
"enshrined/svg-sanitize": "<0.13.1",
"erusev/parsedown": "<1.7.2",
@@ -2041,11 +2215,12 @@
"ezsystems/ezfind-ls": ">=5.3,<5.3.6.1|>=5.4,<5.4.11.1|>=2017.12,<2017.12.0.1",
"ezsystems/ezplatform": ">=1.7,<1.7.9.1|>=1.13,<1.13.5.1|>=2.5,<2.5.4",
"ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6",
- "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2",
+ "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1",
"ezsystems/ezplatform-kernel": ">=1,<1.0.2.1",
"ezsystems/ezplatform-user": ">=1,<1.0.1",
"ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.14.2|>=6,<6.7.9.1|>=6.8,<6.13.6.3|>=7,<7.2.4.1|>=7.3,<7.3.2.1|>=7.5,<7.5.7.1",
- "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.1|>=2011,<2017.12.7.2|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.4.2",
+ "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.2|>=2011,<2017.12.7.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.5.1",
+ "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3",
"ezsystems/repository-forms": ">=2.3,<2.3.2.1",
"ezyang/htmlpurifier": "<4.1.1",
"firebase/php-jwt": "<2",
@@ -2054,6 +2229,7 @@
"friendsofsymfony/oauth2-php": "<1.3",
"friendsofsymfony/rest-bundle": ">=1.2,<1.2.2",
"friendsofsymfony/user-bundle": ">=1.2,<1.3.5",
+ "friendsoftypo3/mediace": ">=7.6.2,<7.6.5",
"fuel/core": "<1.8.1",
"getgrav/grav": "<1.7-beta.8",
"gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3",
@@ -2061,8 +2237,8 @@
"gregwar/rst": "<1.0.3",
"guzzlehttp/guzzle": ">=4-rc.2,<4.2.4|>=5,<5.3.1|>=6,<6.2.1",
"illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10",
- "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30",
- "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29",
+ "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.31|>=7,<7.22.4",
+ "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29|>=5.5,<=5.5.44|>=6,<6.18.34|>=7,<7.23.2",
"illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15",
"illuminate/view": ">=7,<7.1.2",
"ivankristianto/phpwhois": "<=4.3",
@@ -2070,24 +2246,35 @@
"joomla/session": "<1.3.1",
"jsmitty12/phpwhois": "<5.1",
"kazist/phpwhois": "<=4.2.6",
+ "kitodo/presentation": "<3.1.2",
"kreait/firebase-php": ">=3.2,<3.8.1",
"la-haute-societe/tcpdf": "<6.2.22",
- "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30|>=7,<7.1.2",
+ "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.34|>=7,<7.23.2",
"laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10",
"league/commonmark": "<0.18.3",
"librenms/librenms": "<1.53",
+ "livewire/livewire": ">2.2.4,<2.2.6",
"magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3",
"magento/magento1ce": "<1.9.4.3",
"magento/magento1ee": ">=1,<1.14.4.3",
"magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2",
+ "marcwillmann/turn": "<0.3.3",
+ "mediawiki/core": ">=1.31,<1.31.4|>=1.32,<1.32.4|>=1.33,<1.33.1",
+ "mittwald/typo3_forum": "<1.2.1",
"monolog/monolog": ">=1.8,<1.12",
"namshi/jose": "<2.2",
+ "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6",
+ "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13",
"nystudio107/craft-seomatic": "<3.3",
"nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1",
- "october/october": ">=1.0.319,<1.0.467",
+ "october/backend": ">=1.0.319,<1.0.467",
+ "october/cms": ">=1.0.319,<1.0.466",
+ "october/october": ">=1.0.319,<1.0.466",
+ "october/rain": ">=1.0.319,<1.0.468",
"onelogin/php-saml": "<2.10.4",
"oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5",
"openid/php-openid": "<2.3",
+ "openmage/magento-lts": "<19.4.6|>=20,<20.0.2",
"oro/crm": ">=1.7,<1.7.4",
"oro/platform": ">=1.7,<1.7.4",
"padraic/humbug_get_contents": "<1.1.2",
@@ -2095,6 +2282,7 @@
"paragonie/random_compat": "<2",
"paypal/merchant-sdk-php": "<3.12",
"pear/archive_tar": "<1.4.4",
+ "personnummer/personnummer": "<3.0.2",
"phpfastcache/phpfastcache": ">=5,<5.0.13",
"phpmailer/phpmailer": "<6.1.6",
"phpmussel/phpmussel": ">=1,<1.6",
@@ -2106,18 +2294,23 @@
"phpxmlrpc/extras": "<0.6.1",
"pimcore/pimcore": "<6.3",
"prestashop/autoupgrade": ">=4,<4.10.1",
+ "prestashop/contactform": ">1.0.1,<4.3",
"prestashop/gamification": "<2.3.2",
"prestashop/ps_facetedsearch": "<3.4.1",
"privatebin/privatebin": "<1.2.2|>=1.3,<1.3.2",
"propel/propel": ">=2-alpha.1,<=2-alpha.7",
"propel/propel1": ">=1,<=1.7.1",
+ "pterodactyl/panel": "<0.7.19|>=1-rc.0,<=1-rc.6",
"pusher/pusher-php-server": "<2.2.1",
"rainlab/debugbar-plugin": "<3.1",
"robrichards/xmlseclibs": "<3.0.4",
+ "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1",
"sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9",
"scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11",
"sensiolabs/connect": "<4.2.3",
"serluck/phpwhois": "<=4.2.6",
+ "shopware/core": "<=6.3.1",
+ "shopware/platform": "<=6.3.1",
"shopware/shopware": "<5.3.7",
"silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1",
"silverstripe/assets": ">=1,<1.4.7|>=1.5,<1.5.2",
@@ -2144,11 +2337,12 @@
"ssddanbrown/bookstack": "<0.29.2",
"stormpath/sdk": ">=0,<9.9.99",
"studio-42/elfinder": "<2.1.49",
+ "sulu/sulu": "<1.6.34|>=2,<2.0.10|>=2.1,<2.1.1",
"swiftmailer/swiftmailer": ">=4,<5.4.5",
"sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2",
"sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1",
"sylius/grid-bundle": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1",
- "sylius/resource-bundle": "<1.3.13|>=1.4,<1.4.6|>=1.5,<1.5.1|>=1.6,<1.6.3",
+ "sylius/resource-bundle": "<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4",
"sylius/sylius": "<1.3.16|>=1.4,<1.4.12|>=1.5,<1.5.9|>=1.6,<1.6.5",
"symbiote/silverstripe-multivaluefield": ">=3,<3.0.99",
"symbiote/silverstripe-versionedfiles": "<=2.0.3",
@@ -2158,7 +2352,7 @@
"symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1",
"symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7",
"symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7",
- "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8",
+ "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5",
"symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13",
"symfony/mime": ">=4.3,<4.3.8",
"symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7",
@@ -2173,7 +2367,7 @@
"symfony/security-guard": ">=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11",
"symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7",
"symfony/serializer": ">=2,<2.0.11",
- "symfony/symfony": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7",
+ "symfony/symfony": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5",
"symfony/translation": ">=2,<2.0.17",
"symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3",
"symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8",
@@ -2187,11 +2381,12 @@
"titon/framework": ">=0,<9.9.99",
"truckersmp/phpwhois": "<=4.3.1",
"twig/twig": "<1.38|>=2,<2.7",
- "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.30|>=9,<9.5.17|>=10,<10.4.2",
- "typo3/cms-core": ">=8,<8.7.30|>=9,<9.5.17|>=10,<10.4.2",
+ "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.30|>=9,<9.5.20|>=10,<10.4.6",
+ "typo3/cms-core": ">=8,<8.7.30|>=9,<9.5.20|>=10,<10.4.6",
"typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5",
"typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4",
"typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1",
+ "typo3fluid/fluid": ">=2,<2.0.5|>=2.1,<2.1.4|>=2.2,<2.2.1|>=2.3,<2.3.5|>=2.4,<2.4.1|>=2.5,<2.5.5|>=2.6,<2.6.1",
"ua-parser/uap-php": "<3.8",
"usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2",
"verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4",
@@ -2199,7 +2394,7 @@
"willdurand/js-translation-bundle": "<2.1.1",
"yii2mod/yii2-cms": "<1.9.2",
"yiisoft/yii": ">=1.1.14,<1.1.15",
- "yiisoft/yii2": "<2.0.15",
+ "yiisoft/yii2": "<2.0.38",
"yiisoft/yii2-bootstrap": "<2.0.4",
"yiisoft/yii2-dev": "<2.0.15",
"yiisoft/yii2-elasticsearch": "<2.0.5",
@@ -2261,7 +2456,7 @@
"type": "tidelift"
}
],
- "time": "2020-07-16T05:17:29+00:00"
+ "time": "2020-10-19T07:02:45+00:00"
},
{
"name": "sebastian/finder-facade",
@@ -2304,6 +2499,7 @@
],
"description": "FinderFacade is a convenience wrapper for Symfony's Finder component.",
"homepage": "https://github.com/sebastianbergmann/finder-facade",
+ "abandoned": true,
"time": "2020-01-16T08:08:45+00:00"
},
{
@@ -2876,20 +3072,20 @@
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.18.0",
+ "version": "v1.20.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "1c302646f6efc070cd46856e600e5e0684d6b454"
+ "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454",
- "reference": "1c302646f6efc070cd46856e600e5e0684d6b454",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f4ba089a5b6366e453971d3aad5fe8e897b37f41",
+ "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=7.1"
},
"suggest": {
"ext-ctype": "For best performance"
@@ -2897,7 +3093,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.18-dev"
+ "dev-main": "1.20-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -2948,24 +3144,24 @@
"type": "tidelift"
}
],
- "time": "2020-07-14T12:35:20+00:00"
+ "time": "2020-10-23T14:02:19+00:00"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.18.0",
+ "version": "v1.20.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a"
+ "reference": "39d483bdf39be819deabf04ec872eb0b2410b531"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/a6977d63bf9a0ad4c65cd352709e230876f9904a",
- "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/39d483bdf39be819deabf04ec872eb0b2410b531",
+ "reference": "39d483bdf39be819deabf04ec872eb0b2410b531",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=7.1"
},
"suggest": {
"ext-mbstring": "For best performance"
@@ -2973,7 +3169,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.18-dev"
+ "dev-main": "1.20-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -3025,7 +3221,7 @@
"type": "tidelift"
}
],
- "time": "2020-07-14T12:35:20+00:00"
+ "time": "2020-10-23T14:02:19+00:00"
},
{
"name": "symfony/process",
@@ -3305,16 +3501,16 @@
},
{
"name": "twig/twig",
- "version": "v1.43.0",
+ "version": "v1.43.1",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
- "reference": "597a03e85a60af6feee4f5127f3ef4279a1694c3"
+ "reference": "2311602f6a208715252febe682fa7c38e56a3373"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/twigphp/Twig/zipball/597a03e85a60af6feee4f5127f3ef4279a1694c3",
- "reference": "597a03e85a60af6feee4f5127f3ef4279a1694c3",
+ "url": "https://api.github.com/repos/twigphp/Twig/zipball/2311602f6a208715252febe682fa7c38e56a3373",
+ "reference": "2311602f6a208715252febe682fa7c38e56a3373",
"shasum": ""
},
"require": {
@@ -3366,18 +3562,6 @@
"templating"
],
"funding": [
- {
- "url": "https://certification.symfony.com/",
- "type": "custom"
- },
- {
- "url": "https://live.symfony.com/",
- "type": "custom"
- },
- {
- "url": "https://symfony.com/cloud/",
- "type": "custom"
- },
{
"url": "https://github.com/fabpot",
"type": "github"
@@ -3387,7 +3571,7 @@
"type": "tidelift"
}
],
- "time": "2020-07-05T13:00:49+00:00"
+ "time": "2020-08-05T15:05:05+00:00"
},
{
"name": "webmozart/assert",
@@ -4180,6 +4364,7 @@
"minimum-stability": "stable",
"stability-flags": {
"imsglobal/caliper": 20,
+ "imsglobal/lti-1p3-tool": 20,
"roave/security-advisories": 20,
"phpmd/phpmd": 0
},
diff --git a/docker-compose.yml b/docker-compose.yml
index 0fcc614f7..b64389998 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,7 +1,7 @@
version: '3'
services:
db:
- image: mariadb:10.4
+ image: mariadb:10.5
container_name: ipeer_db
environment:
- MYSQL_ROOT_PASSWORD=randompassword
@@ -43,9 +43,7 @@ services:
worker: &worker
<<: *app
container_name: ipeer_worker
- command: cake/console/cake worker run
- ports:
- - "9002:9000"
+ command: bash -c "sleep 5 && cake/console/cake worker run"
web:
image: nginx:1.19-alpine
container_name: ipeer_web
@@ -59,15 +57,13 @@ services:
# for running unit tests
app-unittest:
- image: ubcctlt/ipeer-app
+ image: ubcctlt/ipeer-app-unittest
build:
context: .
dockerfile: Dockerfile-app-unittest
container_name: ipeer_app_unittest
volumes:
- .:/var/www/html
- ports:
- - "9001:9000"
environment:
- IPEER_DB_HOST=db
- IPEER_DB_USER=ipeer
diff --git a/readme.md b/readme.md
index 825ebd288..d82f7d34b 100644
--- a/readme.md
+++ b/readme.md
@@ -201,9 +201,11 @@ You may optionally override the user default IRI (from `$base_url/users/view/$us
`CALIPER_ACTOR_UNIQUE_IDENTIFIER_PARAM`: Optionally set the actor's unique identifier using any column from the `user` table (ex: `username`, `id`, `email`). Will be inserted into the `CALIPER_ACTOR_BASE_URL` string.
+
iPeer 3.4.9
-----------
* Fix unsecure form submission when deployed load balancer with SSL offload (#663)
+* Added LTI 1.3
iPeer 3.4.8
-----------
@@ -666,4 +668,4 @@ any suggestion or question? please let us know
troubleshooting:
-if you type http://yourserverpath/youripeerpath/ and you get http://yourserverpath/loginout/login, your mod_rewrite
-is not set up properly. make sure the line in http.conf has 'AllowOverride All'.
+is not set up properly. make sure the line in http.conf has 'AllowOverride All'.
\ No newline at end of file
diff --git a/version.txt b/version.txt
index 7921bd0c8..7bcbb3808 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-3.4.8
+3.4.9