ORVSD
Archived Posts from this Category
Archived Posts from this Category
Posted by Greg on 30 Apr 2008 | Tagged as: ORVSD, planetosl
Wow. I am amazed at how quickly teachers are latching onto the Oregon Virtual School District stuff.
Since I set up a system to automatically create school Moodle servers on demand, 109 Moodle instances have been spawned on the shared-code Moodle system. That means at least one teacher from 109 different public schools and ESDs in Oregon has been interested enough in the ORVSD offerings to give it a try. Of course, only a small number of them are far enough along to be using it with their students, but there are quite a few teachers getting up to speed with how the tools work. I’m delighted to see the system seems to be scaling up remarkably well. It’s not having any problem at all dealing with so many separate vhosts/databases running on the same Moodle install.
I expect we’re going to see an explosion of use by the end of the summer and beginning of next fall. I guess I better get those disk arrays ordered … we’re probably going to need a lot more disk space soon.
Posted by Greg on 10 Mar 2008 | Tagged as: ORVSD, howto, learning management systems, planetosl, sysadmin
When I first started working with Moodle servers, one of the things that bugged me was the fact that it required a complete install of the code for every site hosted on the system. While that’s fine for most circumstances, it really did not work well in our environment where we’re looking at potentially hosting hundreds of Moodle instances. So, in the fine open source tradition of scratching an itch by finding something someone else has done, modifying it, and then sharing it with the world … I give you shared-code Moodle, OSL-style.
First, though, credit where credit is due. Martin Langhoff posted almost all of what we needed to do here. All I needed to do is expand upon it to fit our needs.
Second, what the modified code actually does:
1) config.php looks in Moodle dirroot/multisite_config for an ini file matching the server name. I.E.: fqdn.domain.org.ini
2) If found, the ini file is parsed and used to populate the Moodle $CFG
On to the code!
1) Create a directory in your Moodle wwwroot named multisite_config and make sure it’s readable by the web server
2) Create a moodledata_shared directory to hold the various sites’ moodledata directories
3) Modify the wwwroot/config.php file to look like:
<?php /// Moodle Configuration File
unset($CFG);
$CFG->dirroot = '/var/www/moodle_shared';
// Determine hostname
$hostname = $_SERVER['HTTP_HOST'];
if (isset($_ENV['HTTP_HOST'])){ // this is to support cronjobs on a per-host basis
$hostname = $_ENV['HTTP_HOST'];
}
// Load multi-site configs
$multisite_config_filename = "$CFG->dirroot/multisite_config/$hostname.ini";
if (file_exists($multisite_config_filename)) {
$sites_array = parse_ini_file($multisite_config_filename);
} else {
// Whoops! No ini found, fall back to a default Moodle host
$URL="http://default-moodle.domain.org";
header ("Location: $URL");
die("<pre>Unable to open site configuration file for '$hostname'. Has the config file been created?\n</pre>");
}
$CFG->dbtype = 'mysql';
$CFG->dbhost = $sites_array[dbhost];
$CFG->dbname = $sites_array[dbname];
$CFG->dbuser = $sites_array[dbuser];
$CFG->dbpass = $sites_array[dbpass];
$CFG->dbpersist = false;
$CFG->prefix = 'mdl_';
$CFG->wwwroot = $sites_array[wwwroot];
$CFG->dataroot = '/var/www/moodledata_shared/'.$hostname;
$CFG->admin = 'admin';
4) Create an ini file for each Moodle instance you want to host and place it in the Moodle dirroot/multisite_config/ directory. An example ini file for a fictitious template.domain.org Moodle instance:
; multisite_config.ini
[template]
dbhost = localhost
dbname = template_db_name
dbuser = template_user
dbpass = dbpassword
wwwroot = http://template.domain.org/moodle
5) Create a moodledata_shared/hostname directory for the moodledata stuff.
I have a canned mysqldump file I use to create new Moodle sites instead of using the GUI (along with an automated system to create the databases and generate the ini files, but that’s a topic for another post another time). Since I wanted to avoid creating a vhost for every Moodle instance and having to bounce Apache every time I add a new one, I set up a wildcard domain to point at the moodle_shared webroot. But this should work equally well with explicitly-defined Apache vhosts.
Todo:
1) Modify the GUI config to have it write the ini files directly.
2) Look into having site-specific modules. As it stands right now, all sites get the same modules. So far we haven’t run into module conflicts or sites wanting customized versions of modules, but I expect it’s only a matter of time.
3) Performance and scaling testing. This seems to work well enough with the approximately 50 low traffic sites I’m running now, but I’m not sure how much of a penalty the reading and parsing of the ini file imposes. It may not scale well on high traffic sites.
3a) Not sure how well this might be adapted to a multi-server or clustered environment.
Posted by Greg on 30 Jan 2007 | Tagged as: ORVSD, OpenID, drupal, planetosl
User name validation - a quick look at the Drupal API reveals exactly the function I needed: user_validate_name()
To add user name validation to the OpenID Drupal module, add the following code to the openid_create_account_submit() function immediately after the $query = $_POST; statement:
if (user_validate_name($query['edit']['fullname']) != NULL) {
$error = user_validate_name($query['edit']['fullname']);
drupal_set_message('Name is invalid. '.$error, 'error');
header("Location: " . url('openid/get_email'));
exit(0);
}
Worked like a charm. Any user name submitted when registering using an OpenID is now validated against Drupal’s internal user name validation - alphanumeric characters and spaces only. Anything else drops the user back to the name and email request form with an error telling them why the name was rejected. Slick!
Now I just need to figure out how to map existing Drupal users in the database to OpenIDs. Anyone done that before?
UPDATE: Resolved the above question. Add a record to the authmap table with the user’s UID and OpenID. Make sure the OpenID is normalized (has the trailing slash).
UPDATE #2: Updated the diff file that shows what I changed from the stock OpenID Drupal module.
Posted by Greg on 30 Jan 2007 | Tagged as: ORVSD, OpenID, drupal, planetosl
What can I say beyond, “It works!”
Oh, all right. I suppose I could say a few things. The stock OpenID Drupal module works, but it needed a bit of improvement to be useful to us.
By default, the OpenID module creates a Drupal user whose name is their OpenID. That is somewhat problematic, since OpenIDs tend to be somewhat lengthy. So lengthy, in fact, that I have yet to find a Drupal theme that handles them well. They usually either get cropped or overflow into the next column, depending on the CSS. Less than optimal.
We really want to use OpenID as the authentication for the OVSD systems. Justin and I were talking in IRC about his efforts to get it running with Drupal 5. I was feeling inspired, so last night I took a whack at it. With a remarkably-small amount of head-scratching, I was able to modify the stock OpenID Drupal module (v1.1.1) to pull the user’s full name from their OpenID profile and use it as their Drupal name.
I cracked open the openid.module file and made the following changes:
$auth_request->addExtensionArg('sreg', 'optional', 'email');
to this:
$auth_request->addExtensionArg('sreg', 'optional', 'email,fullname');
if ($sreg) {
$_SESSION['sreg_email'] = $sreg['email'];
}
to look like this:
if ($sreg) {
$_SESSION['sreg_email'] = $sreg['email'];
$_SESSION['sreg_fullname'] = $sreg['fullname'];
}
$form['email'] = array('#type' => 'textfield',
'#title' => t('Email Address'),
'#default_value' => @$_SESSION['sreg_email'],
'#size' => 25,
'#maxlength' => 64,
'#description' => t('Enter your email address.')
);
$form['submit'] = array('#type' => 'submit',
'#value' => t('Submit')
);
$form['#action'] = url('openid/get_email');
$content = sprintf("<h3>Create account with OpenID</h3><p>Before logging in " .
"with your OpenID (%s), you must enter an email address:</p> %s",
$_SESSION['openid'], drupal_get_form('openid_create_account',
$form));
So we just need to add the user’s full name to the registration form:
$form['email'] = array('#type' => 'textfield',
'#title' => t('Email Address'),
'#default_value' => @$_SESSION['sreg_email'],
'#size' => 25,
'#maxlength' => 64,
'#description' => t('Enter your email address.')
);
$form['fullname'] = array('#type' => 'textfield',
'#title' => t('Full name'),
'#default_value' => @$_SESSION['sreg_fullname'],
'#size' => 25,
'#maxlength' => 64,
'#description' => t('Enter your full name.')
);
$form['submit'] = array('#type' => 'submit',
'#value' => t('Submit')
);
$form['#action'] = url('openid/get_email');
$content = sprintf("<h3>Create account with OpenID</h3><p>Before logging in " .
"with your OpenID (%s), you must enter your name and email address:</p> %s",
$_SESSION['openid'], drupal_get_form('openid_create_account',
$form));
$user = user_save('', array('name' => $_SESSION['openid'],
'pass' => user_password(),
'mail' => $query['edit']['email'],
'init' => $_SESSION['openid'],
To use the “fullname” variable we grabbed from the user’s OpenID profile, we just need to change it to this:
$user = user_save('', array('name' => $query['edit']['fullname'],
'pass' => user_password(),
'mail' => $query['edit']['email'],
'init' => $_SESSION['openid'],
I’ve posted a diff file that shows the exact changes from the stock OpenID Drupal module.
Security note: If you decide to use this code, be aware that there is no verification done on the user’s name yet. Whatever the user enters in the name field of the registration form is submitted directly into Drupal as the user’s name. So it’s possible there is a security/exploit issue if a malicious user puts something wacky in there. I need to wade into it the code and see if Drupal already has some safeguards in place, or whether I need to add a bit of sanitizing code to the module to ensure there’s nothing nasty embedded in the name. In the mean time, use at your own risk.