3

I need to create an external application that creates, modifies and enrol users of Moodle.

I've been reading Moodle documentation but its more for front administrators that for developers. How can I do to create a user? which tables hold obligatory information about them? and how do I enrol existing users to Moodle?

halfer
  • 19,824
  • 17
  • 99
  • 186
For MOodle
  • 41
  • 1
  • 1
  • 2
  • Can't understand: at this moment 4 people have starred this question but no one has upvoted it. – EAmez Mar 15 '18 at 11:27

3 Answers3

21

You should use web services rather than using SQL - https://docs.moodle.org/dev/Creating_a_web_service_client

  1. Enable web services /admin/search.php?query=enablewebservices
  2. Enable rest protocol /admin/settings.php?section=webserviceprotocols
  3. Add a service /admin/settings.php?section=externalservices
    • add short name = myservice
    • enable = true
  4. Click on functions for the service.
  5. Add core_user_create_users and enrol_manual_enrol_users
    • You'll need to look at the api documentation for the parameters
    • /admin/webservice/documentation.php
  6. Create a role - /admin/roles/manage.php
  7. Choose a user level + system context
  8. Add capability - webservice/rest:use
  9. Create a testuser and add to the role created above
  10. Create a token for the user /admin/settings.php?section=webservicetokens

Once you have that set up, use something like this:

// First get the token.
$tokenurl = 'http://www.yourmoodlesite.com/login/token.php?username=testuser&password=xx&service=myservice';

$tokenresponse = file_get_contents($tokenurl);

$tokenobject = json_decode($tokenresponse);

if (!empty($tokenobject->error)) {
    echo $tokenobject->error;
    die();
}

// Then call the create user and enrol functions
// Remember to add the question mark after "server.php" because http_build_query() won't add it on its own and you'll end up with a 404 error
$baseurl = 'http://www.yourmoodlesite.com/webservice/rest/server.php?';

// Then add these parameters to the url.

$users = array();
// See the api documentation /admin/webservice/documentation.php
// for core_user_create_users for building the $users array
// e.g.
// $users = array(array(
// 'username' => 'lecapitaine',   //Username policy is defined in Moodle security config
// 'password' =>  'EngageNCC-1701', //Plain text password consisting of any characters
// 'firstname' =>  'William', //The first name(s) of the user
// 'lastname' => 'Shatner',  //The family name of the user
// 'email' => 'jimmy.k@enterprise.com',
// 'lang' => 'en',
// ));

$params = array(
    'wstoken' => $tokenobject->token,
    'wsfunction' => 'core_user_create_users',
    'moodlewsrestformat' => 'json',
    'users' => $users,
);

$url = $baseurl . http_build_query($params);

$response = file_get_contents($url);

$newusers = json_decode($response);

// Newusers will be an array of objects containing the new user ids.

$enrolments = array();
// See the api documentation /admin/webservice/documentation.php
// for enrol_manual_enrol_users for building the $enrolments array

// Then enrol the users.
$params = array(
    'wstoken' => $tokenobject->token,
    'wsfunction' => 'enrol_manual_enrol_users',
    'moodlewsrestformat' => 'json',
    'enrolments' => $enrolments,
);

$url = $baseurl . http_build_query($params);

$response = file_get_contents($url);

$enrolled = json_decode($response);
J-a-n-u-s
  • 1,469
  • 17
  • 20
Russell England
  • 9,436
  • 1
  • 27
  • 41
  • You, sir, helped me a lot! Thank you very much! – Andrey Bulezyuk Jul 12 '19 at 14:01
  • 1
    Just something I stumbled upon following this answer: In 3.9 I also had to add the capability "moodle/role:assign" to the role, because when I was trying to enrol the user at course X the API would return an error like "You can't assign user (3) to course (4) with roleid (5)". After some research I found out I had to add this capability to the role and this script ran perfectly. – G.Felicio Sep 15 '22 at 12:45
12

As answered here creating moodle users and register them on courses programatically by me =3. This works completely extern to moodle.

$servername = 'localhost';
$username = 'username';
$password = 'password';
$dbname = 'moodle';

$u_moodle = 'theusernameyouwant';
$hp_moodle = password_hash('thepasswordyouwant', PASSWORD_DEFAULT); ///IMPORTANT!
$name = 'first name';
$lname = 'last name';
$email = 'e@m.ail'; ///This have to be verified by you as we're inserting it directly
$course = '123'; //Id that you put in moodle admin, not the real id    

$conn = new mysqli($servername, $username, $password, $dbname);

$sql = "INSERT INTO 'mdl_user' (auth, confirmed, mnethostid, username, password, firstname, lastname, email)
    VALUES ('manual', 1, 1, '$u_moodle', '$hp_moodle', '$name', '$lname', '$email')";
// auth = 'manual', confirmed = 1, mnethostid = 1 Always. the others are your variables

if ($conn->query($sql) === TRUE) {
    echo "OKTC";
} else {
    ////Manage your errors
}

$sql = "SELECT * FROM $m_user WHERE email='$email'";
$result = $conn2->query($sql);
if($row = $result->fetch_assoc()) {
    $id = $row['id']; //Id of newly created user. we're using that for to register him on the course
}

////You have to use this if your idnumber for the course is the one you put into moodle (thats not the real id)
$sql = "SELECT id FROM 'mdl_course' WHERE idnumber=$course";
$result = $conn->query($sql);
if(!$result){
    ///Not existing course, manage your error
}
if($row = $result->fetch_assoc()) {
    $idcourse = $row["id"];
}

///I need now the "enrol" id, so I do this:
$sql = "SELECT id FROM 'mdl_enrol' WHERE courseid=$idcourse AND enrol='manual'";
$result = $conn->query($sql);
if(!$result){
    ///Not enrol associated (this shouldn't happen and means you have an error in your moodle database)
}
if($row = $result->fetch_assoc()) {
    $idenrol = $row["id"];
}

///Lastly I need the context
$sql = "SELECT id FROM 'mdl_context' WHERE contextlevel=50 AND instanceid=$idcourse"; ///contextlevel = 50 means course in moodle
$result = $conn->query($sql);
if(!$result){
    ///Again, weird error, shouldnt happen to you
}
if($row = $result->fetch_assoc()) {
    $idcontext = $row["id"];
}

///We were just getting variables from moodle. Here is were the enrolment begins:

$time = time();
$ntime = $time + 60*60*24*$duration; //How long will it last enroled $duration = days, this can be 0 for unlimited.
$sql = "INSERT INTO 'mdl_user_enrolments' (status, enrolid, userid, timestart, timeend, timecreated, timemodified)
VALUES (0, $idenrol, $id, '$time', '$ntime', '$time', '$time')";
if ($conn->query($sql) === TRUE) {
} else {
    ///Manage your sql error
}

$sql = "INSERT INTO 'mdl_role_assignments' (roleid, contextid, userid, timemodified)
VALUES (5, $idcontext, '$id', '$time')"; //Roleid = 5, means student.
if ($conn->query($sql) === TRUE) {
} else {
    //manage your errors
}

E finito. There you got a new user name enroled into course 123.

Community
  • 1
  • 1
Aschab
  • 1,378
  • 2
  • 14
  • 31
  • Thank you for answering the question that was asked! Only comment is that you use a $conn2 that should be $conn. Bravo – James Bailey Nov 08 '18 at 18:02
  • The feedback [on the duplicate answer](https://stackoverflow.com/a/36075593) is that this code probably has SQL injection vulnerabilities, or would at least make it more likely that someone copy+pasting the code will end up with a vulnerable website. Readers should swap to bound parameters if they can. – halfer May 20 '20 at 23:03
0

Thanks Aschab for your snippet, it really helped me alot!

Indeed, it inspired me to create a VIEW in Mysql, so you can actually save at least one database call for every user insertion!

CREATE OR REPLACE VIEW v_mdl_meta_enrolment  AS  
SELECT MC.`id` AS course_id,MC.idnumber AS course,E.`id` AS enrol_id,C.`id` AS context_id
FROM ((mdl_course MC join mdl_enrol E) 
JOIN mdl_context C) 
WHERE E.courseid = MC.`id` and E.enrol = 'manual' 
AND C.contextlevel = 50 
AND C.instanceid = MC.`id`;