bulkimport.php 11 KB
Newer Older
1
2
3
4
5
6
<?php
/**
 *
 * @package    mahara
 * @subpackage admin
 * @author     Catalyst IT Ltd
7
8
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
 * @copyright  For copyright information on Mahara, please see the README file distributed with this software.
9
10
11
12
13
14
15
16
 *
 */

define('INTERNAL', 1);
define('ADMIN', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
require_once('pieforms/pieform.php');
require_once('institution.php');
17
require_once(get_config('docroot') . '/lib/htmloutput.php');
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
safe_require('artefact', 'internal');
safe_require('artefact', 'file');

define('TITLE', get_string('bulkleap2aimport', 'admin'));

// Turn on autodetecting of line endings, so mac newlines (\r) will work
ini_set('auto_detect_line_endings', 1);

$authinstances = auth_get_auth_instances();

if (count($authinstances) > 0) {
    $options = array();

    foreach ($authinstances as $authinstance) {
        $options[$authinstance->id] = $authinstance->displayname. ': '.$authinstance->instancename;
    }
    $default = key($options);

    $authinstanceelement = array(
        'type' => 'select',
        'title' => get_string('institution'),
        'description' => get_string('uploadcsvinstitution', 'admin'),
        'options' => $options,
        'defaultvalue' => $default
    );
}

$form = array(
    'name' => 'bulkimport',
    'elements' => array(
        'authinstance' => $authinstanceelement,
49
        'file' => array(
50
            'type' => 'text',
51
52
53
            'title' => get_string('importfile', 'admin'),
            'size' => 40,
            'description' => get_string('bulkleap2aimportfiledescription', 'admin'),
54
55
56
57
58
59
60
61
62
63
            'rules' => array(
                'required' => true
            )
        ),
        'emailusers' => array(
            'type' => 'checkbox',
            'title' => get_string('emailusersaboutnewaccount', 'admin'),
            'description' => get_string('emailusersaboutnewaccountdescription', 'admin'),
            'defaultvalue' => true,
        ),
64
65
66
67
68
        'progress_meter_token' => array(
            'type' => 'hidden',
            'value' => 'bulkimport',
            'readonly' => TRUE,
        ),
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
        'submit' => array(
            'type' => 'submit',
            'value' => get_string('Import', 'admin')
        )
    )
);

/**
 * The CSV file is parsed here so validation errors can be returned to the
 * user. The data from a successful parsing is stored in the <var>$LEAP2AFILES</var>
 * array so it can be accessed by the submit function
 *
 * @param Pieform  $form   The form to validate
 * @param array    $values The values submitted
 */
function bulkimport_validate(Pieform $form, $values) {
85
    global $LEAP2AFILES, $USER;
86
87
88
89
90
91
92
93

    // Don't even start attempting to parse if there are previous errors
    if ($form->has_errors()) {
        return;
    }

    require_once('csvfile.php');

94
95
96
    $zipfile = $values['file'];
    if (!is_file($zipfile)) {
        $form->set_error('file', get_string('importfilenotafile', 'admin'));
97
98
        return;
    }
99
100
    if (!is_readable($zipfile)) {
        $form->set_error('file', get_string('importfilenotreadable', 'admin'));
101
102
103
        return;
    }

104
105
106
107
108
109
110
    // Create temporary directory
    $importdir = get_config('dataroot') . 'import/'
        . $USER->get('id')  . '/' . time() .  '/';
    if (!check_dir_exists($importdir)) {
        throw new SystemException("Couldn't create the temporary export directory $importdir");
    }

111
112
113
114
115
    $archive = new ZipArchive();
    if ($archive->open($zipfile) && $archive->extractTo($importdir)) {
        // successfully extracted
        $archive->close();
        log_debug("Unzipped $zipfile into $importdir");
116
117
    }
    else {
118
        throw new SystemException(get_string('unzipfailed', 'admin', hsc($zipfile)));
119
    }
120

121
    $csvfilename = $importdir . '/usernames.csv';
122
    if (!is_readable($csvfilename)) {
123
        $form->set_error('file', get_string('importfilemissinglisting', 'admin'));
124
125
126
127
128
129
130
131
132
        return;
    }

    $csvusers = new CsvFile($csvfilename);
    $csvusers->set('headerExists', false);
    $csvusers->set('format', array('username', 'filename'));
    $csvdata = $csvusers->get_data();

    if (!empty($csvdata->errors['file'])) {
133
        $form->set_error('file', get_string('invalidlistingfile', 'admin'));
134
135
136
        return;
    }

137
138
139
140
    foreach ($csvdata->data as $user) {
        $username = $user[0];
        $filename = $user[1];
        $LEAP2AFILES[$username] = "$importdir/users/$filename";
141
142
143
144
145
146
147
148
149
    }
}

/**
 * Add the users to the system.
 */
function bulkimport_submit(Pieform $form, $values) {
    global $SESSION, $LEAP2AFILES;

150
151
152
153
154
155
    require_once('file.php');
    require_once(get_config('docroot') . 'import/lib.php');
    safe_require('import', 'leap');

    $key = 0;
    $total = count($LEAP2AFILES);
156

157
    log_info('Attempting to import ' . $total . ' users from Leap2A files');
158

159
160
161
162
    foreach ($LEAP2AFILES as $username => $filename) {
        if (!($key % 10)) {
            set_progress_info('bulkimport', $key, $total, get_string('importing', 'admin'));
        }
163

164
        $key++;
165

166
167
168
169
170
        import_next_user($filename, $username, $values['authinstance']);
    }

    finish_import();
}
171

172
173
function import_next_user($filename, $username, $authinstance) {
    global $ADDEDUSERS, $FAILEDUSERS;
174
175
176

    log_debug('adding user ' . $username . ' from ' . $filename);

177
    $authobj = get_record('auth_instance', 'id', $authinstance);
178
179
    $institution = new Institution($authobj->institution);

180
181
182
    $date = time();
    $nicedate = date('Y/m/d h:i:s', $date);
    $niceuser = preg_replace('/[^a-zA-Z0-9_-]/', '-', $username);
183

184
    $uploaddir = get_config('dataroot') . 'import/' . $niceuser . '-' . $date . '/';
185

186
    check_dir_exists($uploaddir);
187

188
    // Unzip the file
189
190
191
192
193
194
    $archive = new ZipArchive();
    if ($archive->open($filename) && $archive->extractTo($uploaddir)) {
        // successfully extracted
        $archive->close();
    }
    else {
195
        $FAILEDUSERS[$username] = get_string('unzipfailed', 'admin', hsc($filename));
196
        return;
197
    }
198

199
200
201
202
    $leap2afilename = $uploaddir . 'leap2a.xml';
    if (!is_file($leap2afilename)) {
        $FAILEDUSERS[$username] = get_string('noleap2axmlfiledetected', 'admin');
        log_debug($FAILEDUSERS[$username]);
203
        return;
204
    }
205

206
207
208
209
    // If the username is already taken, append something to the end
    while (get_record('usr', 'username', $username)) {
        $username .= "_";
    }
210

211
    $user = (object)array(
212
                          'authinstance'   => $authinstance,
213
214
215
216
217
218
                          'username'       => $username,
                          'firstname'      => 'Imported',
                          'lastname'       => 'User',
                          'password'       => get_random_key(6),
                          'passwordchange' => 1,
                          );
219

220
    db_begin();
221

222
223
224
225
226
227
    try {
        $user->id = create_user($user, array(), $institution, $authobj);
    }
    catch (EmailException $e) {
        // Suppress any emails (e.g. new institution membership) sent out
        // during user creation, becuase the user doesn't have an email
Francois Marier's avatar
Francois Marier committed
228
        // address until we've imported them from the Leap2A file.
229
230
        log_debug("Failed sending email during user import");
    }
231

232
233
    $niceuser = preg_replace('/[^a-zA-Z0-9_-]/', '-', $user->username);
    $record = (object)array(
234
235
236
237
238
239
        'token'      => '',
        'usr'        => $user->id,
        'queue'      => (int)!(PluginImport::import_immediately_allowed()), // import allowed straight away? Then don't queue
        'ready'      => 0, // maybe 1?
        'expirytime' => db_format_timestamp(time()+(60*60*24)),
        'format'     => 'leap',
240
        'data'       => array('importfile' => $filename, 'importfilename' => $filename, 'importid' => $niceuser.time(), 'mimetype' => file_mime_type($filename)),
241
242
243
        'loglevel'   => PluginImportLeap::LOG_LEVEL_VERBOSE,
        'logtargets' => LOG_TARGET_FILE,
        'profile'    => true,
244
245
246
    );
    $tr = new LocalImporterTransport($record);
    $tr->extract_file();
247

248
249
    $importer = PluginImport::create_importer(null, $tr, $record);
    unset($record, $tr);
250
251
    try {
        $importer->process();
252
        log_info("Imported user account $user->id from Leap2A file, see" . $importer->get('logfile') . 'for a full log');
253
254
    }
    catch (ImportException $e) {
Francois Marier's avatar
Francois Marier committed
255
        log_info("Leap2A import failed: " . $e->getMessage());
256
257
        $FAILEDUSERS[$username] = get_string("leap2aimportfailed");
        db_rollback();
258
259
    }

260
261
    db_commit();

262
263
264
    if (empty($FAILEDUSERS[$username])) {
        // Reload the user details, as various fields are changed by the
        // importer when importing (e.g. firstname/lastname)
265
266
267
        $newuser = get_record('usr', 'id', $user->id);
        $newuser->clearpasswd = $user->password;
        $ADDEDUSERS[] = $newuser;
268
    }
269

270
    return;
271
272
273
274
275
276
}

function finish_import() {
    global $SESSION, $ADDEDUSERS, $FAILEDUSERS, $EMAILUSERS;

    $totalusers = count($ADDEDUSERS) + count($FAILEDUSERS);
277

278
279
280
281
    log_info('Imported ' . count($ADDEDUSERS) . '/' . $totalusers . ' users successfully');

    if (!empty($ADDEDUSERS)) {
        $SESSION->add_ok_msg(get_string('importednuserssuccessfully', 'admin', count($ADDEDUSERS), $totalusers));
282
283
284
285
    }

    // Only send e-mail to users after we're sure they have been inserted
    // successfully
286
287
    if ($EMAILUSERS && $ADDEDUSERS) {
        foreach ($ADDEDUSERS as $user) {
288
289
290
            $noemailusers = array();
            try {
                email_user($user, null, get_string('accountcreated', 'mahara', get_config('sitename')),
291
292
                    get_string('accountcreatedchangepasswordtext', 'mahara', $user->firstname, get_config('sitename'), $user->username, $user->clearpasswd, get_config('wwwroot'), get_config('sitename')),
                    get_string('accountcreatedchangepasswordhtml', 'mahara', $user->firstname, get_config('wwwroot'), get_config('sitename'), $user->username, $user->clearpasswd, get_config('wwwroot'), get_config('wwwroot'), get_config('sitename'))
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
                );
            }
            catch (EmailException $e) {
                log_info($e->getMessage());
                $noemailusers[] = $user;
            }
        }

        if ($noemailusers) {
            $message = get_string('uploadcsvsomeuserscouldnotbeemailed', 'admin') . "\n<ul>\n";
            foreach ($noemailusers as $user) {
                $message .= '<li>' . full_name($user) . ' &lt;' . hsc($user->email) . "&gt;</li>\n";
            }
            $message .= "</ul>\n";
            $SESSION->add_info_msg($message, false);
        }
    }

311
312
313
    if (!empty($FAILEDUSERS)) {
        $message = get_string('importfailedfornusers', 'admin', count($FAILEDUSERS), $totalusers) . "\n<ul>\n";
        foreach ($FAILEDUSERS as $username => $error) {
314
315
316
            $message .= '<li>' . hsc($username) . ': ' . hsc($error) . "</li>\n";
        }
        $message .= "</ul>\n";
317
        $SESSION->add_error_msg($message, false);
318
319
    }

320
    redirect(get_config('wwwroot') . '/admin/users/bulkimport.php');
321
322
323
324
325
326
}

$form = pieform($form);

$smarty = smarty();
$smarty->assign('form', $form);
327
$smarty->assign('PAGEHEADING', TITLE);
328
$smarty->display('admin/users/bulkimport.tpl');