I've tested this with some example data files. We don't have the IMS data exchange set up as a live service yet so it's not extensively tested, although I think it should be robust. It's designed to be able to handle arbitrarily large IMS files.
If you test it yourself, we'd be grateful for feedback posted to this site.
I should emphasise that this script processes an XML file stored in the filesystem - it does not directly query the SITS system, it doesn't use Web Services, or anything along those lines.
I haven't been able to find anyone else doing this, so I've started to develop a module that does a live query at login and uses the resulting IMS Enterprise XML data as the resource to identify the courses a student is enrolled on.
It is specifically designed to work with Capita UnitE, which is a common UK student information system. A UnitE component purchaseable from Capita called MLE Link provides a server (or broker if you prefer) which can be sent a student number and will respond with a string of IMS Enterprise format XML.
The code is modular, so the bit that goes to grab the data could easily be replaced.
The module is still in development, but if anyone else is interested in this, I'd like to know and compare notes.
Thanks again for making this public!
Attached is a slightly updated version of the IMS enrolment module.
Changes:
- Fixed a typo which meant the "email log to admin" setting was not working
- More information in the log file output
- Refactored the code into separate functions, to make it easier for other developers to work on the code in future (e.g. to reuse the code in a "Web Services" context)
All feedback welcome - please post messages in this forum to let us know how it works for you...
I meet a problem, and it's that you do not contemplate that the file IMS has an a one line.
I'm doing a preprocessing it, to arrange this problem.
I'm thinking of using an intermediate file, as the following example:
Insert in line 153:
-----------------------------------8<-----------------------------------------------------
$this->xmlcache = '';
//Antoni Mas at 22-11-2005.
//Create temporal file
$temporalfile = $filename.".tmp";
//Open file
$fh = fopen($filename, "r");
//Create and open temporal file
$fc = fopen($temporalfile, "x");
//Get line (unique)
$curline = fgets($fh);
//Replace current tag which it don't information.
$newdoc = ereg_replace(">[<]", ">\n<", $curline);
//Write
if (!fwrite($fc, $newdoc)) {
$this->log .= "Can't write file: $temporalfile\n\n";
}
fclose($fc);
fclose($fh);
if (!rename($temporalfile, $filename)) {
$this->log .= "failed to copy $filename...\n";
}
// FIRST PASS: Run through the file and process the group/person entries
---------------------------------8<-----------------------------------------
But this is an optional, then an other flag of the configuration.
Hi just started using your module to parse data generated by our IMS Export program (The Capita MLE Link program mentioned elsewhere)
1. it outputs <ID>, not <userid> for the user name. (I would not swear to it, but I think <ID> is correct) - I changed userid to id on line 250 to fix this problem - I realise its not a general solution.
2. all its tags are in upper case. I added $tagname=strtoupper($tagname);
at line 442 to fix this (again, not a generic solution.
3. It reported 6 records with a blank roletype even though, hoving checekd the data, all have a value of 01
4. Oh and my output was originally one long line with no linefeeds, so for the moment, I just changed >< to >\n< in my IMS file with an editor. But that's, I think the problem already reported.
Here are some snippets from the log:
Created user record for user '20035493' (ID number 20035493, name *****).
Created user record for user '20035897' (ID number 20035897, name *****).
Failed to create course 5096/51FFA in Moodle
Failed to create course 5095/51FFA in Moodle
....plus a whole load more - this may be my understanding of your module - I'll investigate this further before coming back
And finally six instances of
ERROR - Unhandled role type detected. Role code is ''. Please contact the developer to fix this.
Process has completed.
Time taken: 4 seconds
It's possible that your system is outputting Enterprise 1.0 data rather than Enterprise 1.1. (In v1.0 the tags are supposed to be in capitals, while in v1.1 they should be in lower case!) I will incorporate case-folding into the script, because it would be ideal to be able to cope with both versions.
- (I would not swear to it, but I think <ID> is correct)
No, <userid> is the tag name, not <id> - as described in section 3.3.3 here. (It's the same for both v1.0 and v1.1.) You may be looking at the <id> tag contained within the <sourcedid> element? That indicates the ID within the source system, not the login which the user should use in Moodle.
- It reported 6 records with a blank roletype
This is unusual. Would you be willing to email me the data file so I can get to the bottom of why this may be happening? If the roles are indicated as "01" I'm not sure why it would not be picked up.
1. re id vs userid, you are correct, however, in our case, the sourcdid|id IS the userid in the system. The MIS know and reports no other id (userid etc). I know it adds complexity, but I guess a field mapping facility would fix it (and any other problem of this sort).
2. letting you have the file - I realise that it is virtually impossible to fix it without the file, but of course there are data protection implications - especially if the data leaves the UK, where our laws can no longer protect it, so I guess I should email it direct to your normal e-mail account once I have cleared it with our data protection officer.
3. I also found the reason it would not create courses was because the course table is set up with a key for category+sortorder, and your code sets category to 1 for all created courses (no problem) but seems not to set sortorder. As a result, all courses are given a key of 1-0 and any after the first fails to insert because of duplicate key.
2. Of course, that's fine. If you can send it then I'll have a look. If not, then your own diagnosis/fix will be required.
3. Did you add that key yourself? Our installation doesn't have that key. But your point is valid - I'll try and make sure there is a value for "sortorder".
Re 3. the key. No, We didn't add the key. I'm using 1.5.2+ here (2005060223), and we are using as out of the box (or rather download) except for the addition of the Object module.
I must own up to not having read the current IMS standard. The earlier one was enough to give me a lifetime of indigestion!
Chris.
Changes:
- Can now cope with XML files with no line-breaks!
- Option to fall back on <sourcedid><id> if your naughty MIS doesn't output a <userid> field
- Case-insensitive XML tag detection (should make it work with IMS 1.0 files?)
- Sets the "sortorder" field when inserting a new course into the database
been involved with doing this for our current and former systems in both the SIS and LMS realms.
One question, how do you associate the with Moodle courses?
There are 2 ways I've seen this go in our work here (university of wisconsin):
1) Auto creation
1st time such a comes in, it creates a new course.
2) Associate with existing course
There is a pre-existing course, matches up to it based on the
(or sourceid.id).
There's an option in the preferences to specify whether the script should create a course if the sourcedid.id does not already exist in Moodle's database. Turn it on if you want option (1), turn it off if you want option (2).
Next, a few more questions for the auto course create mode:
3) Is there a way to pick the course category?
This would be used for associating with a department or school/department.
4) What is used for the course title?
I'm assuming it's in the group.description.short from your example.
Now, for a something a bit harder, dealing with multi-sectioned courses.
5) How would you handle a lecture/lab?
This is where we have a large enrollment lecture, say 200 students,
and multple labs sections, each student is in 1 lab.
What I'd like to be to do is have either a single course in Moodle
with students in groups associated with both lecture and lab sections
or a set of courses that have a hierarchical relationship between
the lecture/lab.
In this case, the Enterprise datafeed could be modified to show the lecture/lab
relationship. You'd have nested group elements. That's one direction to
take this. Could be other ways to go.
6) How are crosslisted courses handled?
These are courses that are offered in 2 or more departments.
Each department has a section.
Our typical solution here has been to create 1 course and put
all the students in it. Some department is considered the "owner"
of the course.
4) Yes, that's right.
5) I'm afraid I don't understand the scenario clearly. I think you're asking for the module to allocate the students to "groups" within a Moodle course? We don't do much with Moodle's "groups" functionality yet so I can't really comment on that.
(The module doesn't currently do anything with nested groups in the IMS data - I can confirm that at least!)
6) The "enrol_coursealias" table can probably be used to account for this. For example, if two course codes BIOL101 and PHOL101 actually refer to the same course, then entries in the coursealias table can automatically translate both of those into a single Moodle course. Look at the README file for a little bit more info about the coursealias table.
As it now stands, your enrol module would work fine for single departments,
where the category assignment didn't matter.
5) ok, this is harder to do group assignment.
OK Now tested. Works well with my XML as far as I can see.
I tracked down the roletype problem.
In my xml (1.0) I have
<role>
<roletype>01</roletype>
</role>
Your code assumes
<role roletype='01'>
</role>
I added this code
if(preg_match('{<roletype>(.+?)</roletype>}is', $mmatch[1], $matches)){
$member->roletype = trim($matches[1]); // 01 means Student, 02 means Instructor, 3 means ContentDeveloper, and there are more besides
}
after your match around line 248, and it worked fine.
I guess you could wrap this code inside "if ($member->roletype){ ...}" in case both existed in the same xml file, but they really should not. It ought to be one or the other, not both.
I'm puzzled about the roletype format in your data: even in the 1.0 IMS specification, the roletype is definitely an attribute, not a child element! For example, if you look at the example provided in the 1.0 document, you can see roletype in there as an attribute.
I'm not keen on adding your modification into the official version of my script, because as far as I can tell your system is producing non-standard XML. Do you have the ability to modify the way the XML is produced?
Unfortunately not. It is produced by a program supplied by (sound of coughing up feathers) Capita Education Services. There's an awful lot of people out there using Capita Student record systems....
Trouble is that if they modify it, it will probably break the systems it DOES work with, so that means they won't change it.
In the meantime, I am writing a replacement for it (the Capita program), but I need the justification for that or TPTB won't countenance using it. Failure to conform to standards MIGHT swing it, but I am not certain. In the meantime, a demonstrable way of importing this data is essential to convincing them to go Moodle. It would be nice if it is in your module, so that we get the benefit of enhancements to it over time, but if it has to be a separate module, then we hit the problem of home cooked code again.
- Can use the group.org.orgunit element to specify course category when creating a new course
- Contains an option to handle the slightly-malformed Capita XML gracefully
Good work!!
But, you might add the following thing when a course is created
--------------------------------------------------8<------------------------------------------
//Insert info from the current language
$site = get_site();
if (current_language() == $CFG->lang) {
$course->teacher = $site->teacher;
$course->teachers = $site->teachers;
$course->student = $site->student;
$course->students = $site->students;
} else {
$course->teacher = get_string("defaultcourseteacher");
$course->teachers = get_string("defaultcourseteachers");
$course->student = get_string("defaultcoursestudent");
$course->students = get_string("defaultcoursestudents");
}
----------------------------------------------8<--------------------------------------------
Thanks!
But, you might add the following thing when a person is created
if(preg_match('{<adr>.*?<locality>(.+?)</locality>.*?</adr>}is', $tagcontents, $matches)){
$person->city = trim($matches[1]);
}
if(preg_match('{<adr>.*?<country>(.+?)</country>.*?</adr>}is', $tagcontents, $matches)){
$person->country = trim($matches[1]);
}
This is an optional, but I'd think when it's necessary.
Thanks!
Thanks, and sorry I've not tested the Capita produced code yet. I will do so, but I've been working on a home grown IMS-E XML writer, because, to be honest the performance of the capita product (ignoring the conformance issues) is leaving me wondering about its usefulness.
I am pleased to see the the categorisation opportunity, using the group.org.orgname entity. The capita code won't write this entity, but I have already added this info to my home grown XML writer. So I look forward to trying it out there.
By the way, for those interested in performance issues, I added 1965 courses and arounf 7450 students into Moodle (creating all the courses and all the students, and enrolling them on their courses). This set up is
Zend Engine v2.0.3
Apache/1.3.33 (Win32)
PHP/5.0.3
MySQL 4.1.8-nt-log
Windows XP SP2 (not server edition)
Pentium 4 3.2GHz
1GB RAM
It loaded the complete file in 17 minutes. A rerun of the file to discover that no new data was to be processed (i.e no new students and no new courses) took just 70 seconds.
I have to say I was impressed. Then I was nurtured on Learnwsie where it takes about 17 minutes to load ONE course and enrol about 20 students!
Separate thread, slightly different subject....
You've provided a way to pass through org info into Moodle categories. I ma wondering how to pass across cohort information and use it to control grouping of students within courses.
Many of our courses have more than one cohort of students on them. We are primarily a vocational college, and this means we have a lot of part time courses. This in turn means that the same "course" can be running on Tuesdays and Thursdays, or on Mondays and Wednesdays etc, but with different student cohorts.
It seems to me (shoot me down in flames if you will, we don't have the experience yet) that the best way to handle this is to have a single course to hold the course materials and activities, and to put the different sets of students (cohorts) into different student groups inside a single course. If this is nonsense, stop reading now, but if not, then this info is available in the MIS system, and I am wondering how it is best to carry it across in the IMS standard. The only way I can think of is to make the course a group of sub-groups, where each of the subgroups is a separate cohort.
While on the subject of groups and sub-groups, I'd like to raise a side issue. Why is the org and particularly the orgname, buried as a subentity (and, effectively an attribute) of the course group entity. Surely it makes more semantic sense to make the org a group, and then make the groups that represent courses members of it. I.e. group(org) contains members that each map to a group(course) each of which contains members(student).
To do it the way suggested in the standard seems to me to be a flaw in the standard in the sense that they have created a new solution to something for which they already had a solution. It is also not a well normalised solution, since using their system the orgname is repeated over and over, unnecessarily.
[replying to my own post, sorry.] On thinking about the processing, it seemed simplest to add a cohort entity inside the extension entity of the member entity.
i.e. membership.member.extension.cohort contains cohort code.
That way, you get the info at the point when you need it. I.e. you are newly enrolling a student, and therefore (if specified) you shoudl add it to a group. It also avoids upsetting the process of enrolment of students onto courses, since the arrangement of membership.member entities will remain unchanged.
Actually, looking at the spec, the member.role.subrole entity might be useful for this purpose - it can contain any string data up to 32 characters, which should be plenty. What do you think?
oops yes, i meant role.extension.
My only concern with using subrole is if someone else finds a better use for it. For example, differentiating between project team leaders and others in a situation that required such a thing. That seems more like what a sub role really is. I guess its pretty unlikely to beused for students (only teachers etc) but it still feels a bit like stealing.
I'm not sure what is the best direction for this. Your extension is a nice way to avoid interfering with the courses data. But it would require knowledge of that extension in any MIS which was supposed to specify course sub-groups.
The only other alternative - which is in the spirit of the spec (i.e. big and unwieldy ) is to create a membership matching each course and then make the groups members of it. But to do that, you'd still need to create leaf entities for the groups, and I am not sure what their type would be and how you'd stop some import programs trying to treat them as if they were courses.
so you'd have
enterprise
person
group (type=moodlecourse)
group (type=moodlegroup)
membership(id of group(of type moodlecourse)
member(id of group(of type moodlegroup)
membership(id of group(of type moodlegroup)
person refs
Trouble with this is that it would almost certainly break any other system at all because they don't expect this extra layer.
I think on balance, I'd like to go with the extension for now and throw the problem back to the IMS crew to fix for a future update to the spec.
I've posted a diatribe in the groups area as well about a better way of handling them in Moodle. I must learn to stop posting!!!!
Have you any preferences re sub-groups/moodle groups in the MIS data.
I still think I would like to go for the <extension> option for now, since I don't think the standard has a proper provision for it, or at least doesn't have one that would be transparent to other users.
What a pity the MIS standard isn't managed the same way Moodle is.
Chris
OK, at last I tested it with some data from the Capita export program, and it seems to be broken again - not sure where yet.
I'll try to trim the file right down and see, but basically it gave me about thirty pages of
Notice: Undefined property: stdClass::$username in c:\wamp\www\moodle\enrol\imsenterprise\enrol.php on line 399
And it was doing a LOT of work - I know this because the processor got hot enough for the auxiliary fan to cut in. I can't currently see how that property would be undefined. Perhaps you have some ideas.
Once I have a cut down file, I'll anonymise it and send it to you.
When you say "it worked fine", this includes setting/checking of usernames?
It's possible that the processor load was because of the very long logfile being built up in memory - so it would be particularly useful to remove the "Notice"s in order to lessen the chance of that impacting on the server.
I processed the output from Capita without first setting the relevant options, so, I guess it wasn't setting the userid value because it wasn't looking in sourcedid.id for it.
As for "worked fine", I mean that it didn't report errors and the log of what it had done looked like it was doing what I had expected. I have not done detailed checking yet. I am also working on a search extension to the object module at the moment, so I have overstretched myself a little.
I see that in your script there's a strange thing, and he's that me these removing all references to teacher, and then you use the function to remove the teacher of the course (into member function).
(line +/- 500 aprox.)
-------------8<-------------------
// Unenrol
delete_records('user_teachers', 'userid', $memberstoreobj->userid);
if (! remove_teacher($memberstoreobj->userid, $memberstoreobj->course)) {
-------------------8<-------------
First, you remove all references to teacher.
Second, you return to remove the teacher, when already you've remove all his references of this course, which it's sure that they don't exist, since before you revome all.
This is a bug, no?
I've thinking, but I don't see where developer.
Would you create a temporary image?
switch($link)
{
case 'png':
$iTmp = imagecreatefrompng($link);
break;
case 'gif':
$iTmp = imagecreatefromgif($link);
break;
case 'jpeg':
case 'jpg':
$iTmp = imagecreatefromjpeg($link);
break;
}
From the IMS there happen to you the url and the format of the image.
Do many student management systems include this kind of data?
I order you the files that I've modified, have made it like optional.
I've modified the function save_profile_image of the gdlib in order that it takes url's.
Quite this in the zip.
Hi Dan!
I've gone through the code briefly (v0.4). In general terms it makes sense to me, though I do have a couple of off-the-cuff questions... I tried to RTFC but a thing or two may have escaped me...
- Does it unenrol students only if the existing record matches
enrol==='imsenterprise'
and there's no record in the XML file? - Log handling -- it seems that you forgot to make
$CFG->enrol_emailadmins
useful perhaps?-- The use of
$this->log .= foo
is going to ramp up memory use really badly. The standard thing in Moodle code during trace is to use mtrace(). If each module/plugin was to have its own reporting mechanisms... - This will trigger an expensive re-read way too often. Thought about storing and checking mtime or md5 of the last file successfully imported?
- There are some gotchas in the Moodle style (use of camel case, missing prefix
auth_imsenterprise
(though I would shorten it a bit to avoid the carpal thing... imse?) in functions, etc. Nothing serious but needs a check.
With regards to user acct autocreation, you might want to take a peek at the code in auth/db that I have in this unofficial branch -- it is intended to make it into HEAD soon: http://locke.catalyst.net.nz/gitweb?p=moodle.git;a=shortlog;h=mdl-artena-tairawhiti
That code provides for account autocreation, generates a temp passwords and mails it out to users. As long as you have an email address for them, naturally
Anyway -- I think it's a good plugin! There are some things that perhaps need to be pulled out (course aliasing) -- it doesn't belong "inside" the plugin, in any case it should be a common mechanism. It has a lot of overlap with metacourses.
Oh, and there's that pesky issue of Postgres support... Actually -- if you separate course aliasing, your DB support issue goes away completely.
- Does it unenrol students only if the existing record matches
enrol==='imsenterprise'
and there's no record in the XML file?- No. It unenrols students only if there's a membership record in the XML file marked with <status>0</status> which indicates an "inactive" membership.
- No. It unenrols students only if there's a membership record in the XML file marked with <status>0</status> which indicates an "inactive" membership.
- Log handling -- it seems that you forgot to make
$CFG->enrol_emailadmins
useful perhaps?- No, I don't think so. In an early version there was a typo (missing "s" at the end) which meant the email doesn't get sent. But in v0.4 it should work - line 250 & 251 are
if (!empty($CFG->enrol_mailadmins)) {
email_to_user(..............);
- No, I don't think so. In an early version there was a typo (missing "s" at the end) which meant the email doesn't get sent. But in v0.4 it should work - line 250 & 251 are
- The use of
$this->log .= foo
is going to ramp up memory use really badly. The standard thing in Moodle code during trace is to use mtrace(). If each module/plugin was to have its own reporting mechanisms...- Thanks for pointing that out. I think actually I copied this behaviour from the "flat file enrolment" mechanism. If we're to use mtrace(), how is the log ever going to be emailed to the administrator? I'd be grateful for thoughts on the best way to proceed.
- Thanks for pointing that out. I think actually I copied this behaviour from the "flat file enrolment" mechanism. If we're to use mtrace(), how is the log ever going to be emailed to the administrator? I'd be grateful for thoughts on the best way to proceed.
- This will trigger an expensive re-read way too often. Thought about
storing and checking mtime or md5 of the last file successfully
imported?
- Good suggestion. I would guess that filemtime() should be a good way to fix this. Will add this to next release.
- Good suggestion. I would guess that filemtime() should be a good way to fix this. Will add this to next release.
- There are some gotchas in the Moodle style (use of camel case, missing prefix
auth_imsenterprise
(though I would shorten it a bit to avoid the carpal thing... imse?) in functions, etc. Nothing serious but needs a check.- No - it's a class file, so they are class methods rather than functions. There should be no need to prefix their names. You're right about my occasional camel-case lapses though...
I agree that course aliasing is more generic than just the IMS-E process, and I'd like to see it as part of the main enrolment code. It does overlap with metacourses, but has a lot of differences.
1) For the log, writing to a logfile will be much better than building the log up in memory and then emailing it.
2) I forgot that there *are* functions as well as class methods in that file - doh - a little bit more renaming is in order.
writing to a logfile
Exactly. I am wondering though if (a) all this log writing and sending to admins is needed and (b) if that's the case, we should have a standard-ish way of doing it. Suggestion: use tempnam()
to pick a unique-ish filename under moodledata/tmp, and then error_log("msg\n",3,$filename);
. You can later collect the file, mail it out and delete it.
It unenrols students only if there's a membership record in the XML file marked with 0 which indicates an "inactive" membership.
So you don't expect to see all the enrolments in each file revision? ... thought IMS Enterprise wasn't about sending add/update/del entries, but about showing all current records.
email_to_user(..............);
Oops. I missed that. Sorry!
I would guess that filemtime() should be a good way to fix this.
Combining filemtime() and md5() will make it very robust. You can store the last seen time and md5 in $CFG.
With regards to functions and method names, you are right, it's a class file so you don't need prefixes for the methods (though as you say, there are functions there too). Moodle style would be good too ;)
- thought IMS Enterprise wasn't about sending add/update/del entries, but about showing all current records
- The specification explicitly allows for both, although they do say that they recommend the 'snapshot' rather than the 'incremental' way of doing things since it's more tolerant of communication lapses.
I will read the Moodle style guide from cover to cover!
- Logging is handled differently (writes directly to a text file). This should make it more scaleable, and faster.
- Checks file (path, modification time, and MD5 hash) to make sure that unneccessary repeated processing of the same data is avoided.
- Detects city and country entries when creating new users.
- Moodle groups can be managed, by using the extension tag member.role.extension.cohort
- Added SQL table-creation file for Postgres as well as MySQL.
- Now follows the Moodle coding guidelines!
- Antoni provided code for including the user photo. I've added the code in, but I've commented it out, because it relies on a modification to a Moodle library file. If you want to use this functionality, you can install the modified file and then uncomment the lines - see post here for detail.
- I agree with Martin that the "coursealias" functionality would be better moved out of this script and into generic enrolment handling, but it's staying here for the time being in order to be available for people installing into a standard Moodle 1.5 setup.
I've got a student, his userid is 20 and his name is "Joe Moodle", and I want to enroll him in a course called "Moodle 101" whose id is 7. HE will be in the group called "unit 2" within that course whose id is 5. I want him to enroll from today and have his enrollment period last 180 days. How would I mark this up and what information of the above would be required and what would be optional? And what would I do if Joe Moodle did not already have an account at my site? What will happen if the student is already enrolled in the particular course and I simply am changing his group membership and/or extending his enrollment period?
Remember that the numeric keys used in the Moodle databases are not the interoperable data - a student data system is never going to know in advance that Joe is the 20th user added to the Moodle database - so those aren't the keys exchanged in this type of data.
Typically a course would have a reference code as well as a name, so let's assume its code is MOODLE101. To define your course you could use
<group>
<sourcedid>
<source>MyDataSystem</source>
<id>MOODLE101</id>
</sourcedid>
<description>
<short>Moodle 101</short>
</description>
</group>
The enrolment script will look for a course with code MOODLE101, and (optionally) create it if it doesn't exist. Similarly for the person. You haven't said what his username is - let's assume it's "jmoodle":
<person>
<sourcedid>
<source>MyDataSystem</source>
<id>jmoodle</id>
</sourcedid>
<userid>jmoodle</userid>
<name>
<fn>Joe Moodle</fn>
<n>
<family>MOODLE</family>
<given>JOE</given>
</n>
</name>
</person>
If Joe doesn't already have an account, the script can (optionally) create an account for him.
Let's now look at the membership, adding the person to the course:
<membership>
<sourcedid>
<source>MyDataSystem</source>
<id>MOODLE101</id>
</sourcedid>
<member>
<sourcedid>
<source>MyDataSystem</source>
<id>jmoodle</id>
</sourcedid>
<role roletype="01">
<status>1</status>
<extension><cohort>unit 2</cohort></extension>
</role>
</member>
</membership>
The IMS-E specification does offer a facility for specifying start/end dates but I haven't implemented that feature. Our system here will enrol/unenrol people by modifying their IMS-E record at the necessary time, so we don't need to pass that data across. It may be worth implementing the <timeframe> feature in future.
If a person is already added to a group within the course, the script won't actually modify that. If they are not grouped, however, then the specified grouping will be applied.
This is not specified in the IMS Enterprise Information Model.
It's probably not such a good idea to pass it anyway.
Better to get Moodle to authenticate against an existing database using something like the LDAP interface.
What system are the username/password pairs currently in?
I've made some changes to the IMS Enterprise plugin that allows you to specify the password. This is, in fact, allowed in the IMS-E specification. See here:
http://www.imsglobal.org/enterprise/entv1p1/imsent_bindv1p1.html#1428026
I've made various other changes that improve logging and detection of existing accounts (so you don't try to recreate them). I've attached the patch and an explanation to MDL-15864
However, there's a nasty bug in the existing script. As Dan said, the new user's "auth" type defaults to whatever the default authentication method is at your site. There have been some changes to Moodle's authentication structure which means $CFG->auth returns a comma-separated list of auth plugins. You can only set one of these values in a user's record. I've reported this as a bug (MDL-15863).
Unfortunately, the bug has been assigned to "Nobody", so I'm not sure how it's going to be handled
Chris