Skip to content

Commit

Permalink
MDL-32387 add paypal enrolment expiration action
Browse files Browse the repository at this point in the history
  • Loading branch information
skodak committed Jan 12, 2013
1 parent ca48fe5 commit d9a707a
Show file tree
Hide file tree
Showing 6 changed files with 380 additions and 1 deletion.
75 changes: 75 additions & 0 deletions enrol/paypal/cli/sync.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* PayPal CLI tool.
*
* Notes:
* - it is required to use the web server account when executing PHP CLI scripts
* - you need to change the "www-data" to match the apache user account
* - use "su" if "sudo" not available
*
* @package enrol_paypal
* @copyright 2012 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

define('CLI_SCRIPT', true);

require(__DIR__.'/../../../config.php');
require_once("$CFG->libdir/clilib.php");

// Now get cli options.
list($options, $unrecognized) = cli_get_params(array('verbose'=>false, 'help'=>false), array('v'=>'verbose', 'h'=>'help'));

if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}

if ($options['help']) {
$help =
"Process PayPal expiration sync
Options:
-v, --verbose Print verbose progress information
-h, --help Print out this help
Example:
\$ sudo -u www-data /usr/bin/php enrol/paypal/cli/sync.php
";

echo $help;
die;
}

if (!enrol_is_enabled('paypal')) {
echo('enrol_paypal plugin is disabled'."\n");
exit(2);
}

if (empty($options['verbose'])) {
$trace = new null_progress_trace();
} else {
$trace = new text_progress_trace();
}

/** @var $plugin enrol_paypal_plugin */
$plugin = enrol_get_plugin('paypal');

$result = $plugin->sync($trace);

exit($result);
2 changes: 2 additions & 0 deletions enrol/paypal/lang/en/enrol_paypal.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
$string['enrolperiod_help'] = 'Length of time that the enrolment is valid, starting with the moment the user is enrolled. If disabled, the enrolment duration will be unlimited.';
$string['enrolstartdate'] = 'Start date';
$string['enrolstartdate_help'] = 'If enabled, users can be enrolled from this date onward only.';
$string['expiredaction'] = 'Enrolment expiration action';
$string['expiredaction_help'] = 'Select action to carry out when user enrolment expires. Please note that some user data and settings are purged from course during course unenrolment.';
$string['mailadmins'] = 'Notify admin';
$string['mailstudents'] = 'Notify students';
$string['mailteachers'] = 'Notify teachers';
Expand Down
121 changes: 121 additions & 0 deletions enrol/paypal/lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -283,4 +283,125 @@ public function get_user_enrolment_actions(course_enrolment_manager $manager, $u
}
return $actions;
}

public function cron() {
$trace = new text_progress_trace();
$this->process_expirations($trace);
}

/**
* Execute synchronisation.
* @param progress_trace $trace
* @return int exit code, 0 means ok
*/
public function sync(progress_trace $trace) {
$this->process_expirations($trace);
return 0;
}

/**
* Do any enrolment expiration processing.
*
* @param progress_trace $trace
* @return bool true if any data processed, false if not
*/
protected function process_expirations(progress_trace $trace) {
global $DB;

//TODO: this method should be moved to parent class once we refactor all existing enrols, see MDL-36504.

$processed = false;
$name = $this->get_name();

// Deal with expired accounts.
$action = $this->get_config('expiredaction', ENROL_EXT_REMOVED_KEEP);

if ($action == ENROL_EXT_REMOVED_UNENROL) {
$instances = array();
$sql = "SELECT ue.*, e.courseid, c.id AS contextid
FROM {user_enrolments} ue
JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = :enrol)
JOIN {context} c ON (c.instanceid = e.courseid AND c.contextlevel = :courselevel)
WHERE ue.timeend > 0 AND ue.timeend < :now";
$params = array('now'=>time(), 'courselevel'=>CONTEXT_COURSE, 'enrol'=>$name);

$rs = $DB->get_recordset_sql($sql, $params);
foreach ($rs as $ue) {
if (!$processed) {
$trace->output("Starting processing of enrol_$name expirations...");
$processed = true;
}
if (empty($instances[$ue->enrolid])) {
$instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
}
$instance = $instances[$ue->enrolid];
if (!$this->roles_protected()) {
// Let's just guess what extra roles are supposed to be removed.
if ($instance->roleid) {
role_unassign($instance->roleid, $ue->userid, $ue->contextid);
}
}
// The unenrol cleans up all subcontexts if this is the only course enrolment for this user.
$this->unenrol_user($instance, $ue->userid);
$trace->output("Unenrolling expired user $ue->userid from course $instance->courseid", 1);
}
$rs->close();
unset($instances);

} else if ($action == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
$instances = array();
$sql = "SELECT ue.*, e.courseid, c.id AS contextid
FROM {user_enrolments} ue
JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = :enrol)
JOIN {context} c ON (c.instanceid = e.courseid AND c.contextlevel = :courselevel)
WHERE ue.timeend > 0 AND ue.timeend < :now
AND ue.status = :useractive";
$params = array('now'=>time(), 'courselevel'=>CONTEXT_COURSE, 'useractive'=>ENROL_USER_ACTIVE, 'enrol'=>$name);
$rs = $DB->get_recordset_sql($sql, $params);
foreach ($rs as $ue) {
if (!$processed) {
$trace->output("Starting processing of enrol_$name expirations...");
$processed = true;
}
if (empty($instances[$ue->enrolid])) {
$instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
}
$instance = $instances[$ue->enrolid];

if (!$this->roles_protected()) {
// Let's just guess what roles should be removed.
$count = $DB->count_records('role_assignments', array('userid'=>$ue->userid, 'contextid'=>$ue->contextid));
if ($count == 1) {
role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$ue->contextid, 'component'=>'', 'itemid'=>0));

} else if ($count > 1 and $instance->roleid) {
role_unassign($instance->roleid, $ue->userid, $ue->contextid, '', 0);
}
}
// In any case remove all roles that belong to this instance and user.
role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$ue->contextid, 'component'=>'enrol_'.$name, 'itemid'=>$instance->id), true);
// Final cleanup of subcontexts if there are no more course roles.
if (0 == $DB->count_records('role_assignments', array('userid'=>$ue->userid, 'contextid'=>$ue->contextid))) {
role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$ue->contextid, 'component'=>'', 'itemid'=>0), true);
}

$this->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
$trace->output("Suspending expired user $ue->userid in course $instance->courseid", 1);
}
$rs->close();
unset($instances);

} else {
// ENROL_EXT_REMOVED_KEEP means no changes.
}

if ($processed) {
$trace->output("...finished processing of enrol_$name expirations");
} else {
$trace->output("No expired enrol_$name enrolments detected");
}
$trace->finished();

return $processed;
}
}
9 changes: 9 additions & 0 deletions enrol/paypal/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@

$settings->add(new admin_setting_configcheckbox('enrol_paypal/mailadmins', get_string('mailadmins', 'enrol_paypal'), '', 0));

// Note: let's reuse the ext sync constants and strings here, internally it is very similar,
// it describes what should happen when users are not supposed to be enrolled any more.
$options = array(
ENROL_EXT_REMOVED_KEEP => get_string('extremovedkeep', 'enrol'),
ENROL_EXT_REMOVED_SUSPENDNOROLES => get_string('extremovedsuspendnoroles', 'enrol'),
ENROL_EXT_REMOVED_UNENROL => get_string('extremovedunenrol', 'enrol'),
);
$settings->add(new admin_setting_configselect('enrol_paypal/expiredaction', get_string('expiredaction', 'enrol_paypal'), get_string('expiredaction_help', 'enrol_paypal'), ENROL_EXT_REMOVED_SUSPENDNOROLES, $options));

//--- enrol instance defaults ----------------------------------------------------------------------------
$settings->add(new admin_setting_heading('enrol_paypal_defaults',
get_string('enrolinstancedefaults', 'admin'), get_string('enrolinstancedefaults_desc', 'admin')));
Expand Down
171 changes: 171 additions & 0 deletions enrol/paypal/tests/paypal_test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* paypal enrolment plugin tests.
*
* @package enrol_paypal
* @category phpunit
* @copyright 2012 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

defined('MOODLE_INTERNAL') || die();


class enrol_paypal_testcase extends advanced_testcase {

protected function enable_plugin() {
$enabled = enrol_get_plugins(true);
$enabled['paypal'] = true;
$enabled = array_keys($enabled);
set_config('enrol_plugins_enabled', implode(',', $enabled));
}

protected function disable_plugin() {
$enabled = enrol_get_plugins(true);
unset($enabled['paypal']);
$enabled = array_keys($enabled);
set_config('enrol_plugins_enabled', implode(',', $enabled));
}

public function test_basics() {
$this->assertFalse(enrol_is_enabled('paypal'));
$plugin = enrol_get_plugin('paypal');
$this->assertInstanceOf('enrol_paypal_plugin', $plugin);
$this->assertEquals(ENROL_EXT_REMOVED_SUSPENDNOROLES, get_config('enrol_paypal', 'expiredaction'));
}

public function test_sync_nothing() {
$this->resetAfterTest();

$this->enable_plugin();
$paypalplugin = enrol_get_plugin('paypal');

// Just make sure the sync does not throw any errors when nothing to do.
$paypalplugin->sync(new null_progress_trace());
}

public function test_expired() {
global $DB;
$this->resetAfterTest();

/** @var enrol_paypal_plugin $paypalplugin */
$paypalplugin = enrol_get_plugin('paypal');
/** @var enrol_manual_plugin $manualplugin */
$manualplugin = enrol_get_plugin('manual');
$this->assertNotEmpty($manualplugin);

$now = time();
$trace = new null_progress_trace();
$this->enable_plugin();


// Prepare some data.

$studentrole = $DB->get_record('role', array('shortname'=>'student'));
$this->assertNotEmpty($studentrole);
$teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
$this->assertNotEmpty($teacherrole);
$managerrole = $DB->get_record('role', array('shortname'=>'manager'));
$this->assertNotEmpty($managerrole);

$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$user3 = $this->getDataGenerator()->create_user();
$user4 = $this->getDataGenerator()->create_user();

$course1 = $this->getDataGenerator()->create_course();
$course2 = $this->getDataGenerator()->create_course();
$context1 = context_course::instance($course1->id);
$context2 = context_course::instance($course2->id);

$data = array('roleid'=>$studentrole->id, 'courseid'=>$course1->id);
$id = $paypalplugin->add_instance($course1, $data);
$instance1 = $DB->get_record('enrol', array('id'=>$id));
$data = array('roleid'=>$studentrole->id, 'courseid'=>$course2->id);
$id = $paypalplugin->add_instance($course2, $data);
$instance2 = $DB->get_record('enrol', array('id'=>$id));
$data = array('roleid'=>$teacherrole->id, 'courseid'=>$course2->id);
$id = $paypalplugin->add_instance($course2, $data);
$instance3 = $DB->get_record('enrol', array('id'=>$id));

$maninstance1 = $DB->get_record('enrol', array('courseid'=>$course2->id, 'enrol'=>'manual'), '*', MUST_EXIST);

$manualplugin->enrol_user($maninstance1, $user3->id, $studentrole->id);

$this->assertEquals(1, $DB->count_records('user_enrolments'));
$this->assertEquals(1, $DB->count_records('role_assignments'));
$this->assertEquals(1, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id)));

$paypalplugin->enrol_user($instance1, $user1->id, $studentrole->id);
$paypalplugin->enrol_user($instance1, $user2->id, $studentrole->id);
$paypalplugin->enrol_user($instance1, $user3->id, $studentrole->id, 0, $now-60);

$paypalplugin->enrol_user($instance2, $user1->id, $studentrole->id, 0, 0);
$paypalplugin->enrol_user($instance2, $user2->id, $studentrole->id, 0, $now-60*60);
$paypalplugin->enrol_user($instance2, $user3->id, $studentrole->id, 0, $now+60*60);

$paypalplugin->enrol_user($instance3, $user1->id, $teacherrole->id, $now-60*60*24*7, $now-60);
$paypalplugin->enrol_user($instance3, $user4->id, $teacherrole->id);

role_assign($managerrole->id, $user3->id, $context1->id);

$this->assertEquals(9, $DB->count_records('user_enrolments'));
$this->assertEquals(9, $DB->count_records('role_assignments'));
$this->assertEquals(6, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id)));
$this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$teacherrole->id)));
$this->assertEquals(1, $DB->count_records('role_assignments', array('roleid'=>$managerrole->id)));

// Execute tests.

$paypalplugin->set_config('expiredaction', ENROL_EXT_REMOVED_KEEP);
$code = $paypalplugin->sync($trace);
$this->assertSame(0, $code);
$this->assertEquals(9, $DB->count_records('user_enrolments'));
$this->assertEquals(9, $DB->count_records('role_assignments'));


$paypalplugin->set_config('expiredaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
$paypalplugin->sync($trace);
$this->assertEquals(9, $DB->count_records('user_enrolments'));
$this->assertEquals(6, $DB->count_records('role_assignments'));
$this->assertEquals(4, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id)));
$this->assertEquals(1, $DB->count_records('role_assignments', array('roleid'=>$teacherrole->id)));
$this->assertFalse($DB->record_exists('role_assignments', array('contextid'=>$context1->id, 'userid'=>$user3->id, 'roleid'=>$studentrole->id)));
$this->assertFalse($DB->record_exists('role_assignments', array('contextid'=>$context2->id, 'userid'=>$user2->id, 'roleid'=>$studentrole->id)));
$this->assertFalse($DB->record_exists('role_assignments', array('contextid'=>$context2->id, 'userid'=>$user1->id, 'roleid'=>$teacherrole->id)));
$this->assertTrue($DB->record_exists('role_assignments', array('contextid'=>$context2->id, 'userid'=>$user1->id, 'roleid'=>$studentrole->id)));


$paypalplugin->set_config('expiredaction', ENROL_EXT_REMOVED_UNENROL);
role_assign($studentrole->id, $user3->id, $context1->id);
role_assign($studentrole->id, $user2->id, $context2->id);
role_assign($teacherrole->id, $user1->id, $context2->id);
$this->assertEquals(9, $DB->count_records('user_enrolments'));
$this->assertEquals(9, $DB->count_records('role_assignments'));
$this->assertEquals(6, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id)));
$this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$teacherrole->id)));
$paypalplugin->sync($trace);
$this->assertEquals(6, $DB->count_records('user_enrolments'));
$this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user3->id)));
$this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance2->id, 'userid'=>$user2->id)));
$this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user1->id)));
$this->assertEquals(5, $DB->count_records('role_assignments'));
$this->assertEquals(4, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id)));
$this->assertEquals(1, $DB->count_records('role_assignments', array('roleid'=>$teacherrole->id)));
}
}
Loading

0 comments on commit d9a707a

Please sign in to comment.