/** * Handles the upload and import of the user CSV file. * @param Object $page The page object to show messages. */ function WPCW_users_importUsersFromFile($page) { set_time_limit(0); $page->showMessage(__('Import started...', 'wp_courseware')); flush(); if (isset($_FILES['import_course_csv']['name'])) { // See what type of file we're tring to upload $type = strtolower($_FILES['import_course_csv']['type']); $fileTypes = array('text/csv', 'text/plain', 'application/csv', 'text/comma-separated-values', 'application/excel', 'application/vnd.ms-excel', 'application/vnd.msexcel', 'text/anytext', 'application/octet-stream', 'application/txt'); if (!in_array($type, $fileTypes)) { $page->showMessage(__('Unfortunately, you tried to upload a file that isn\'t a CSV file.', 'wp_courseware'), true); return false; } // Filetype is fine, carry on $errornum = $_FILES['import_course_csv']['error'] + 0; $tempfile = $_FILES['import_course_csv']['tmp_name']; // File uploaded successfully? if ($errornum == 0) { // Try the import, return error/success here if (($csvHandle = fopen($tempfile, "r")) !== FALSE) { $assocData = array(); $rowCounter = 0; // Extract the user details from the CSV file into an array for importing. while (($rowData = fgetcsv($csvHandle, 0, ",")) !== FALSE) { if (0 === $rowCounter) { $headerRecord = $rowData; } else { foreach ($rowData as $key => $value) { $assocData[$rowCounter - 1][$headerRecord[$key]] = $value; } $assocData[$rowCounter - 1]['row_num'] = $rowCounter + 1; } $rowCounter++; } // Check we have users to process before continuing. if (count($assocData) < 1) { $page->showMessage(__('No data was found in the CSV file, so there is nothing to do.', 'wp_courseware'), true); return; } // Get a list of all courses that we can add a user too. $courseList = WPCW_courses_getCourseList(false); // Statistics for update. $count_newUser = 0; $count_skippedButUpdated = 0; $count_aborted = 0; // By now, $assocData contains a list of user details in an array. // So now we try to insert all of these users into the system, and validate them all. $skippedList = array(); foreach ($assocData as $userRowData) { // #### 1 - See if we have a username that we can use. If not, abort. $firstName = trim($userRowData['first_name']); $lastName = trim($userRowData['last_name']); $userNameToCreate = $firstName . $lastName; if (!$userNameToCreate) { $skippedList[] = array('id' => $userRowData, 'row_num' => $userRowData['row_num'], 'aborted' => true, 'reason' => __('Cannot create a user with no name.', 'wp_courseware')); $count_aborted++; continue; } // username check // // #### 2 - Email address of user already exists. if ($userID = email_exists($userRowData['email_address'])) { $skippedList[] = array('id' => $userRowData, 'row_num' => $userRowData['row_num'], 'aborted' => false, 'reason' => __('Email address already exists.', 'wp_courseware')); $count_skippedButUpdated++; } else { // #### 3A - Try and create a unique Username $userlogin = $userNameToCreate; while (username_exists($userlogin)) { $userlogin = $userNameToCreate . rand(10, 999); } // #### 3B - Create a new password $newPassword = wp_generate_password(15); // #### 3C - Try to create the new user $userDetailsToAdd = array('user_login' => $userlogin, 'user_email' => $userRowData['email_address'], 'first_name' => $firstName, 'last_name' => $lastName, 'display_name' => trim($firstName . ' ' . $lastName), 'user_pass' => $newPassword); // #### 3D - Check for error when creating $result = wp_insert_user($userDetailsToAdd); if (is_wp_error($result)) { $skippedList[] = array('id' => $userRowData, 'row_num' => $userRowData['row_num'], 'aborted' => true, 'reason' => $result->get_error_message()); $count_aborted++; continue; } // #### 3E - User now exists at this point, copy ID // to user ID variable. $userID = $result; // #### 3F - Notify user of their new password. wp_new_user_notification($userID, $newPassword); flush(); $message = sprintf(__('Username: %s'), $user->user_login) . "\r\n\r\n"; $message .= __('To set your password, visit the following address:') . "\r\n\r\n"; $message .= '<' . network_site_url("wp-login.php?action=rp&key={$key}&login="******">\r\n\r\n"; $message .= wp_login_url() . "\r\n\r\n"; $message .= sprintf(__('If you have any problems, please contact us at %s.'), get_option('admin_email')) . "\r\n\r\n"; $message .= __('Adios!') . "\r\n\r\n"; wp_mail($user->user_email, sprintf(__('[%s] Your username and password info'), $blogname), $message); $count_newUser++; } // #### 4 - Break list of courses into an array, and then add that user to those courses $coursesToAdd = explode(',', $userRowData['courses_to_add_to']); if ($coursesToAdd && count($coursesToAdd) > 0) { WPCW_courses_syncUserAccess($userID, $coursesToAdd); } } // Summary import. $page->showMessage(__('Import complete!', 'wp_courseware') . ' ' . sprintf(__('%d users were registered, %d users were updated, and %d user entries could not be processed.', 'wp_courseware'), $count_newUser, $count_skippedButUpdated, $count_aborted)); // Show any skipped users if (!empty($skippedList)) { printf('<div id="wpcw_user_import_skipped">'); printf('<b>' . __('The following %d users were not imported:', 'wp_courseware') . '</b>', count($skippedList)); printf('<table class="widefat">'); printf('<thead>'); printf('<tr>'); printf('<th>%s</th>', __('Line #', 'wp_courseware')); printf('<th>%s</th>', __('User Email Address', 'wp_courseware')); printf('<th>%s</th>', __('Reason why not imported', 'wp_courseware')); printf('<th>%s</th>', __('Updated Anyway?', 'wp_courseware')); printf('</tr>'); printf('</thead>'); $odd = false; foreach ($skippedList as $skipItem) { printf('<tr class="%s %s">', $odd ? 'alternate' : '', $skipItem['aborted'] ? 'wpcw_error' : 'wpcw_ok'); printf('<td>%s</td>', $skipItem['row_num']); printf('<td>%s</td>', $skipItem['id']['email_address']); printf('<td>%s</td>', $skipItem['reason']); printf('<td>%s</td>', $skipItem['aborted'] ? __('No, Aborted', 'wp_courseware') : __('Yes', 'wp_courseware')); printf('</tr>'); $odd = !$odd; } printf('</table>'); printf('</div>'); } // All done fclose($csvHandle); } else { $page->showMessage(__('Unfortunately, the temporary CSV file could not be opened for processing.', 'wp_courseware'), true); return; } } else { switch ($errornum) { case UPLOAD_ERR_FORM_SIZE: case UPLOAD_ERR_INI_SIZE: $page->showMessage(__("Unfortunately the file you've uploaded is too large for the system.", 'wp_courseware'), true); break; case UPLOAD_ERR_PARTIAL: case UPLOAD_ERR_NO_FILE: $page->showMessage(__("For some reason, the file you've uploaded didn't transfer correctly to the server. Please try again.", 'wp_courseware'), true); break; case UPLOAD_ERR_NO_TMP_DIR: case UPLOAD_ERR_CANT_WRITE: $page->showMessage(__("There appears to be an issue with your server, as the import file could not be stored in the temporary directory.", 'wp_courseware'), true); break; case UPLOAD_ERR_EXTENSION: $page->showMessage(__('Unfortunately, you tried to upload a file that isn\'t a CSV file.', 'wp_courseware'), true); break; } } } // end of if (isset($_FILES['import_course_csv']['name'])) }
/** * Shows the configuration form for the widget. */ function form($instance) { // Create a default title if there is one. if ($instance) { $title = esc_attr($instance['title']); } else { $title = __('Current User Progress', 'wp_courseware'); } $option_course = esc_attr(WPCW_arrays_getValue($instance, 'option_course')); $option_module = esc_attr(WPCW_arrays_getValue($instance, 'option_module')); $option_show_course_title = WPCW_arrays_getValue($instance, 'option_show_course_title') == 'on' ? 'checked="checked"' : ''; $option_show_course_desc = WPCW_arrays_getValue($instance, 'option_show_course_desc') == 'on' ? 'checked="checked"' : ''; $option_show_module_desc = WPCW_arrays_getValue($instance, 'option_show_module_desc') == 'on' ? 'checked="checked"' : ''; $option_show_only_on_units = WPCW_arrays_getValue($instance, 'option_show_only_on_units') == 'on' ? 'checked="checked"' : ''; // Module visibility Toggling $option_toggle_modules = esc_attr(WPCW_arrays_getValue($instance, 'option_toggle_modules')); $option_show_modules_previous = esc_attr(WPCW_arrays_getValue($instance, 'option_show_modules_previous')); $option_show_modules_next = esc_attr(WPCW_arrays_getValue($instance, 'option_show_modules_next')); // Generate dropdowns for the previous/next options $optionsList_previous = array('all' => __('All previous modules', 'wp_courseware'), 'none' => __('None', 'wp_courseware')); for ($i = 1; $i <= 20; $i++) { $optionsList_previous[$i] = sprintf(_n('Show just 1 previous module', 'Show %d previous modules', $i, 'wp_courseware'), $i); } $optionsList_next = array('all' => __('All subsequent modules', 'wp_courseware'), 'none' => __('None', 'wp_courseware')); for ($i = 1; $i <= 20; $i++) { $optionsList_next[$i] = sprintf(_n('Show just 1 subsequent module', 'Show %d subsequent modules', $i, 'wp_courseware'), $i); } ?> <p> <b><label for="<?php echo $this->get_field_id('title'); ?> "><?php _e('Title:', 'wp_courseware'); ?> </label></b> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?> " name="<?php echo $this->get_field_name('title'); ?> " type="text" value="<?php echo $title; ?> " /> <small><?php _e('(Optional) Leave blank for no title.', 'wp_courseware'); ?> </small> </p> <p> <b style="display: block; padding-bottom: 3px;"><label for="<?php echo $this->get_field_id('option_course'); ?> "><?php _e('Course To Show:', 'wp_courseware'); ?> </label></b> <?php $courseList = array('' => __('-- Select a Training Course --', 'wp_courseware'), 'current' => __("Show User's Current Course", 'wp_courseware')); // Blend lists together $mainCourseList = WPCW_courses_getCourseList(); if ($mainCourseList) { $courseList = $courseList + $mainCourseList; } echo WPCW_CourseProgress::createDropdown($this->get_field_name('option_course'), $courseList, $option_course, $this->get_field_id('option_course')); ?> <br/><small><?php _e('(Required) Choose whether to display a specific course to the user or to display the course associated with the unit that the user is currently viewing.', 'wp_courseware'); ?> </small> </p> <p> <b style="display: block; padding-bottom: 3px;"><label><?php _e('Show/Hide Modules:', 'wp_courseware'); ?> </label></b> <small><?php _e('Here you can control how many modules to show before and after the current module to save space.', 'wp_courseware'); ?> </small> </p> <table> <tr> <td><label for="<?php echo $this->get_field_id('option_show_modules_previous'); ?> "><?php _e('Previous modules to display:', 'wp_courseware'); ?> </label></td> <td><label for="<?php echo $this->get_field_id('option_show_modules_next'); ?> "><?php _e('Subsequent modules to display:', 'wp_courseware'); ?> </label></td> </tr> <tr> <td> <?php echo WPCW_CourseProgress::createDropdown($this->get_field_name('option_show_modules_previous'), $optionsList_previous, $option_show_modules_previous, $this->get_field_id('option_show_modules_previous')); ?> </td> <td> <?php echo WPCW_CourseProgress::createDropdown($this->get_field_name('option_show_modules_next'), $optionsList_next, $option_show_modules_next, $this->get_field_id('option_show_modules_next')); ?> </td> </tr> </table><br/> <p> <b style="display: block; padding-bottom: 3px;"><label for="<?php echo $this->get_field_id('option_toggle_modules'); ?> "><?php _e('Expand/Contract Modules:', 'wp_courseware'); ?> </label></b> <?php echo WPCW_CourseProgress::createDropdown($this->get_field_name('option_toggle_modules'), array('expand_all' => __('Expand all modules', 'wp_courseware'), 'contract_all_but_current' => __('Contract all except current module', 'wp_courseware'), 'contract_all' => __('Contract all modules', 'wp_courseware')), $option_toggle_modules, $this->get_field_id('option_toggle_modules')); ?> <br/><small><?php _e('You can save sidebar space by contracting modules in the widget to just show the module title.', 'wp_courseware'); ?> </small> </p> <?php /* // Likely to be deprecated. <p> <b><label for="<?php echo $this->get_field_id('option_module'); ?>"><?php _e('Module:', 'wp_courseware'); ?></label></b> <input class="widefat" id="<?php echo $this->get_field_id('option_module'); ?>" name="<?php echo $this->get_field_name('option_module'); ?>" type="text" value="<?php echo $option_module; ?>" /> <small><?php _e('(Optional) The module number of a module in this course to show specifically (rather than all modules in the course).', 'wp_courseware'); ?></small> </p> */ ?> <p> <b style="display: block; padding-bottom: 3px;"><label for="<?php echo $this->get_field_id('option_show_module_desc'); ?> "><?php _e('More Options:', 'wp_courseware'); ?> </label></b> <input id="<?php echo $this->get_field_id('option_show_course_title'); ?> " name="<?php echo $this->get_field_name('option_show_course_title'); ?> " type="checkbox" <?php echo $option_show_course_title; ?> /> <?php _e('Show Course Title', 'wp_courseware'); ?> <br/> <input id="<?php echo $this->get_field_id('option_show_course_desc'); ?> " name="<?php echo $this->get_field_name('option_show_course_desc'); ?> " type="checkbox" <?php echo $option_show_course_desc; ?> /> <?php _e('Show Course Description', 'wp_courseware'); ?> <br/> <input id="<?php echo $this->get_field_id('option_show_module_desc'); ?> " name="<?php echo $this->get_field_name('option_show_module_desc'); ?> " type="checkbox" <?php echo $option_show_module_desc; ?> /> <?php _e('Show Module Descriptions', 'wp_courseware'); ?> <br/> <input id="<?php echo $this->get_field_id('option_show_only_on_units'); ?> " name="<?php echo $this->get_field_name('option_show_only_on_units'); ?> " type="checkbox" <?php echo $option_show_only_on_units; ?> /> <?php _e('Only display this widget when showing a course unit', 'wp_courseware'); ?> </p> <?php }
/** * Function that allows a module to be created or edited. */ function WPCW_showPage_ModifyModule_load() { $page = new PageBuilder(true); $moduleDetails = false; $moduleID = false; $adding = false; // Trying to edit a course if (isset($_GET['module_id'])) { $moduleID = $_GET['module_id'] + 0; $moduleDetails = WPCW_modules_getModuleDetails($moduleID); // Abort if module not found. if (!$moduleDetails) { $page->showPageHeader(__('Edit Module', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL()); $page->showMessage(__('Sorry, but that module could not be found.', 'wp_courseware'), true); $page->showPageFooter(); return; } else { $page->showPageHeader(__('Edit Module', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL()); } } else { $page->showPageHeader(__('Add Module', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL()); $adding = true; } global $wpcwdb; $formDetails = array('module_title' => array('label' => __('Module Title', 'wp_courseware'), 'type' => 'text', 'required' => true, 'cssclass' => 'wpcw_module_title', 'desc' => __('The title of your module. You <b>do not need to number the modules</b> - this is done automatically based on the order that they are arranged.', 'wp_courseware'), 'validate' => array('type' => 'string', 'maxlen' => 150, 'minlen' => 1, 'regexp' => '/^[^<>]+$/', 'error' => __('Please specify a name for your module, up to a maximum of 150 characters, just no angled brackets (< or >). Your trainees will be able to see this module title.', 'wp_courseware'))), 'parent_course_id' => array('label' => __('Associated Course', 'wp_courseware'), 'type' => 'select', 'required' => true, 'cssclass' => 'wpcw_associated_course', 'desc' => __('The associated training course that this module belongs to.', 'wp_courseware'), 'data' => WPCW_courses_getCourseList(__('-- Select a Training Course --', 'wp_courseware'))), 'module_desc' => array('label' => __('Module Description', 'wp_courseware'), 'type' => 'textarea', 'required' => true, 'cssclass' => 'wpcw_module_desc', 'desc' => __('The description of this module. Your trainees will be able to see this module description.', 'wp_courseware'), 'validate' => array('type' => 'string', 'maxlen' => 5000, 'minlen' => 1, 'error' => __('Please limit the description of your module to 5000 characters.', 'wp_courseware')))); $form = new RecordsForm($formDetails, $wpcwdb->modules, 'module_id'); $form->customFormErrorMsg = __('Sorry, but unfortunately there were some errors saving the module details. Please fix the errors and try again.', 'wp_courseware'); $form->setAllTranslationStrings(WPCW_forms_getTranslationStrings()); // Useful place to go $directionMsg = '<br/></br>' . sprintf(__('Do you want to return to the <a href="%s">course summary page</a>?', 'wp_courseware'), admin_url('admin.php?page=WPCW_wp_courseware')); // Override success messages $form->msg_record_created = __('Module details successfully created.', 'wp_courseware') . $directionMsg; $form->msg_record_updated = __('Module details successfully updated.', 'wp_courseware') . $directionMsg; $form->setPrimaryKeyValue($moduleID); $form->setSaveButtonLabel(__('Save ALL Details', 'wp_courseware')); // See if we have a course ID to pre-set. if ($adding && ($courseID = WPCW_arrays_getValue($_GET, 'course_id'))) { $form->loadDefaults(array('parent_course_id' => $courseID)); } // Call to re-order modules once they've been created $form->afterSaveFunction = 'WPCW_actions_modules_afterModuleSaved_formHook'; $form->show(); $page->showPageMiddle('20%'); // Editing a module? if ($moduleDetails) { // ### Include a link to delete the module $page->openPane('wpcw-deletion-module', __('Delete Module?', 'wp_courseware')); printf('<a href="%s&action=delete_module&module_id=%d" class="wpcw_delete_item" title="%s">%s</a>', admin_url('admin.php?page=WPCW_wp_courseware'), $moduleID, __("Are you sure you want to delete the this module?\n\nThis CANNOT be undone!", 'wp_courseware'), __('Delete this Module', 'wp_courseware')); printf('<p>%s</p>', __('Units will <b>not</b> be deleted, they will <b>just be disassociated</b> from this module.', 'wp_courseware')); $page->closePane(); // #### Show a list of all sub-units $page->openPane('wpcw-units-module', __('Units in this Module', 'wp_courseware')); $unitList = WPCW_units_getListOfUnits($moduleID); if ($unitList) { printf('<ul class="wpcw_unit_list">'); foreach ($unitList as $unitID => $unitObj) { printf('<li>%s %d - %s</li>', __('Unit', 'wp_courseware'), $unitObj->unit_meta->unit_number, $unitObj->post_title); } printf('</ul>'); } else { printf('<p>%s</p>', __('There are currently no units in this module.', 'wp_courseware')); } } $page->showPageFooter(); }
/** * Page that shows the overview of mapping for the levels to courses. * @param PageBuilder $page The current page object. */ private function showMembershipMappingLevels_overview($page) { // Handle the detection of the membership plugin before doing anything else. if (!$this->found_membershipTool()) { $page->showPageFooter(); return; } // Try to show the level data $levelData = $this->getMembershipLevels_cached(); if ($levelData) { // Create the table to show the data $table = new TableBuilder(); $table->attributes = array('class' => 'wpcw_tbl widefat', 'id' => 'wpcw_members_tbl'); $col = new TableColumn(__('Level ID', 'wp_courseware'), 'wpcw_members_id'); $table->addColumn($col); $col = new TableColumn(__('Level Name', 'wp_courseware'), 'wpcw_members_name'); $table->addColumn($col); $col = new TableColumn(__('Users at this level can access:', 'wp_courseware'), 'wpcw_members_levels'); $table->addColumn($col); $col = new TableColumn(__('Actions', 'wp_courseware'), 'wpcw_members_actions'); $table->addColumn($col); $odd = false; // Work out the base URL for the overview page $baseURL = admin_url('admin.php?page=' . $this->extensionID); // The list of courses that are currently on the system. $courses = WPCW_courses_getCourseList(false); // Add actual level data foreach ($levelData as $id => $levelDatum) { $data = array(); $data['wpcw_members_id'] = $levelDatum['id']; $data['wpcw_members_name'] = $levelDatum['name']; // Get list of courses already associated with level. $courseListInDB = $this->getCourseAccessListForLevel($levelDatum['id']); if ($courses) { $data['wpcw_members_levels'] = '<ul class="wpcw_tickitems">'; // Show which courses will be added to users created at this level. foreach ($courses as $courseID => $courseName) { $data['wpcw_members_levels'] .= sprintf('<li class="wpcw_%s">%s</li>', isset($courseListInDB[$courseID]) ? 'enabled' : 'disabled', $courseName); } $data['wpcw_members_levels'] .= '</ul>'; } else { $data['wpcw_members_levels'] = __('There are no courses yet.', 'wp_courseware'); } // Buttons to edit the permissions $data['wpcw_members_actions'] = sprintf('<a href="%s&level_id=%s" class="button-secondary">%s</a>', $baseURL, $levelDatum['id'], __('Edit Course Access Settings', 'wp_courseware')); $odd = !$odd; $table->addRow($data, $odd ? 'alternate' : ''); } echo $table->toString(); } else { $page->showMessage(sprintf(__('No membership levels were found for %s.', 'wp_courseware'), $this->extensionName), true); } }
/** * Generate a course list for resetting the progress for a user. * * @param $fieldName String The name to use for the name attribute for this dropdown. * @param $courseIDList Array If specified, this is a list of IDs to determine which courses to use in the reset box. * @param $blankMessage String the message to show if there are no courses. * @param $addBlank String Use this string as the first item in the dropdown. * @param $cssID String The CSS ID to use for the select box. * @param $cssClass String The CSS class to use for the select box. * * @return String The course reset dropdown box. */ function WPCW_courses_getCourseResetDropdown($fieldName, $courseIDList = false, $blankMessage, $addBlank, $cssID, $cssClass) { $selectDetails = array('' => $addBlank); // Need all courses $courseList = WPCW_courses_getCourseList(); if (!empty($courseList)) { $blankCount = 2; foreach ($courseList as $courseID => $aCourse) { // Filter out unwanted courses. if (is_array($courseIDList) && !in_array($courseID, $courseIDList)) { continue; } // Have sentinel of course_ to identify a course. $selectDetails['course_' . $courseID] = $aCourse; // Now we add the modules for this course $moduleList = WPCW_courses_getModuleDetailsList($courseID); if (!empty($moduleList)) { foreach ($moduleList as $moduleID => $moduleDetails) { // Now we add the units for this course $units = WPCW_units_getListOfUnits($moduleID); if (!empty($units)) { // Only add a module if it has units, to make resetting easier. $selectDetails['module_' . $moduleID] = sprintf(' - %s %d: %s', __('Module', 'wp_courseware'), $moduleDetails->module_number, $moduleDetails->module_title); foreach ($units as $unitID => $unitDetails) { $selectDetails['unit_' . $unitID] = sprintf(' -- %s %d: %s', __('Unit', 'wp_courseware'), $unitDetails->unit_meta->unit_number, $unitDetails->post_title); } } // end of unit list check } // end of foreach module } // end of module list check // Add a blank sentinel to space out courses. $paddingKey = str_pad(false, $blankCount++, ' '); $selectDetails[$paddingKey] = ' '; } } // No courses... show meaningful message to the trainer. if (count($selectDetails) == 1) { $selectDetails[' '] = $blankMessage; } // Generate the select box. Use the $cssID as the name of the field too. return WPCW_forms_createDropdown($fieldName, $selectDetails, false, $cssID, $cssClass); }