source: moodle/trunk/fuentes/admin/tool/uploaduser/locallib.php @ 136

Last change on this file since 136 was 136, checked in by mabarracus, 4 years ago

Ported code to xenial

File size: 14.1 KB
Line 
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Bulk user registration functions
19 *
20 * @package    tool
21 * @subpackage uploaduser
22 * @copyright  2004 onwards Martin Dougiamas (http://dougiamas.com)
23 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
26defined('MOODLE_INTERNAL') || die();
27
28define('UU_USER_ADDNEW', 0);
29define('UU_USER_ADDINC', 1);
30define('UU_USER_ADD_UPDATE', 2);
31define('UU_USER_UPDATE', 3);
32
33define('UU_UPDATE_NOCHANGES', 0);
34define('UU_UPDATE_FILEOVERRIDE', 1);
35define('UU_UPDATE_ALLOVERRIDE', 2);
36define('UU_UPDATE_MISSING', 3);
37
38define('UU_BULK_NONE', 0);
39define('UU_BULK_NEW', 1);
40define('UU_BULK_UPDATED', 2);
41define('UU_BULK_ALL', 3);
42
43define('UU_PWRESET_NONE', 0);
44define('UU_PWRESET_WEAK', 1);
45define('UU_PWRESET_ALL', 2);
46
47/**
48 * Tracking of processed users.
49 *
50 * This class prints user information into a html table.
51 *
52 * @package    core
53 * @subpackage admin
54 * @copyright  2007 Petr Skoda  {@link http://skodak.org}
55 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
56 */
57class uu_progress_tracker {
58    private $_row;
59    public $columns = array('status', 'line', 'id', 'username', 'firstname', 'lastname', 'email', 'password', 'auth', 'enrolments', 'suspended', 'deleted');
60
61    /**
62     * Print table header.
63     * @return void
64     */
65    public function start() {
66        $ci = 0;
67        echo '<table id="uuresults" class="generaltable boxaligncenter flexible-wrap" summary="'.get_string('uploadusersresult', 'tool_uploaduser').'">';
68        echo '<tr class="heading r0">';
69        echo '<th class="header c'.$ci++.'" scope="col">'.get_string('status').'</th>';
70        echo '<th class="header c'.$ci++.'" scope="col">'.get_string('uucsvline', 'tool_uploaduser').'</th>';
71        echo '<th class="header c'.$ci++.'" scope="col">ID</th>';
72        echo '<th class="header c'.$ci++.'" scope="col">'.get_string('username').'</th>';
73        echo '<th class="header c'.$ci++.'" scope="col">'.get_string('firstname').'</th>';
74        echo '<th class="header c'.$ci++.'" scope="col">'.get_string('lastname').'</th>';
75        echo '<th class="header c'.$ci++.'" scope="col">'.get_string('email').'</th>';
76        echo '<th class="header c'.$ci++.'" scope="col">'.get_string('password').'</th>';
77        echo '<th class="header c'.$ci++.'" scope="col">'.get_string('authentication').'</th>';
78        echo '<th class="header c'.$ci++.'" scope="col">'.get_string('enrolments', 'enrol').'</th>';
79        echo '<th class="header c'.$ci++.'" scope="col">'.get_string('suspended', 'auth').'</th>';
80        echo '<th class="header c'.$ci++.'" scope="col">'.get_string('delete').'</th>';
81        echo '</tr>';
82        $this->_row = null;
83    }
84
85    /**
86     * Flush previous line and start a new one.
87     * @return void
88     */
89    public function flush() {
90        if (empty($this->_row) or empty($this->_row['line']['normal'])) {
91            // Nothing to print - each line has to have at least number
92            $this->_row = array();
93            foreach ($this->columns as $col) {
94                $this->_row[$col] = array('normal'=>'', 'info'=>'', 'warning'=>'', 'error'=>'');
95            }
96            return;
97        }
98        $ci = 0;
99        $ri = 1;
100        echo '<tr class="r'.$ri.'">';
101        foreach ($this->_row as $key=>$field) {
102            foreach ($field as $type=>$content) {
103                if ($field[$type] !== '') {
104                    $field[$type] = '<span class="uu'.$type.'">'.$field[$type].'</span>';
105                } else {
106                    unset($field[$type]);
107                }
108            }
109            echo '<td class="cell c'.$ci++.'">';
110            if (!empty($field)) {
111                echo implode('<br />', $field);
112            } else {
113                echo '&nbsp;';
114            }
115            echo '</td>';
116        }
117        echo '</tr>';
118        foreach ($this->columns as $col) {
119            $this->_row[$col] = array('normal'=>'', 'info'=>'', 'warning'=>'', 'error'=>'');
120        }
121    }
122
123    /**
124     * Add tracking info
125     * @param string $col name of column
126     * @param string $msg message
127     * @param string $level 'normal', 'warning' or 'error'
128     * @param bool $merge true means add as new line, false means override all previous text of the same type
129     * @return void
130     */
131    public function track($col, $msg, $level = 'normal', $merge = true) {
132        if (empty($this->_row)) {
133            $this->flush(); //init arrays
134        }
135        if (!in_array($col, $this->columns)) {
136            debugging('Incorrect column:'.$col);
137            return;
138        }
139        if ($merge) {
140            if ($this->_row[$col][$level] != '') {
141                $this->_row[$col][$level] .='<br />';
142            }
143            $this->_row[$col][$level] .= $msg;
144        } else {
145            $this->_row[$col][$level] = $msg;
146        }
147    }
148
149    /**
150     * Print the table end
151     * @return void
152     */
153    public function close() {
154        $this->flush();
155        echo '</table>';
156    }
157}
158
159/**
160 * Validation callback function - verified the column line of csv file.
161 * Converts standard column names to lowercase.
162 * @param csv_import_reader $cir
163 * @param array $stdfields standard user fields
164 * @param array $profilefields custom profile fields
165 * @param moodle_url $returnurl return url in case of any error
166 * @return array list of fields
167 */
168function uu_validate_user_upload_columns(csv_import_reader $cir, $stdfields, $profilefields, moodle_url $returnurl) {
169    $columns = $cir->get_columns();
170
171    if (empty($columns)) {
172        $cir->close();
173        $cir->cleanup();
174        print_error('cannotreadtmpfile', 'error', $returnurl);
175    }
176    if (count($columns) < 2) {
177        $cir->close();
178        $cir->cleanup();
179        print_error('csvfewcolumns', 'error', $returnurl);
180    }
181
182    // test columns
183    $processed = array();
184    foreach ($columns as $key=>$unused) {
185        $field = $columns[$key];
186        $lcfield = core_text::strtolower($field);
187        if (in_array($field, $stdfields) or in_array($lcfield, $stdfields)) {
188            // standard fields are only lowercase
189            $newfield = $lcfield;
190
191        } else if (in_array($field, $profilefields)) {
192            // exact profile field name match - these are case sensitive
193            $newfield = $field;
194
195        } else if (in_array($lcfield, $profilefields)) {
196            // hack: somebody wrote uppercase in csv file, but the system knows only lowercase profile field
197            $newfield = $lcfield;
198
199        } else if (preg_match('/^(cohort|course|group|type|role|enrolperiod|enrolstatus)\d+$/', $lcfield)) {
200            // special fields for enrolments
201            $newfield = $lcfield;
202
203        } else {
204            $cir->close();
205            $cir->cleanup();
206            print_error('invalidfieldname', 'error', $returnurl, $field);
207        }
208        if (in_array($newfield, $processed)) {
209            $cir->close();
210            $cir->cleanup();
211            print_error('duplicatefieldname', 'error', $returnurl, $newfield);
212        }
213        $processed[$key] = $newfield;
214    }
215
216    return $processed;
217}
218
219/**
220 * Increments username - increments trailing number or adds it if not present.
221 * Varifies that the new username does not exist yet
222 * @param string $username
223 * @return incremented username which does not exist yet
224 */
225function uu_increment_username($username) {
226    global $DB, $CFG;
227
228    if (!preg_match_all('/(.*?)([0-9]+)$/', $username, $matches)) {
229        $username = $username.'2';
230    } else {
231        $username = $matches[1][0].($matches[2][0]+1);
232    }
233
234    if ($DB->record_exists('user', array('username'=>$username, 'mnethostid'=>$CFG->mnet_localhost_id))) {
235        return uu_increment_username($username);
236    } else {
237        return $username;
238    }
239}
240
241/**
242 * Check if default field contains templates and apply them.
243 * @param string template - potential tempalte string
244 * @param object user object- we need username, firstname and lastname
245 * @return string field value
246 */
247function uu_process_template($template, $user) {
248    if (is_array($template)) {
249        // hack for for support of text editors with format
250        $t = $template['text'];
251    } else {
252        $t = $template;
253    }
254    if (strpos($t, '%') === false) {
255        return $template;
256    }
257
258    $username  = isset($user->username)  ? $user->username  : '';
259    $firstname = isset($user->firstname) ? $user->firstname : '';
260    $lastname  = isset($user->lastname)  ? $user->lastname  : '';
261
262    $callback = partial('uu_process_template_callback', $username, $firstname, $lastname);
263
264    $result = preg_replace_callback('/(?<!%)%([+-~])?(\d)*([flu])/', $callback, $t);
265
266    if (is_null($result)) {
267        return $template; //error during regex processing??
268    }
269
270    if (is_array($template)) {
271        $template['text'] = $result;
272        return $t;
273    } else {
274        return $result;
275    }
276}
277
278/**
279 * Internal callback function.
280 */
281function uu_process_template_callback($username, $firstname, $lastname, $block) {
282    switch ($block[3]) {
283        case 'u':
284            $repl = $username;
285            break;
286        case 'f':
287            $repl = $firstname;
288            break;
289        case 'l':
290            $repl = $lastname;
291            break;
292        default:
293            return $block[0];
294    }
295
296    switch ($block[1]) {
297        case '+':
298            $repl = core_text::strtoupper($repl);
299            break;
300        case '-':
301            $repl = core_text::strtolower($repl);
302            break;
303        case '~':
304            $repl = core_text::strtotitle($repl);
305            break;
306    }
307
308    if (!empty($block[2])) {
309        $repl = core_text::substr($repl, 0 , $block[2]);
310    }
311
312    return $repl;
313}
314
315/**
316 * Returns list of auth plugins that are enabled and known to work.
317 *
318 * If ppl want to use some other auth type they have to include it
319 * in the CSV file next on each line.
320 *
321 * @return array type=>name
322 */
323function uu_supported_auths() {
324    // Get all the enabled plugins.
325    $plugins = get_enabled_auth_plugins();
326    $choices = array();
327    foreach ($plugins as $plugin) {
328        $objplugin = get_auth_plugin($plugin);
329        // If the plugin can not be manually set skip it.
330        if (!$objplugin->can_be_manually_set()) {
331            continue;
332        }
333        $choices[$plugin] = get_string('pluginname', "auth_{$plugin}");
334    }
335
336    return $choices;
337}
338
339/**
340 * Returns list of roles that are assignable in courses
341 * @return array
342 */
343function uu_allowed_roles() {
344    // let's cheat a bit, frontpage is guaranteed to exist and has the same list of roles ;-)
345    $roles = get_assignable_roles(context_course::instance(SITEID), ROLENAME_ORIGINALANDSHORT);
346    return array_reverse($roles, true);
347}
348
349/**
350 * Returns mapping of all roles using short role name as index.
351 * @return array
352 */
353function uu_allowed_roles_cache() {
354    $allowedroles = get_assignable_roles(context_course::instance(SITEID), ROLENAME_SHORT);
355    foreach ($allowedroles as $rid=>$rname) {
356        $rolecache[$rid] = new stdClass();
357        $rolecache[$rid]->id   = $rid;
358        $rolecache[$rid]->name = $rname;
359        if (!is_numeric($rname)) { // only non-numeric shortnames are supported!!!
360            $rolecache[$rname] = new stdClass();
361            $rolecache[$rname]->id   = $rid;
362            $rolecache[$rname]->name = $rname;
363        }
364    }
365    return $rolecache;
366}
367
368/**
369 * Pre process custom profile data, and update it with corrected value
370 *
371 * @param stdClass $data user profile data
372 * @return stdClass pre-processed custom profile data
373 */
374function uu_pre_process_custom_profile_data($data) {
375    global $CFG, $DB;
376    // find custom profile fields and check if data needs to converted.
377    foreach ($data as $key => $value) {
378        if (preg_match('/^profile_field_/', $key)) {
379            $shortname = str_replace('profile_field_', '', $key);
380            if ($fields = $DB->get_records('user_info_field', array('shortname' => $shortname))) {
381                foreach ($fields as $field) {
382                    require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
383                    $newfield = 'profile_field_'.$field->datatype;
384                    $formfield = new $newfield($field->id, $data->id);
385                    if (method_exists($formfield, 'convert_external_data')) {
386                        $data->$key = $formfield->convert_external_data($value);
387                    }
388                }
389            }
390        }
391    }
392    return $data;
393}
394
395/**
396 * Checks if data provided for custom fields is correct
397 * Currently checking for custom profile field or type menu
398 *
399 * @param array $data user profile data
400 * @return bool true if no error else false
401 */
402function uu_check_custom_profile_data(&$data) {
403    global $CFG, $DB;
404    $noerror = true;
405
406    // find custom profile fields and check if data needs to converted.
407    foreach ($data as $key => $value) {
408        if (preg_match('/^profile_field_/', $key)) {
409            $shortname = str_replace('profile_field_', '', $key);
410            if ($fields = $DB->get_records('user_info_field', array('shortname' => $shortname))) {
411                foreach ($fields as $field) {
412                    require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
413                    $newfield = 'profile_field_'.$field->datatype;
414                    $formfield = new $newfield($field->id, 0);
415                    if (method_exists($formfield, 'convert_external_data') &&
416                            is_null($formfield->convert_external_data($value))) {
417                        $data['status'][] = get_string('invaliduserfield', 'error', $shortname);
418                        $noerror = false;
419                    }
420                }
421            }
422        }
423    }
424    return $noerror;
425}
Note: See TracBrowser for help on using the repository browser.