parent
							
								
									791a25abe9
								
							
						
					
					
						commit
						ece1d3a1b3
					
				@ -0,0 +1,662 @@ | 
				
			||||
<?php | 
				
			||||
/* For licensing terms, see /license.txt */ | 
				
			||||
 | 
				
			||||
use ChamiloSession as Session; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * @author Bart Mollet | 
				
			||||
 * @author Julio Montoya <gugli100@gmail.com> BeezNest 2011 | 
				
			||||
 * | 
				
			||||
 * @package chamilo.admin | 
				
			||||
 */ | 
				
			||||
$cidReset = true; | 
				
			||||
require_once __DIR__.'/../inc/global.inc.php'; | 
				
			||||
 | 
				
			||||
$urlId = api_get_current_access_url_id(); | 
				
			||||
$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : ''; | 
				
			||||
 | 
				
			||||
api_protect_admin_script(); | 
				
			||||
 | 
				
			||||
$this_section = SECTION_PLATFORM_ADMIN; | 
				
			||||
 | 
				
			||||
$extraFields = UserManager::createDataPrivacyExtraFields(); | 
				
			||||
Session::write('data_privacy_extra_fields', $extraFields); | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Prepares the shared SQL query for the user table. | 
				
			||||
 * See get_user_data() and get_number_of_users(). | 
				
			||||
 * | 
				
			||||
 * @param bool $getCount Whether to count, or get data | 
				
			||||
 * | 
				
			||||
 * @return string SQL query | 
				
			||||
 */ | 
				
			||||
function prepare_user_sql_query($getCount) | 
				
			||||
{ | 
				
			||||
    $sql = ''; | 
				
			||||
    $user_table = Database::get_main_table(TABLE_MAIN_USER); | 
				
			||||
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN); | 
				
			||||
 | 
				
			||||
    if ($getCount) { | 
				
			||||
        $sql .= "SELECT COUNT(u.id) AS total_number_of_items FROM $user_table u"; | 
				
			||||
    } else { | 
				
			||||
        $sql .= 'SELECT u.id AS col0, u.official_code AS col2, '; | 
				
			||||
        if (api_is_western_name_order()) { | 
				
			||||
            $sql .= 'u.firstname AS col3, u.lastname AS col4, '; | 
				
			||||
        } else { | 
				
			||||
            $sql .= 'u.lastname AS col3, u.firstname AS col4, '; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $sql .= " u.username AS col5, | 
				
			||||
                    u.email AS col6, | 
				
			||||
                    u.status AS col7, | 
				
			||||
                    u.active AS col8, | 
				
			||||
                    u.id AS col9, | 
				
			||||
                    u.registration_date AS col10, | 
				
			||||
                    u.expiration_date AS exp, | 
				
			||||
                    u.password, | 
				
			||||
                    v.field_id | 
				
			||||
                FROM $user_table u"; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    // adding the filter to see the user's only of the current access_url | 
				
			||||
    if ((api_is_platform_admin() || api_is_session_admin()) && api_get_multiple_access_url()) { | 
				
			||||
        $access_url_rel_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); | 
				
			||||
        $sql .= " INNER JOIN $access_url_rel_user_table url_rel_user  | 
				
			||||
                  ON (u.id=url_rel_user.user_id)"; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    $extraFields = Session::read('data_privacy_extra_fields'); | 
				
			||||
    $extraFieldId = $extraFields['delete_legal']; | 
				
			||||
    $extraFieldIdDeleteAccount = $extraFields['delete_account_extra_field']; | 
				
			||||
 | 
				
			||||
    $extraFieldValue = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES); | 
				
			||||
    $sql .= " INNER JOIN $extraFieldValue v | 
				
			||||
              ON ( | 
				
			||||
                    u.id = v.item_id AND  | 
				
			||||
                    (field_id = $extraFieldId OR field_id = $extraFieldIdDeleteAccount) AND | 
				
			||||
                    v.value = 1 | 
				
			||||
              ) "; | 
				
			||||
 | 
				
			||||
    $keywordList = [ | 
				
			||||
        'keyword_firstname', | 
				
			||||
        'keyword_lastname', | 
				
			||||
        'keyword_username', | 
				
			||||
        'keyword_email', | 
				
			||||
        'keyword_officialcode', | 
				
			||||
        'keyword_status', | 
				
			||||
        'keyword_active', | 
				
			||||
        'keyword_inactive', | 
				
			||||
        'check_easy_passwords', | 
				
			||||
    ]; | 
				
			||||
 | 
				
			||||
    $keywordListValues = []; | 
				
			||||
    $atLeastOne = false; | 
				
			||||
    foreach ($keywordList as $keyword) { | 
				
			||||
        $keywordListValues[$keyword] = null; | 
				
			||||
        if (isset($_GET[$keyword]) && !empty($_GET[$keyword])) { | 
				
			||||
            $keywordListValues[$keyword] = $_GET[$keyword]; | 
				
			||||
            $atLeastOne = true; | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    if ($atLeastOne == false) { | 
				
			||||
        $keywordListValues = []; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    if (isset($_GET['keyword']) && !empty($_GET['keyword'])) { | 
				
			||||
        $keywordFiltered = Database::escape_string("%".$_GET['keyword']."%"); | 
				
			||||
        $sql .= " WHERE ( | 
				
			||||
                    u.firstname LIKE '$keywordFiltered' OR | 
				
			||||
                    u.lastname LIKE '$keywordFiltered' OR | 
				
			||||
                    concat(u.firstname, ' ', u.lastname) LIKE '$keywordFiltered' OR | 
				
			||||
                    concat(u.lastname,' ',u.firstname) LIKE '$keywordFiltered' OR | 
				
			||||
                    u.username LIKE '$keywordFiltered' OR | 
				
			||||
                    u.official_code LIKE '$keywordFiltered' OR | 
				
			||||
                    u.email LIKE '$keywordFiltered' | 
				
			||||
                ) | 
				
			||||
        "; | 
				
			||||
    } elseif (isset($keywordListValues) && !empty($keywordListValues)) { | 
				
			||||
        $query_admin_table = ''; | 
				
			||||
        $keyword_admin = ''; | 
				
			||||
 | 
				
			||||
        if (isset($keywordListValues['keyword_status']) && | 
				
			||||
            $keywordListValues['keyword_status'] == PLATFORM_ADMIN | 
				
			||||
        ) { | 
				
			||||
            $query_admin_table = " , $admin_table a "; | 
				
			||||
            $keyword_admin = ' AND a.user_id = u.id '; | 
				
			||||
            $keywordListValues['keyword_status'] = '%'; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $keyword_extra_value = ''; | 
				
			||||
 | 
				
			||||
        $sql .= " $query_admin_table | 
				
			||||
            WHERE ( | 
				
			||||
                u.firstname LIKE '".Database::escape_string("%".$keywordListValues['keyword_firstname']."%")."' AND | 
				
			||||
                u.lastname LIKE '".Database::escape_string("%".$keywordListValues['keyword_lastname']."%")."' AND | 
				
			||||
                u.username LIKE '".Database::escape_string("%".$keywordListValues['keyword_username']."%")."' AND | 
				
			||||
                u.email LIKE '".Database::escape_string("%".$keywordListValues['keyword_email']."%")."' AND | 
				
			||||
                u.status LIKE '".Database::escape_string($keywordListValues['keyword_status'])."' "; | 
				
			||||
        if (!empty($keywordListValues['keyword_officialcode'])) { | 
				
			||||
            $sql .= " AND u.official_code LIKE '".Database::escape_string("%".$keywordListValues['keyword_officialcode']."%")."' "; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $sql .= " | 
				
			||||
            $keyword_admin | 
				
			||||
            $keyword_extra_value | 
				
			||||
        "; | 
				
			||||
 | 
				
			||||
        if (isset($keywordListValues['keyword_active']) && | 
				
			||||
            !isset($keywordListValues['keyword_inactive']) | 
				
			||||
        ) { | 
				
			||||
            $sql .= " AND u.active = 1"; | 
				
			||||
        } elseif (isset($keywordListValues['keyword_inactive']) && | 
				
			||||
            !isset($keywordListValues['keyword_active']) | 
				
			||||
        ) { | 
				
			||||
            $sql .= " AND u.active = 0"; | 
				
			||||
        } | 
				
			||||
        $sql .= " ) "; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    $preventSessionAdminsToManageAllUsers = api_get_setting('prevent_session_admins_to_manage_all_users'); | 
				
			||||
    if (api_is_session_admin() && $preventSessionAdminsToManageAllUsers === 'true') { | 
				
			||||
        $sql .= " AND u.creator_id = ".api_get_user_id(); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    // adding the filter to see the user's only of the current access_url | 
				
			||||
    if ((api_is_platform_admin() || api_is_session_admin()) && | 
				
			||||
        api_get_multiple_access_url() | 
				
			||||
    ) { | 
				
			||||
        $sql .= " AND url_rel_user.access_url_id = ".api_get_current_access_url_id(); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    return $sql; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Get the total number of users on the platform. | 
				
			||||
 * | 
				
			||||
 * @see SortableTable#get_total_number_of_items() | 
				
			||||
 */ | 
				
			||||
function get_number_of_users() | 
				
			||||
{ | 
				
			||||
    $sql = prepare_user_sql_query(true); | 
				
			||||
    $res = Database::query($sql); | 
				
			||||
    $obj = Database::fetch_object($res); | 
				
			||||
 | 
				
			||||
    return $obj->total_number_of_items; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Get the users to display on the current page (fill the sortable-table). | 
				
			||||
 * | 
				
			||||
 * @param   int     offset of first user to recover | 
				
			||||
 * @param   int     Number of users to get | 
				
			||||
 * @param   int     Column to sort on | 
				
			||||
 * @param   string  Order (ASC,DESC) | 
				
			||||
 * | 
				
			||||
 * @return array Users list | 
				
			||||
 * | 
				
			||||
 * @see SortableTable#get_table_data($from) | 
				
			||||
 */ | 
				
			||||
function get_user_data($from, $number_of_items, $column, $direction) | 
				
			||||
{ | 
				
			||||
    $sql = prepare_user_sql_query(false); | 
				
			||||
    if (!in_array($direction, ['ASC', 'DESC'])) { | 
				
			||||
        $direction = 'ASC'; | 
				
			||||
    } | 
				
			||||
    $column = (int) $column; | 
				
			||||
    $from = (int) $from; | 
				
			||||
    $number_of_items = (int) $number_of_items; | 
				
			||||
    $sql .= " ORDER BY col$column $direction "; | 
				
			||||
    $sql .= " LIMIT $from,$number_of_items"; | 
				
			||||
 | 
				
			||||
    $res = Database::query($sql); | 
				
			||||
 | 
				
			||||
    $users = []; | 
				
			||||
    $t = time(); | 
				
			||||
    while ($user = Database::fetch_row($res)) { | 
				
			||||
        $userPicture = UserManager::getUserPicture( | 
				
			||||
            $user[0], | 
				
			||||
            USER_IMAGE_SIZE_SMALL | 
				
			||||
        ); | 
				
			||||
        $photo = '<img  | 
				
			||||
            src="'.$userPicture.'" width="22" height="22"  | 
				
			||||
            alt="'.api_get_person_name($user[2], $user[3]).'"  | 
				
			||||
            title="'.api_get_person_name($user[2], $user[3]).'" />'; | 
				
			||||
 | 
				
			||||
        if ($user[7] == 1 && !empty($user[10])) { | 
				
			||||
            // check expiration date | 
				
			||||
            $expiration_time = convert_sql_date($user[10]); | 
				
			||||
            // if expiration date is passed, store a special value for active field | 
				
			||||
            if ($expiration_time < $t) { | 
				
			||||
                $user[7] = '-1'; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        // forget about the expiration date field | 
				
			||||
        $users[] = [ | 
				
			||||
            $user[0], | 
				
			||||
            $photo, | 
				
			||||
            $user[1], | 
				
			||||
            $user[2], | 
				
			||||
            $user[3], | 
				
			||||
            $user[4], | 
				
			||||
            $user[5], | 
				
			||||
            $user[6], | 
				
			||||
            $user[7], | 
				
			||||
            api_get_local_time($user[9]), | 
				
			||||
            $user[12], | 
				
			||||
            $user[0], | 
				
			||||
        ]; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    return $users; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Returns a mailto-link. | 
				
			||||
 * | 
				
			||||
 * @param string $email An email-address | 
				
			||||
 * | 
				
			||||
 * @return string HTML-code with a mailto-link | 
				
			||||
 */ | 
				
			||||
function email_filter($email) | 
				
			||||
{ | 
				
			||||
    return Display::encrypted_mailto_link($email, $email); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Returns a mailto-link. | 
				
			||||
 * | 
				
			||||
 * @param string $email  An email-address | 
				
			||||
 * @param array  $params Deprecated | 
				
			||||
 * @param array  $row | 
				
			||||
 * | 
				
			||||
 * @return string HTML-code with a mailto-link | 
				
			||||
 */ | 
				
			||||
function user_filter($name, $params, $row) | 
				
			||||
{ | 
				
			||||
    return '<a href="'.api_get_path(WEB_PATH).'whoisonline.php?origin=user_list&id='.$row[0].'">'.$name.'</a>'; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
function requestTypeFilter($fieldId, $url_params, $row) | 
				
			||||
{ | 
				
			||||
    $extraFields = Session::read('data_privacy_extra_fields'); | 
				
			||||
    $extraFieldId = $extraFields['delete_legal']; | 
				
			||||
 | 
				
			||||
    if ($fieldId == $extraFieldId) { | 
				
			||||
        return get_lang('DeleteLegal'); | 
				
			||||
    } else { | 
				
			||||
        return get_lang('DeleteAccount'); | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Build the modify-column of the table. | 
				
			||||
 * | 
				
			||||
 * @param   int     The user id | 
				
			||||
 * @param   string  URL params to add to table links | 
				
			||||
 * @param   array   Row of elements to alter | 
				
			||||
 * | 
				
			||||
 * @throws Exception | 
				
			||||
 * | 
				
			||||
 * @return string Some HTML-code with modify-buttons | 
				
			||||
 */ | 
				
			||||
function modify_filter($user_id, $url_params, $row) | 
				
			||||
{ | 
				
			||||
    $_admins_list = Session::read('admin_list', []); | 
				
			||||
    $is_admin = in_array($user_id, $_admins_list); | 
				
			||||
    $token = Security::getTokenFromSession(); | 
				
			||||
    $result = ''; | 
				
			||||
    $result .= '<a href="user_information.php?user_id='.$user_id.'">'. | 
				
			||||
        Display::return_icon('synthese_view.gif', get_lang('Info')).'</a>  '; | 
				
			||||
 | 
				
			||||
    $result .= Display::url( | 
				
			||||
        Display::return_icon('message_new.png'), | 
				
			||||
        api_get_path(WEB_CODE_PATH).'messages/new_message.php?send_to_user='.$user_id | 
				
			||||
    ); | 
				
			||||
    $result .= '  '; | 
				
			||||
    $extraFields = Session::read('data_privacy_extra_fields'); | 
				
			||||
    $extraFieldId = $extraFields['delete_legal']; | 
				
			||||
 | 
				
			||||
    if ($row[10] == $extraFieldId) { | 
				
			||||
        $result .= Display::url( | 
				
			||||
            get_lang('RemoveTerms'), | 
				
			||||
            api_get_self().'?user_id='.$user_id.'&action=delete_terms&sec_token='.$token | 
				
			||||
        ); | 
				
			||||
        $result .= '  '; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    $result .= ' <a href="'.api_get_self().'?action=anonymize&user_id='.$user_id.'&'.$url_params.'&sec_token='.$token.'"  onclick="javascript:if(!confirm('."'".addslashes( | 
				
			||||
            api_htmlentities(get_lang('ConfirmYourChoice')) | 
				
			||||
        )."'".')) return false;">'. | 
				
			||||
        Display::return_icon( | 
				
			||||
            'anonymous.png', | 
				
			||||
            get_lang('Anonymize'), | 
				
			||||
            [], | 
				
			||||
            ICON_SIZE_SMALL | 
				
			||||
        ). | 
				
			||||
        '</a>'; | 
				
			||||
 | 
				
			||||
    if ($user_id != api_get_user_id()) { | 
				
			||||
        $result .= ' <a href="'.api_get_self().'?action=delete_user&user_id='.$user_id.'&'.$url_params.'&sec_token='.$token.'"  onclick="javascript:if(!confirm('."'".addslashes( | 
				
			||||
            api_htmlentities(get_lang('ConfirmYourChoice')) | 
				
			||||
        )."'".')) return false;">'. | 
				
			||||
        Display::return_icon( | 
				
			||||
            'delete.png', | 
				
			||||
            get_lang('Delete'), | 
				
			||||
            [], | 
				
			||||
            ICON_SIZE_SMALL | 
				
			||||
        ). | 
				
			||||
        '</a>'; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    $editProfileUrl = Display::getProfileEditionLink($user_id, true); | 
				
			||||
 | 
				
			||||
    $result .= '<a href="'.$editProfileUrl.'">'. | 
				
			||||
        Display::return_icon( | 
				
			||||
            'edit.png', | 
				
			||||
            get_lang('Edit'), | 
				
			||||
            [], | 
				
			||||
            ICON_SIZE_SMALL | 
				
			||||
        ). | 
				
			||||
        '</a> '; | 
				
			||||
 | 
				
			||||
    if ($is_admin) { | 
				
			||||
        $result .= Display::return_icon( | 
				
			||||
            'admin_star.png', | 
				
			||||
            get_lang('IsAdministrator'), | 
				
			||||
            ['width' => ICON_SIZE_SMALL, 'heigth' => ICON_SIZE_SMALL] | 
				
			||||
        ); | 
				
			||||
    } else { | 
				
			||||
        $result .= Display::return_icon( | 
				
			||||
            'admin_star_na.png', | 
				
			||||
            get_lang('IsNotAdministrator') | 
				
			||||
        ); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    return $result; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Build the active-column of the table to lock or unlock a certain user | 
				
			||||
 * lock = the user can no longer use this account. | 
				
			||||
 * | 
				
			||||
 * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University | 
				
			||||
 * | 
				
			||||
 * @param int    $active the current state of the account | 
				
			||||
 * @param string $params | 
				
			||||
 * @param array  $row | 
				
			||||
 * | 
				
			||||
 * @return string Some HTML-code with the lock/unlock button | 
				
			||||
 */ | 
				
			||||
function active_filter($active, $params, $row) | 
				
			||||
{ | 
				
			||||
    $_user = api_get_user_info(); | 
				
			||||
 | 
				
			||||
    if ($active == '1') { | 
				
			||||
        $action = 'Lock'; | 
				
			||||
        $image = 'accept'; | 
				
			||||
    } elseif ($active == '-1') { | 
				
			||||
        $action = 'edit'; | 
				
			||||
        $image = 'warning'; | 
				
			||||
    } elseif ($active == '0') { | 
				
			||||
        $action = 'Unlock'; | 
				
			||||
        $image = 'error'; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    $result = ''; | 
				
			||||
 | 
				
			||||
    if ($action === 'edit') { | 
				
			||||
        $result = Display::return_icon( | 
				
			||||
            $image.'.png', | 
				
			||||
            get_lang('AccountExpired'), | 
				
			||||
            [], | 
				
			||||
            16 | 
				
			||||
        ); | 
				
			||||
    } elseif ($row['0'] != $_user['user_id']) { | 
				
			||||
        // you cannot lock yourself out otherwise you could disable all the | 
				
			||||
        // accounts including your own => everybody is locked out and nobody | 
				
			||||
        // can change it anymore. | 
				
			||||
        $result = Display::return_icon( | 
				
			||||
            $image.'.png', | 
				
			||||
            get_lang(ucfirst($action)), | 
				
			||||
            ['onclick' => 'active_user(this);', 'id' => 'img_'.$row['0']], | 
				
			||||
            16 | 
				
			||||
        ); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    return $result; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Instead of displaying the integer of the status, we give a translation for the status. | 
				
			||||
 * | 
				
			||||
 * @param int $status | 
				
			||||
 * | 
				
			||||
 * @return string translation | 
				
			||||
 * | 
				
			||||
 * @version march 2008 | 
				
			||||
 * | 
				
			||||
 * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium | 
				
			||||
 */ | 
				
			||||
function status_filter($status) | 
				
			||||
{ | 
				
			||||
    $statusname = api_get_status_langvars(); | 
				
			||||
 | 
				
			||||
    return $statusname[$status]; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
if (isset($_GET['keyword']) || isset($_GET['keyword_firstname'])) { | 
				
			||||
    $interbreadcrumb[] = ['url' => 'index.php', 'name' => get_lang('PlatformAdmin')]; | 
				
			||||
    $interbreadcrumb[] = ['url' => 'user_list_consent.php', 'name' => get_lang('UserList')]; | 
				
			||||
    $tool_name = get_lang('SearchUsers'); | 
				
			||||
} else { | 
				
			||||
    $interbreadcrumb[] = ['url' => 'index.php', 'name' => get_lang('PlatformAdmin')]; | 
				
			||||
    $tool_name = get_lang('UserList'); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
$message = ''; | 
				
			||||
 | 
				
			||||
if (!empty($action)) { | 
				
			||||
    $check = Security::check_token('get'); | 
				
			||||
    if ($check) { | 
				
			||||
        switch ($action) { | 
				
			||||
            case 'delete_terms': | 
				
			||||
                $extraFieldValue = new ExtraFieldValue('user'); | 
				
			||||
                $value = $extraFieldValue->get_values_by_handler_and_field_variable( | 
				
			||||
                    $_GET['user_id'], | 
				
			||||
                    'legal_accept' | 
				
			||||
                ); | 
				
			||||
                $result = $extraFieldValue->delete($value['id']); | 
				
			||||
 | 
				
			||||
                $value = $extraFieldValue->get_values_by_handler_and_field_variable( | 
				
			||||
                    $_GET['user_id'], | 
				
			||||
                    'request_for_legal_agreement_consent_removal' | 
				
			||||
                ); | 
				
			||||
                $result = $extraFieldValue->delete($value['id']); | 
				
			||||
 | 
				
			||||
                Display::addFlash(Display::return_message(get_lang('Deleted'))); | 
				
			||||
                header('Location: '.api_get_self()); | 
				
			||||
                exit; | 
				
			||||
 | 
				
			||||
                break; | 
				
			||||
            case 'delete_user': | 
				
			||||
                $message = UserManager::deleteUserWithVerification($_GET['user_id']); | 
				
			||||
                Display::addFlash($message); | 
				
			||||
                header('Location: '.api_get_self()); | 
				
			||||
                exit; | 
				
			||||
                break; | 
				
			||||
            case 'delete': | 
				
			||||
                if (api_is_platform_admin()) { | 
				
			||||
                    $number_of_selected_users = count($_POST['id']); | 
				
			||||
                    $number_of_affected_users = 0; | 
				
			||||
                    if (is_array($_POST['id'])) { | 
				
			||||
                        foreach ($_POST['id'] as $index => $user_id) { | 
				
			||||
                            if ($user_id != $_user['user_id']) { | 
				
			||||
                                if (UserManager::delete_user($user_id)) { | 
				
			||||
                                    $number_of_affected_users++; | 
				
			||||
                                } | 
				
			||||
                            } | 
				
			||||
                        } | 
				
			||||
                    } | 
				
			||||
                    if ($number_of_selected_users == $number_of_affected_users) { | 
				
			||||
                        $message = Display::return_message( | 
				
			||||
                            get_lang('SelectedUsersDeleted'), | 
				
			||||
                            'confirmation' | 
				
			||||
                        ); | 
				
			||||
                    } else { | 
				
			||||
                        $message = Display::return_message( | 
				
			||||
                            get_lang('SomeUsersNotDeleted'), | 
				
			||||
                            'error' | 
				
			||||
                        ); | 
				
			||||
                    } | 
				
			||||
                } | 
				
			||||
                break; | 
				
			||||
            case 'anonymize': | 
				
			||||
                $message = UserManager::anonymizeUserWithVerification($_GET['user_id']); | 
				
			||||
                Display::addFlash($message); | 
				
			||||
                header('Location: '.api_get_self()); | 
				
			||||
                exit; | 
				
			||||
                break; | 
				
			||||
        } | 
				
			||||
        Security::clear_token(); | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
// Create a search-box | 
				
			||||
$form = new FormValidator('search_simple', 'get', null, null, null, 'inline'); | 
				
			||||
$form->addText( | 
				
			||||
    'keyword', | 
				
			||||
    get_lang('Search'), | 
				
			||||
    false, | 
				
			||||
    [ | 
				
			||||
        'aria-label' => get_lang('SearchUsers'), | 
				
			||||
    ] | 
				
			||||
); | 
				
			||||
$form->addButtonSearch(get_lang('Search')); | 
				
			||||
 | 
				
			||||
$actionsLeft = ''; | 
				
			||||
$actionsCenter = ''; | 
				
			||||
$actionsRight = ''; | 
				
			||||
$actionsLeft .= $form->returnForm(); | 
				
			||||
 | 
				
			||||
if (isset($_GET['keyword'])) { | 
				
			||||
    $parameters = ['keyword' => Security::remove_XSS($_GET['keyword'])]; | 
				
			||||
} elseif (isset($_GET['keyword_firstname'])) { | 
				
			||||
    $parameters['keyword_firstname'] = Security::remove_XSS($_GET['keyword_firstname']); | 
				
			||||
    $parameters['keyword_lastname'] = Security::remove_XSS($_GET['keyword_lastname']); | 
				
			||||
    $parameters['keyword_username'] = Security::remove_XSS($_GET['keyword_username']); | 
				
			||||
    $parameters['keyword_email'] = Security::remove_XSS($_GET['keyword_email']); | 
				
			||||
    $parameters['keyword_officialcode'] = Security::remove_XSS($_GET['keyword_officialcode']); | 
				
			||||
    $parameters['keyword_status'] = Security::remove_XSS($_GET['keyword_status']); | 
				
			||||
    $parameters['keyword_active'] = Security::remove_XSS($_GET['keyword_active']); | 
				
			||||
    $parameters['keyword_inactive'] = Security::remove_XSS($_GET['keyword_inactive']); | 
				
			||||
} | 
				
			||||
// Create a sortable table with user-data | 
				
			||||
$parameters['sec_token'] = Security::get_token(); | 
				
			||||
 | 
				
			||||
$_admins_list = array_keys(UserManager::get_all_administrators()); | 
				
			||||
Session::write('admin_list', $_admins_list); | 
				
			||||
// Display Advanced search form. | 
				
			||||
$form = new FormValidator( | 
				
			||||
    'advanced_search', | 
				
			||||
    'get', | 
				
			||||
    '', | 
				
			||||
    '', | 
				
			||||
    [], | 
				
			||||
    FormValidator::LAYOUT_HORIZONTAL | 
				
			||||
); | 
				
			||||
 | 
				
			||||
$form->addElement('html', '<div id="advanced_search_form" style="display:none;">'); | 
				
			||||
$form->addElement('header', get_lang('AdvancedSearch')); | 
				
			||||
$form->addText('keyword_firstname', get_lang('FirstName'), false); | 
				
			||||
$form->addText('keyword_lastname', get_lang('LastName'), false); | 
				
			||||
$form->addText('keyword_username', get_lang('LoginName'), false); | 
				
			||||
$form->addText('keyword_email', get_lang('Email'), false); | 
				
			||||
$form->addText('keyword_officialcode', get_lang('OfficialCode'), false); | 
				
			||||
 | 
				
			||||
$status_options = []; | 
				
			||||
$status_options['%'] = get_lang('All'); | 
				
			||||
$status_options[STUDENT] = get_lang('Student'); | 
				
			||||
$status_options[COURSEMANAGER] = get_lang('Teacher'); | 
				
			||||
$status_options[DRH] = get_lang('Drh'); | 
				
			||||
$status_options[SESSIONADMIN] = get_lang('SessionsAdmin'); | 
				
			||||
$status_options[PLATFORM_ADMIN] = get_lang('Administrator'); | 
				
			||||
 | 
				
			||||
$form->addElement( | 
				
			||||
    'select', | 
				
			||||
    'keyword_status', | 
				
			||||
    get_lang('Profile'), | 
				
			||||
    $status_options | 
				
			||||
); | 
				
			||||
$form->addButtonSearch(get_lang('SearchUsers')); | 
				
			||||
 | 
				
			||||
$defaults = []; | 
				
			||||
$defaults['keyword_active'] = 1; | 
				
			||||
$defaults['keyword_inactive'] = 1; | 
				
			||||
$form->setDefaults($defaults); | 
				
			||||
$form->addElement('html', '</div>'); | 
				
			||||
 | 
				
			||||
$form = $form->returnForm(); | 
				
			||||
 | 
				
			||||
$table = new SortableTable( | 
				
			||||
    'users', | 
				
			||||
    'get_number_of_users', | 
				
			||||
    'get_user_data', | 
				
			||||
    (api_is_western_name_order() xor api_sort_by_first_name()) ? 3 : 2 | 
				
			||||
); | 
				
			||||
$table->set_additional_parameters($parameters); | 
				
			||||
$table->set_header(0, '', false, 'width="18px"'); | 
				
			||||
$table->set_header(1, get_lang('Photo'), false); | 
				
			||||
$table->set_header(2, get_lang('OfficialCode')); | 
				
			||||
 | 
				
			||||
if (api_is_western_name_order()) { | 
				
			||||
    $table->set_header(3, get_lang('FirstName')); | 
				
			||||
    $table->set_header(4, get_lang('LastName')); | 
				
			||||
} else { | 
				
			||||
    $table->set_header(3, get_lang('LastName')); | 
				
			||||
    $table->set_header(4, get_lang('FirstName')); | 
				
			||||
} | 
				
			||||
$table->set_header(5, get_lang('LoginName')); | 
				
			||||
$table->set_header(6, get_lang('Email')); | 
				
			||||
$table->set_header(7, get_lang('Profile')); | 
				
			||||
$table->set_header(8, get_lang('Active'), true, 'width="15px"'); | 
				
			||||
$table->set_header(9, get_lang('RegistrationDate'), true, 'width="90px"'); | 
				
			||||
$table->set_header(10, get_lang('RequestType'), true, 'width="15px"'); | 
				
			||||
$table->set_header(11, get_lang('Action'), false, 'width="220px"'); | 
				
			||||
 | 
				
			||||
$table->set_column_filter(3, 'user_filter'); | 
				
			||||
$table->set_column_filter(4, 'user_filter'); | 
				
			||||
$table->set_column_filter(6, 'email_filter'); | 
				
			||||
$table->set_column_filter(7, 'status_filter'); | 
				
			||||
$table->set_column_filter(8, 'active_filter'); | 
				
			||||
$table->set_column_filter(11, 'modify_filter'); | 
				
			||||
$table->set_column_filter(10, 'requestTypeFilter'); | 
				
			||||
 | 
				
			||||
// Only show empty actions bar if delete users has been blocked | 
				
			||||
$actionsList = []; | 
				
			||||
if (api_is_platform_admin() && | 
				
			||||
    !api_get_configuration_value('deny_delete_users') | 
				
			||||
) { | 
				
			||||
    $actionsList['delete'] = get_lang('DeleteFromPlatform'); | 
				
			||||
} | 
				
			||||
$actionsList['disable'] = get_lang('Disable'); | 
				
			||||
$actionsList['enable'] = get_lang('Enable'); | 
				
			||||
$table->set_form_actions($actionsList); | 
				
			||||
 | 
				
			||||
$table_result = $table->return_table(); | 
				
			||||
$extra_search_options = ''; | 
				
			||||
$toolbarActions = Display::toolbarAction( | 
				
			||||
    'toolbarUser', | 
				
			||||
    [$actionsLeft, $actionsCenter, $actionsRight], | 
				
			||||
    [4, 4, 4] | 
				
			||||
); | 
				
			||||
 | 
				
			||||
$notice = Display::return_message(get_lang('InformationRightToBeForgottenText'), 'normal', false); | 
				
			||||
 | 
				
			||||
$tpl = new Template($tool_name); | 
				
			||||
$tpl->assign('actions', $toolbarActions); | 
				
			||||
$tpl->assign('message', $message); | 
				
			||||
$tpl->assign('content', $form.$table_result.$extra_search_options.$notice); | 
				
			||||
$tpl->display_one_col_template(); | 
				
			||||
@ -0,0 +1,321 @@ | 
				
			||||
<?php | 
				
			||||
/* For licensing terms, see /license.txt */ | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 *  @package chamilo.admin | 
				
			||||
 */ | 
				
			||||
$cidReset = true; | 
				
			||||
require_once __DIR__.'/../inc/global.inc.php'; | 
				
			||||
 | 
				
			||||
$this_section = SECTION_PLATFORM_ADMIN; | 
				
			||||
 | 
				
			||||
$id = isset($_GET['id']) ? (int) $_GET['id'] : 0; | 
				
			||||
 | 
				
			||||
$usergroup = new UserGroup(); | 
				
			||||
$userGroupInfo = $usergroup->get($id); | 
				
			||||
 | 
				
			||||
if (empty($userGroupInfo)) { | 
				
			||||
    api_not_allowed(true); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
$usergroup->protectScript($userGroupInfo); | 
				
			||||
 | 
				
			||||
$calendarPlugin = null; | 
				
			||||
if (api_get_plugin_setting('learning_calendar', 'enabled') === 'true') { | 
				
			||||
    $calendarPlugin = LearningCalendarPlugin::create(); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
// Add the JS needed to use the jqgrid | 
				
			||||
$htmlHeadXtra[] = api_get_jqgrid_js(); | 
				
			||||
$action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : null; | 
				
			||||
$userId = isset($_GET['user_id']) ? (int) $_GET['user_id'] : 0; | 
				
			||||
$calendarId = isset($_REQUEST['calendar_id']) ? (int) $_REQUEST['calendar_id'] : 0; | 
				
			||||
 | 
				
			||||
// setting breadcrumbs | 
				
			||||
$interbreadcrumb[] = ['url' => 'usergroups.php', 'name' => get_lang('Classes')]; | 
				
			||||
$interbreadcrumb[] = ['url' => '#', 'name' => $userGroupInfo['name']]; | 
				
			||||
 | 
				
			||||
switch ($action) { | 
				
			||||
    case 'add_calendar': | 
				
			||||
        $form = new FormValidator( | 
				
			||||
            'add_calendar', | 
				
			||||
            'post', | 
				
			||||
            api_get_self().'?id='.$id.'&user_id='.$userId.'&action=add_calendar' | 
				
			||||
        ); | 
				
			||||
 | 
				
			||||
        $userInfo = api_get_user_info($userId); | 
				
			||||
        $form->addHeader($userInfo['complete_name']); | 
				
			||||
        $calendarPlugin->getAddUserToCalendarForm($form); | 
				
			||||
        $form->addButtonSave(get_lang('Add')); | 
				
			||||
        $form->display(); | 
				
			||||
 | 
				
			||||
        if ($form->validate()) { | 
				
			||||
            $calendarId = $form->getSubmitValue('calendar_id'); | 
				
			||||
            if (!empty($calendarId)) { | 
				
			||||
                $calendarPlugin->addUserToCalendar($calendarId, $userId); | 
				
			||||
                Display::addFlash(Display::return_message(get_lang('Added'), 'confirmation')); | 
				
			||||
                header('Location: '.api_get_self().'?id='.$id); | 
				
			||||
                exit; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        exit; | 
				
			||||
        break; | 
				
			||||
    case 'edit_calendar': | 
				
			||||
        $form = new FormValidator( | 
				
			||||
            'add_calendar', | 
				
			||||
            'post', | 
				
			||||
            api_get_self().'?id='.$id.'&user_id='.$userId.'&action=edit_calendar&calendar_id='.$calendarId | 
				
			||||
        ); | 
				
			||||
        $userInfo = api_get_user_info($userId); | 
				
			||||
        $form->addHeader($userInfo['complete_name']); | 
				
			||||
        $calendarPlugin->getAddUserToCalendarForm($form); | 
				
			||||
        $form->setDefaults(['calendar_id' => $calendarId]); | 
				
			||||
        $form->addButtonSave(get_lang('Update')); | 
				
			||||
        $form->display(); | 
				
			||||
 | 
				
			||||
        if ($form->validate()) { | 
				
			||||
            $calendarId = $form->getSubmitValue('calendar_id'); | 
				
			||||
            if (!empty($calendarId)) { | 
				
			||||
                $calendarPlugin->updateUserToCalendar($calendarId, $userId); | 
				
			||||
                Display::addFlash(Display::return_message(get_lang('Added'), 'confirmation')); | 
				
			||||
                header('Location: '.api_get_self().'?id='.$id); | 
				
			||||
                exit; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        exit; | 
				
			||||
        break; | 
				
			||||
    case 'delete': | 
				
			||||
        $res = $usergroup->delete_user_rel_group($_GET['user_id'], $_GET['id']); | 
				
			||||
        Display::addFlash(Display::return_message(get_lang('Deleted'), 'confirmation')); | 
				
			||||
        header('Location: '.api_get_self().'?id='.$id); | 
				
			||||
        exit; | 
				
			||||
        break; | 
				
			||||
    case 'create_control_point': | 
				
			||||
        $value = isset($_GET['value']) ? (int) $_GET['value'] : 0; | 
				
			||||
        $calendarPlugin->addControlPoint($userId, $value); | 
				
			||||
        Display::addFlash( | 
				
			||||
            Display::return_message($calendarPlugin->get_lang('ControlPointAdded'), 'confirmation') | 
				
			||||
        ); | 
				
			||||
        header('Location: '.api_get_self().'?id='.$id); | 
				
			||||
        exit; | 
				
			||||
    case 'add_multiple_users_to_calendar': | 
				
			||||
        $userList = isset($_REQUEST['user_list']) ? explode(',', $_REQUEST['user_list']) : 0; | 
				
			||||
        foreach ($userList as $userId) { | 
				
			||||
            $isAdded = $calendarPlugin->addUserToCalendar($calendarId, $userId); | 
				
			||||
            if (!$isAdded) { | 
				
			||||
                $isAdded = $calendarPlugin->updateUserToCalendar($calendarId, $userId); | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        Display::addFlash( | 
				
			||||
            Display::return_message(get_lang('Added'), 'confirmation') | 
				
			||||
        ); | 
				
			||||
 | 
				
			||||
        header('Location: '.api_get_self().'?id='.$id); | 
				
			||||
        exit; | 
				
			||||
        break; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
Display::display_header(); | 
				
			||||
 | 
				
			||||
// jqgrid will use this URL to do the selects | 
				
			||||
$url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_usergroups_users&id='.$id; | 
				
			||||
 | 
				
			||||
// The order is important you need to check the the $column variable in the model.ajax.php file | 
				
			||||
$columns = [ | 
				
			||||
    get_lang('Name'), | 
				
			||||
    get_lang('Actions'), | 
				
			||||
]; | 
				
			||||
 | 
				
			||||
// Column config | 
				
			||||
$column_model = [ | 
				
			||||
    ['name' => 'name', 'index' => 'name', 'width' => '35', 'align' => 'left', 'sortable' => 'false'], | 
				
			||||
    [ | 
				
			||||
        'name' => 'actions', | 
				
			||||
        'index' => 'actions', | 
				
			||||
        'width' => '20', | 
				
			||||
        'align' => 'center', | 
				
			||||
        'sortable' => 'false', | 
				
			||||
        'formatter' => 'action_formatter', | 
				
			||||
    ], | 
				
			||||
]; | 
				
			||||
 | 
				
			||||
if (api_get_plugin_setting('learning_calendar', 'enabled') === 'true') { | 
				
			||||
    $columns = [ | 
				
			||||
        get_lang('Name'), | 
				
			||||
        get_lang('Calendar'), | 
				
			||||
        get_lang('ClassroomActivity'), | 
				
			||||
        get_lang('TimeSpentByStudentsInCourses'), | 
				
			||||
        $calendarPlugin->get_lang('NumberDaysAccumulatedInCalendar'), | 
				
			||||
        $calendarPlugin->get_lang('DifferenceOfDaysAndCalendar'), | 
				
			||||
        get_lang('Actions'), | 
				
			||||
    ]; | 
				
			||||
 | 
				
			||||
    // Column config | 
				
			||||
    $column_model = [ | 
				
			||||
        ['name' => 'name', 'index' => 'name', 'width' => '35', 'align' => 'left', 'sortable' => 'false'], | 
				
			||||
        [ | 
				
			||||
            'name' => 'calendar', | 
				
			||||
            'index' => 'calendar', | 
				
			||||
            'width' => '35', | 
				
			||||
            'align' => 'left', | 
				
			||||
            'sortable' => 'false', | 
				
			||||
            'formatter' => 'extra_formatter', | 
				
			||||
        ], | 
				
			||||
        [ | 
				
			||||
            'name' => 'gradebook_items', | 
				
			||||
            'index' => 'gradebook_items', | 
				
			||||
            'width' => '35', | 
				
			||||
            'align' => 'left', | 
				
			||||
            'sortable' => 'false', | 
				
			||||
        ], | 
				
			||||
        ['name' => 'time_spent', 'index' => 'time_spent', 'width' => '35', 'align' => 'left', 'sortable' => 'false'], | 
				
			||||
        [ | 
				
			||||
            'name' => 'lp_day_completed', | 
				
			||||
            'index' => 'lp_day_completed', | 
				
			||||
            'width' => '35', | 
				
			||||
            'align' => 'left', | 
				
			||||
            'sortable' => 'false', | 
				
			||||
        ], | 
				
			||||
        ['name' => 'days_diff', 'index' => 'days_diff', 'width' => '35', 'align' => 'left', 'sortable' => 'false'], | 
				
			||||
        [ | 
				
			||||
            'name' => 'actions', | 
				
			||||
            'index' => 'actions', | 
				
			||||
            'width' => '20', | 
				
			||||
            'align' => 'center', | 
				
			||||
            'sortable' => 'false', | 
				
			||||
            'formatter' => 'action_formatter', | 
				
			||||
        ], | 
				
			||||
    ]; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
// Autowidth | 
				
			||||
$extraParams['autowidth'] = 'true'; | 
				
			||||
// height auto | 
				
			||||
$extraParams['height'] = 'auto'; | 
				
			||||
$extraParams['sortname'] = 'name'; | 
				
			||||
$extraParams['sortorder'] = 'desc'; | 
				
			||||
$extraParams['multiselect'] = true; | 
				
			||||
 | 
				
			||||
$deleteIcon = Display::return_icon('delete.png', get_lang('Delete'), null, ICON_SIZE_SMALL); | 
				
			||||
$urlStats = api_get_path(WEB_CODE_PATH); | 
				
			||||
 | 
				
			||||
//$addCalendar = '<a href="'.$urlStats.'mySpace/myStudents.php?student=\'+options.rowId+\'">'.Display::return_icon('agenda.png', get_lang('Agenda'), '', ICON_SIZE_SMALL).'</a>'; | 
				
			||||
 | 
				
			||||
$reportingIcon = Display::return_icon('stats.png', get_lang('Reporting'), '', ICON_SIZE_SMALL); | 
				
			||||
$controlPoint = Display::return_icon('add.png', get_lang('ControlPoint'), '', ICON_SIZE_SMALL); | 
				
			||||
 | 
				
			||||
//return \'<a href="session_edit.php?page=resume_session.php&id=\'+options.rowId+\'">'.Display::return_icon('edit.png', get_lang('Edit'), '', ICON_SIZE_SMALL).'</a>'. | 
				
			||||
// With this function we can add actions to the jgrid | 
				
			||||
$action_links = ' | 
				
			||||
function action_formatter(cellvalue, options, rowObject) { | 
				
			||||
    var value = rowObject[5]; | 
				
			||||
    return \''. | 
				
			||||
    ' <a href="'.$urlStats.'admin/usergroup_users.php?action=create_control_point&value=\'+value+\'&id='.$id.'&user_id=\'+options.rowId+\'">'.$controlPoint.'</a>'. | 
				
			||||
    ' <a href="'.$urlStats.'mySpace/myStudents.php?student=\'+options.rowId+\'">'.$reportingIcon.'</a>'. | 
				
			||||
    ' <a onclick="javascript:if(!confirm('."\'".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES))."\'".')) return false;" href="?id='.$id.'&action=delete&user_id=\'+options.rowId+\'">'.$deleteIcon.'</a>\'; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
function extra_formatter(cellvalue, options, rowObject) { | 
				
			||||
    var calendarName = rowObject[1]; | 
				
			||||
    var calendarId = rowObject[7]; | 
				
			||||
     | 
				
			||||
    if (calendarName == "") {           | 
				
			||||
        return \'<a href="'. | 
				
			||||
        api_get_path(WEB_CODE_PATH).'admin/usergroup_users.php?user_id=\'+options.rowId+\'&id='.$id.'&action=add_calendar&width=700" class="btn btn-primary ajax">'.get_lang('Add').'</a>\'; | 
				
			||||
    } else { | 
				
			||||
    return \' \'+calendarName+\' <a href="'. | 
				
			||||
        api_get_path(WEB_CODE_PATH).'admin/usergroup_users.php?calendar_id=\'+calendarId+\'&user_id=\'+options.rowId+\'&id='.$id.'&action=edit_calendar&width=700" class="btn btn-primary ajax"> '.get_lang('Edit').'</a>\'; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    return calendarName; | 
				
			||||
 | 
				
			||||
    return \''. | 
				
			||||
    ' <a href="'.$urlStats.'mySpace/myStudents.php?student=\'+options.rowId+\'">'.Display::return_icon('stats.png', get_lang('Reporting'), '', ICON_SIZE_SMALL).'</a>'. | 
				
			||||
    ' <a onclick="javascript:if(!confirm('."\'".addslashes(api_htmlentities(get_lang("ConfirmYourChoice"), ENT_QUOTES))."\'".')) return false;"  href="?id='.$id.'&action=delete&user_id=\'+options.rowId+\'">'.$deleteIcon.'</a>\'; | 
				
			||||
}'; | 
				
			||||
 | 
				
			||||
$deleteUrl = api_get_path(WEB_AJAX_PATH).'usergroup.ajax.php?a=delete_user_in_usergroup&group_id='.$id; | 
				
			||||
 | 
				
			||||
$form = new FormValidator( | 
				
			||||
    'add_multiple_calendar', | 
				
			||||
    'post', | 
				
			||||
    api_get_self().'?id='.$id.'&action=add_multiple_users_to_calendar' | 
				
			||||
); | 
				
			||||
$calendarPlugin->getAddUserToCalendarForm($form); | 
				
			||||
$form->addHidden('user_list', ''); | 
				
			||||
$form->addButtonSave(get_lang('Add')); | 
				
			||||
 | 
				
			||||
?> | 
				
			||||
<script> | 
				
			||||
$(function() { | 
				
			||||
<?php | 
				
			||||
    // grid definition see the $usergroup>display() function | 
				
			||||
    echo Display::grid_js( | 
				
			||||
        'usergroups', | 
				
			||||
        $url, | 
				
			||||
        $columns, | 
				
			||||
        $column_model, | 
				
			||||
        $extraParams, | 
				
			||||
        [], | 
				
			||||
        $action_links, | 
				
			||||
        true | 
				
			||||
    ); | 
				
			||||
?> | 
				
			||||
    $("#usergroups").jqGrid( | 
				
			||||
        "navGrid", | 
				
			||||
        "#usergroups_pager", | 
				
			||||
        { edit: false, add: false, del: true, search: false}, | 
				
			||||
        { height:280, reloadAfterSubmit:false }, // edit options | 
				
			||||
        { height:280, reloadAfterSubmit:false }, // add options | 
				
			||||
        { reloadAfterSubmit:false, url: "<?php echo $deleteUrl; ?>" }, // del options
 | 
				
			||||
        { width:500 } // search options | 
				
			||||
    ) | 
				
			||||
    .navButtonAdd('#usergroups_pager',{ | 
				
			||||
        caption:"<?php echo addslashes($calendarPlugin->get_lang('UpdateCalendar')); ?>",
 | 
				
			||||
        buttonicon:"ui-icon ui-icon-plus", | 
				
			||||
        onClickButton: function(a) { | 
				
			||||
            var userIdList = $("#usergroups").jqGrid('getGridParam', 'selarrrow'); | 
				
			||||
            if (userIdList.length) { | 
				
			||||
                $(".modal-body #add_multiple_calendar_user_list").val(userIdList); | 
				
			||||
                $('#myModal').modal(); | 
				
			||||
            } else { | 
				
			||||
                alert("<?php echo addslashes(get_lang('SelectStudents')); ?>");
 | 
				
			||||
            } | 
				
			||||
        }, | 
				
			||||
        position:"last" | 
				
			||||
    }); | 
				
			||||
}); | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> | 
				
			||||
    <div class="modal-dialog" role="document"> | 
				
			||||
        <div class="modal-content"> | 
				
			||||
            <div class="modal-header"> | 
				
			||||
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"> | 
				
			||||
                    <span aria-hidden="true">×</span></button> | 
				
			||||
                <h4 class="modal-title" id="myModalLabel"> | 
				
			||||
                    <?php echo $calendarPlugin->get_lang('AddMultipleUsersToCalendar'); ?> | 
				
			||||
                </h4> | 
				
			||||
            </div> | 
				
			||||
            <div class="modal-body"> | 
				
			||||
                <?php echo $form->display(); ?> | 
				
			||||
            </div> | 
				
			||||
        </div> | 
				
			||||
    </div> | 
				
			||||
</div> | 
				
			||||
 | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
$usergroup->showGroupTypeSetting = true; | 
				
			||||
// Action handling: Adding a note | 
				
			||||
if ($action === 'delete' && is_numeric($_GET['id'])) { | 
				
			||||
    $res = $usergroup->delete_user_rel_group($_GET['user_id'], $_GET['id']); | 
				
			||||
    Display::addFlash(Display::return_message(get_lang('Deleted'), 'confirmation')); | 
				
			||||
    header('Location: '.api_get_self().'?id='.$id); | 
				
			||||
    exit; | 
				
			||||
} else { | 
				
			||||
    $usergroup->displayToolBarUserGroupUsers(); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
Display::display_footer(); | 
				
			||||
@ -0,0 +1,173 @@ | 
				
			||||
<?php | 
				
			||||
/* For licensing terms, see /license.txt */ | 
				
			||||
 | 
				
			||||
use Chamilo\CoreBundle\Entity\Course; | 
				
			||||
use Chamilo\CoreBundle\Entity\CourseRelUser; | 
				
			||||
use Chamilo\CoreBundle\Entity\ExtraField; | 
				
			||||
use Chamilo\CourseBundle\Entity\CCourseDescription; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Course about page | 
				
			||||
 * Show information about a course. | 
				
			||||
 * | 
				
			||||
 * @author Alex Aragon Calixto <alex.aragon@beeznest.com> | 
				
			||||
 * | 
				
			||||
 * @package chamilo.course | 
				
			||||
 */ | 
				
			||||
$cidReset = true; | 
				
			||||
 | 
				
			||||
require_once __DIR__.'/../inc/global.inc.php'; | 
				
			||||
 | 
				
			||||
$courseId = isset($_GET['course_id']) ? (int) $_GET['course_id'] : 0; | 
				
			||||
$token = Security::get_existing_token(); | 
				
			||||
$em = Database::getManager(); | 
				
			||||
//userID | 
				
			||||
$userId = api_get_user_id(); | 
				
			||||
 | 
				
			||||
/** @var Course $course */ | 
				
			||||
$course = $em->find('ChamiloCoreBundle:Course', $courseId); | 
				
			||||
 | 
				
			||||
if (!$course) { | 
				
			||||
    api_not_allowed(true); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
$userRepo = UserManager::getRepository(); | 
				
			||||
$fieldsRepo = $em->getRepository('ChamiloCoreBundle:ExtraField'); | 
				
			||||
$fieldTagsRepo = $em->getRepository('ChamiloCoreBundle:ExtraFieldRelTag'); | 
				
			||||
 | 
				
			||||
/** @var CCourseDescription $courseDescription */ | 
				
			||||
$courseDescriptionTools = $em->getRepository('ChamiloCourseBundle:CCourseDescription') | 
				
			||||
    ->findBy( | 
				
			||||
        [ | 
				
			||||
            'cId' => $course->getId(), | 
				
			||||
            'sessionId' => 0, | 
				
			||||
        ], | 
				
			||||
        [ | 
				
			||||
            'id' => 'DESC', | 
				
			||||
            'descriptionType' => 'ASC', | 
				
			||||
        ] | 
				
			||||
    ); | 
				
			||||
 | 
				
			||||
$courseValues = new ExtraFieldValue('course'); | 
				
			||||
$userValues = new ExtraFieldValue('user'); | 
				
			||||
 | 
				
			||||
$urlCourse = api_get_path(WEB_PATH).'main/course/about.php?course_id='.$courseId; | 
				
			||||
$courseTeachers = $course->getTeachers(); | 
				
			||||
$teachersData = []; | 
				
			||||
 | 
				
			||||
/** @var CourseRelUser $teacherSubscription */ | 
				
			||||
foreach ($courseTeachers as $teacherSubscription) { | 
				
			||||
    $teacher = $teacherSubscription->getUser(); | 
				
			||||
    $userData = [ | 
				
			||||
        'complete_name' => $teacher->getCompleteName(), | 
				
			||||
        'image' => UserManager::getUserPicture( | 
				
			||||
            $teacher->getId(), | 
				
			||||
            USER_IMAGE_SIZE_ORIGINAL | 
				
			||||
        ), | 
				
			||||
        'diploma' => $teacher->getDiplomas(), | 
				
			||||
        'openarea' => $teacher->getOpenarea(), | 
				
			||||
    ]; | 
				
			||||
 | 
				
			||||
    $teachersData[] = $userData; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
$tagField = $fieldsRepo->findOneBy([ | 
				
			||||
    'extraFieldType' => ExtraField::COURSE_FIELD_TYPE, | 
				
			||||
    'variable' => 'tags', | 
				
			||||
]); | 
				
			||||
 | 
				
			||||
$courseTags = []; | 
				
			||||
 | 
				
			||||
if (!is_null($tagField)) { | 
				
			||||
    $courseTags = $fieldTagsRepo->getTags($tagField, $courseId); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
$courseDescription = $courseObjectives = $courseTopics = $courseMethodology = $courseMaterial = $courseResources = $courseAssessment = ''; | 
				
			||||
$courseCustom = []; | 
				
			||||
foreach ($courseDescriptionTools as $descriptionTool) { | 
				
			||||
    switch ($descriptionTool->getDescriptionType()) { | 
				
			||||
        case CCourseDescription::TYPE_DESCRIPTION: | 
				
			||||
            $courseDescription = $descriptionTool->getContent(); | 
				
			||||
            break; | 
				
			||||
        case CCourseDescription::TYPE_OBJECTIVES: | 
				
			||||
            $courseObjectives = $descriptionTool; | 
				
			||||
            break; | 
				
			||||
        case CCourseDescription::TYPE_TOPICS: | 
				
			||||
            $courseTopics = $descriptionTool; | 
				
			||||
            break; | 
				
			||||
        case CCourseDescription::TYPE_METHODOLOGY: | 
				
			||||
            $courseMethodology = $descriptionTool; | 
				
			||||
            break; | 
				
			||||
        case CCourseDescription::TYPE_COURSE_MATERIAL: | 
				
			||||
            $courseMaterial = $descriptionTool; | 
				
			||||
            break; | 
				
			||||
        case CCourseDescription::TYPE_RESOURCES: | 
				
			||||
            $courseResources = $descriptionTool; | 
				
			||||
            break; | 
				
			||||
        case CCourseDescription::TYPE_ASSESSMENT: | 
				
			||||
            $courseAssessment = $descriptionTool; | 
				
			||||
            break; | 
				
			||||
        case CCourseDescription::TYPE_CUSTOM: | 
				
			||||
            $courseCustom[] = $descriptionTool; | 
				
			||||
            break; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
$topics = [ | 
				
			||||
    'objectives' => $courseObjectives, | 
				
			||||
    'topics' => $courseTopics, | 
				
			||||
    'methodology' => $courseMethodology, | 
				
			||||
    'material' => $courseMaterial, | 
				
			||||
    'resources' => $courseResources, | 
				
			||||
    'assessment' => $courseAssessment, | 
				
			||||
    'custom' => array_reverse($courseCustom), | 
				
			||||
]; | 
				
			||||
 | 
				
			||||
$subscriptionUser = CourseManager::is_user_subscribed_in_course($userId, $course->getCode()); | 
				
			||||
 | 
				
			||||
$plugin = BuyCoursesPlugin::create(); | 
				
			||||
$checker = $plugin->isEnabled(); | 
				
			||||
$courseIsPremium = null; | 
				
			||||
if ($checker) { | 
				
			||||
    $courseIsPremium = $plugin->getItemByProduct( | 
				
			||||
        $courseId, | 
				
			||||
        BuyCoursesPlugin::PRODUCT_TYPE_COURSE | 
				
			||||
    ); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
$courseItem = [ | 
				
			||||
    'code' => $course->getCode(), | 
				
			||||
    'title' => $course->getTitle(), | 
				
			||||
    'description' => $courseDescription, | 
				
			||||
    'image' => CourseManager::getPicturePath($course, true), | 
				
			||||
    'syllabus' => $topics, | 
				
			||||
    'tags' => $courseTags, | 
				
			||||
    'teachers' => $teachersData, | 
				
			||||
    'extra_fields' => $courseValues->getAllValuesForAnItem( | 
				
			||||
        $course->getId(), | 
				
			||||
        null, | 
				
			||||
        true | 
				
			||||
    ), | 
				
			||||
    'subscription' => $subscriptionUser, | 
				
			||||
]; | 
				
			||||
 | 
				
			||||
$metaInfo = '<meta property="og:url" content="'.$urlCourse.'" />'; | 
				
			||||
$metaInfo .= '<meta property="og:type" content="website" />'; | 
				
			||||
$metaInfo .= '<meta property="og:title" content="'.$courseItem['title'].'" />'; | 
				
			||||
$metaInfo .= '<meta property="og:description" content="'.$courseDescription.'" />'; | 
				
			||||
$metaInfo .= '<meta property="og:image" content="'.$courseItem['image'].'" />'; | 
				
			||||
 | 
				
			||||
$htmlHeadXtra[] = $metaInfo; | 
				
			||||
$htmlHeadXtra[] = api_get_asset('readmore-js/readmore.js'); | 
				
			||||
 | 
				
			||||
$template = new Template($course->getTitle(), true, true, false, true, false); | 
				
			||||
$template->assign('course', $courseItem); | 
				
			||||
$essence = Essence\Essence::instance(); | 
				
			||||
$template->assign('essence', $essence); | 
				
			||||
$template->assign('is_premium', $courseIsPremium); | 
				
			||||
$template->assign('token', $token); | 
				
			||||
$template->assign('url', $urlCourse); | 
				
			||||
$layout = $template->get_template('course_home/about.tpl'); | 
				
			||||
$content = $template->fetch($layout); | 
				
			||||
$template->assign('content', $content); | 
				
			||||
$template->display_one_col_template(); | 
				
			||||
									
										
											File diff suppressed because it is too large
											Load Diff
										
									
								
							
						@ -0,0 +1,80 @@ | 
				
			||||
<?php | 
				
			||||
/* For licensing terms, see /license.txt */ | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * This class handles the SCORM export of fill-in-the-blanks questions. | 
				
			||||
 * | 
				
			||||
 * @package chamilo.exercise.scorm | 
				
			||||
 */ | 
				
			||||
class ScormAnswerFillInBlanks extends Answer | 
				
			||||
{ | 
				
			||||
    /** | 
				
			||||
     * Export the text with missing words. | 
				
			||||
     * | 
				
			||||
     * As a side effect, it stores two lists in the class : | 
				
			||||
     * the missing words and their respective weightings. | 
				
			||||
     */ | 
				
			||||
    public function export() | 
				
			||||
    { | 
				
			||||
        $js = ''; | 
				
			||||
        // get all enclosed answers | 
				
			||||
        $blankList = []; | 
				
			||||
        foreach ($this->answer as $i => $answer) { | 
				
			||||
            $blankList[] = '['.$answer.']'; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        // splits text and weightings that are joined with the character '::' | 
				
			||||
        $listAnswerInfo = FillBlanks::getAnswerInfo($answer); | 
				
			||||
        //$switchableAnswerSet = $listAnswerInfo['switchable']; | 
				
			||||
 | 
				
			||||
        // display empty [input] with the right width for student to fill it | 
				
			||||
        $answer = ''; | 
				
			||||
        $answerList = []; | 
				
			||||
        for ($i = 0; $i < count($listAnswerInfo['common_words']) - 1; $i++) { | 
				
			||||
            // display the common words | 
				
			||||
            $answer .= $listAnswerInfo['common_words'][$i]; | 
				
			||||
            // display the blank word | 
				
			||||
            $attributes['style'] = 'width:'.$listAnswerInfo['input_size'][$i].'px'; | 
				
			||||
            $answer .= FillBlanks::getFillTheBlankHtml( | 
				
			||||
                $this->questionJSId, | 
				
			||||
                $this->questionJSId + 1, | 
				
			||||
                '', | 
				
			||||
                $attributes, | 
				
			||||
                $answer, | 
				
			||||
                $listAnswerInfo, | 
				
			||||
                true, | 
				
			||||
                $i, | 
				
			||||
                'question_'.$this->questionJSId.'_fib_'.($i + 1) | 
				
			||||
            ); | 
				
			||||
            $answerList[] = $i + 1; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        // display the last common word | 
				
			||||
        $answer .= $listAnswerInfo['common_words'][$i]; | 
				
			||||
 | 
				
			||||
        // because [] is parsed here we follow this procedure: | 
				
			||||
        // 1. find everything between the [ and ] tags | 
				
			||||
        $jstmpw = 'questions_answers_ponderation['.$this->questionJSId.'] = new Array();'."\n"; | 
				
			||||
        $jstmpw .= 'questions_answers_ponderation['.$this->questionJSId.'][0] = 0;'."\n"; | 
				
			||||
 | 
				
			||||
        foreach ($listAnswerInfo['weighting'] as $key => $weight) { | 
				
			||||
            $jstmpw .= 'questions_answers_ponderation['.$this->questionJSId.']['.($key + 1).'] = '.$weight.";\n"; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $wordList = "'".implode("', '", $listAnswerInfo['words'])."'"; | 
				
			||||
        $answerList = "'".implode("', '", $answerList)."'"; | 
				
			||||
 | 
				
			||||
        $html = '<tr><td colspan="2"><table width="100%">'; | 
				
			||||
        $html .= '<tr> | 
				
			||||
            <td> | 
				
			||||
            '.$answer.' | 
				
			||||
            </td> | 
				
			||||
            </tr></table></td></tr>'; | 
				
			||||
        $js .= 'questions_answers['.$this->questionJSId.'] = new Array('.$answerList.');'."\n"; | 
				
			||||
        $js .= 'questions_answers_correct['.$this->questionJSId.'] = new Array('.$wordList.');'."\n"; | 
				
			||||
        $js .= 'questions_types['.$this->questionJSId.'] = \'fib\';'."\n"; | 
				
			||||
        $js .= $jstmpw; | 
				
			||||
 | 
				
			||||
        return [$js, $html]; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,100 @@ | 
				
			||||
<?php | 
				
			||||
/* For licensing terms, see /license.txt */ | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * This class handles the SCORM export of matching questions. | 
				
			||||
 * | 
				
			||||
 * @package chamilo.exercise.scorm | 
				
			||||
 */ | 
				
			||||
class ScormAnswerMatching extends Answer | 
				
			||||
{ | 
				
			||||
    /** | 
				
			||||
     * Export the question part as a matrix-choice, with only one possible answer per line. | 
				
			||||
     * | 
				
			||||
     * @author Amand Tihon <amand@alrj.org> | 
				
			||||
     */ | 
				
			||||
    public function export() | 
				
			||||
    { | 
				
			||||
        $js = ''; | 
				
			||||
        // prepare list of right proposition to allow | 
				
			||||
        // - easiest display | 
				
			||||
        // - easiest randomisation if needed one day | 
				
			||||
        // (here I use array_values to change array keys from $code1 $code2 ... to 0 1 ...) | 
				
			||||
        // get max length of displayed array | 
				
			||||
        $nbrAnswers = $this->selectNbrAnswers(); | 
				
			||||
        $counter = 1; | 
				
			||||
        $questionId = $this->questionJSId; | 
				
			||||
        $jstmpw = 'questions_answers_ponderation['.$questionId.'] = new Array();'."\n"; | 
				
			||||
        $jstmpw .= 'questions_answers_ponderation['.$questionId.'][0] = 0;'."\n"; | 
				
			||||
 | 
				
			||||
        // Options (A, B, C, ...) that will be put into the list-box | 
				
			||||
        $options = []; | 
				
			||||
        $letter = 'A'; | 
				
			||||
        for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) { | 
				
			||||
            $answerCorrect = $this->isCorrect($answerId); | 
				
			||||
            $answer = $this->selectAnswer($answerId); | 
				
			||||
            $realAnswerId = $this->selectAutoId($answerId); | 
				
			||||
            if (!$answerCorrect) { | 
				
			||||
                $options[$realAnswerId]['Lettre'] = $letter; | 
				
			||||
                // answers that will be shown at the right side | 
				
			||||
                $options[$realAnswerId]['Reponse'] = $answer; | 
				
			||||
                $letter++; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $html = []; | 
				
			||||
        $jstmp = ''; | 
				
			||||
        $jstmpc = ''; | 
				
			||||
 | 
				
			||||
        // Answers | 
				
			||||
        for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) { | 
				
			||||
            $identifier = 'question_'.$questionId.'_matching_'; | 
				
			||||
            $answer = $this->selectAnswer($answerId); | 
				
			||||
            $answerCorrect = $this->isCorrect($answerId); | 
				
			||||
            $weight = $this->selectWeighting($answerId); | 
				
			||||
            $jstmp .= $answerId.','; | 
				
			||||
 | 
				
			||||
            if ($answerCorrect) { | 
				
			||||
                $html[] = '<tr class="option_row">'; | 
				
			||||
                //$html[] = '<td width="40%" valign="top"><b>'.$counter.'</b>. '.$answer."</td>"; | 
				
			||||
                $html[] = '<td width="40%" valign="top"> '.$answer."</td>"; | 
				
			||||
                $html[] = '<td width="20%" align="center">  '; | 
				
			||||
                $html[] = '<select name="'.$identifier.$counter.'" id="'.$identifier.$counter.'">'; | 
				
			||||
                $html[] = ' <option value="0">--</option>'; | 
				
			||||
                // fills the list-box | 
				
			||||
                foreach ($options as $key => $val) { | 
				
			||||
                    $html[] = '<option value="'.$key.'">'.$val['Lettre'].'</option>'; | 
				
			||||
                } | 
				
			||||
 | 
				
			||||
                $html[] = '</select>  </td>'; | 
				
			||||
                $html[] = '<td width="40%" valign="top">'; | 
				
			||||
                foreach ($options as $key => $val) { | 
				
			||||
                    $html[] = '<b>'.$val['Lettre'].'.</b> '.$val['Reponse'].'<br />'; | 
				
			||||
                } | 
				
			||||
                $html[] = '</td></tr>'; | 
				
			||||
 | 
				
			||||
                $jstmpc .= '['.$answerCorrect.','.$counter.'],'; | 
				
			||||
 | 
				
			||||
                $myWeight = explode('@', $weight); | 
				
			||||
                if (count($myWeight) == 2) { | 
				
			||||
                    $weight = $myWeight[0]; | 
				
			||||
                } else { | 
				
			||||
                    $weight = $myWeight[0]; | 
				
			||||
                } | 
				
			||||
                $jstmpw .= 'questions_answers_ponderation['.$questionId.']['.$counter.'] = '.$weight.";\n"; | 
				
			||||
                $counter++; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $js .= 'questions_answers['.$questionId.'] = new Array('.substr($jstmp, 0, -1).');'."\n"; | 
				
			||||
        $js .= 'questions_answers_correct['.$questionId.'] = new Array('.substr($jstmpc, 0, -1).');'."\n"; | 
				
			||||
        $js .= 'questions_types['.$questionId.'] = \'matching\';'."\n"; | 
				
			||||
        $js .= $jstmpw; | 
				
			||||
 | 
				
			||||
        $htmlResult = '<tr><td colspan="2"><table id="question_'.$questionId.'" width="100%">'; | 
				
			||||
        $htmlResult .= implode("\n", $html); | 
				
			||||
        $htmlResult .= '</table></td></tr>'."\n"; | 
				
			||||
 | 
				
			||||
        return [$js, $htmlResult]; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,119 @@ | 
				
			||||
<?php | 
				
			||||
/* For licensing terms, see /license.txt */ | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * This class handles the export to SCORM of a multiple choice question | 
				
			||||
 * (be it single answer or multiple answers). | 
				
			||||
 * | 
				
			||||
 * @package chamilo.exercise.scorm | 
				
			||||
 */ | 
				
			||||
class ScormAnswerMultipleChoice extends Answer | 
				
			||||
{ | 
				
			||||
    /** | 
				
			||||
     * Return HTML code for possible answers. | 
				
			||||
     */ | 
				
			||||
    public function export() | 
				
			||||
    { | 
				
			||||
        $js = []; | 
				
			||||
        $type = $this->getQuestionType(); | 
				
			||||
        $questionId = $this->questionJSId; | 
				
			||||
        $jstmpw = 'questions_answers_ponderation['.$questionId.'] = new Array();'; | 
				
			||||
        $jstmpw .= 'questions_answers_ponderation['.$questionId.'][0] = 0;'; | 
				
			||||
        $jstmpw .= 'questions_answers_correct['.$questionId.'] = new Array();'; | 
				
			||||
        $html = []; | 
				
			||||
 | 
				
			||||
        //not sure if we are going to export also the MULTIPLE_ANSWER_COMBINATION to SCORM | 
				
			||||
        //if ($type == MCMA  || $type == MULTIPLE_ANSWER_COMBINATION ) { | 
				
			||||
        if ($type == MCMA) { | 
				
			||||
            $id = 1; | 
				
			||||
            $jstmp = ''; | 
				
			||||
            $jstmpc = ''; | 
				
			||||
            foreach ($this->answer as $i => $answer) { | 
				
			||||
                $identifier = 'question_'.$questionId.'_multiple_'.$i; | 
				
			||||
                $html[] = | 
				
			||||
                    '<tr> | 
				
			||||
                    <td align="center" width="5%"> | 
				
			||||
                    <input name="'.$identifier.'" id="'.$identifier.'" value="'.$i.'" type="checkbox" /> | 
				
			||||
                    </td> | 
				
			||||
                    <td width="95%"> | 
				
			||||
                    <label for="'.$identifier.'">'.Security::remove_XSS($this->answer[$i]).'</label> | 
				
			||||
                    </td> | 
				
			||||
                    </tr>'; | 
				
			||||
 | 
				
			||||
                $jstmp .= $i.','; | 
				
			||||
                if ($this->correct[$i]) { | 
				
			||||
                    $jstmpc .= $i.','; | 
				
			||||
                } | 
				
			||||
                $jstmpw .= 'questions_answers_ponderation['.$questionId.']['.$i.'] = '.$this->weighting[$i].";"; | 
				
			||||
                $jstmpw .= 'questions_answers_correct['.$questionId.']['.$i.'] = '.$this->correct[$i].';'; | 
				
			||||
                $id++; | 
				
			||||
            } | 
				
			||||
            $js[] = 'questions_answers['.$questionId.'] = new Array('.substr($jstmp, 0, -1).');'."\n"; | 
				
			||||
            $js[] = 'questions_types['.$questionId.'] = \'mcma\';'."\n"; | 
				
			||||
            $js[] = $jstmpw; | 
				
			||||
        } elseif ($type == MULTIPLE_ANSWER_COMBINATION) { | 
				
			||||
            $js = ''; | 
				
			||||
            $id = 1; | 
				
			||||
            $jstmp = ''; | 
				
			||||
            $jstmpc = ''; | 
				
			||||
            foreach ($this->answer as $i => $answer) { | 
				
			||||
                $identifier = 'question_'.$questionId.'_exact_'.$i; | 
				
			||||
                $html[] = | 
				
			||||
                    '<tr> | 
				
			||||
                    <td align="center" width="5%"> | 
				
			||||
                    <input name="'.$identifier.'" id="'.$identifier.'" value="'.$i.'" type="checkbox" /> | 
				
			||||
                    </td> | 
				
			||||
                    <td width="95%"> | 
				
			||||
                    <label for="'.$identifier.'">'.Security::remove_XSS($this->answer[$i]).'</label> | 
				
			||||
                    </td> | 
				
			||||
                    </tr>'; | 
				
			||||
 | 
				
			||||
                $jstmp .= $i.','; | 
				
			||||
                if ($this->correct[$i]) { | 
				
			||||
                    $jstmpc .= $i.','; | 
				
			||||
                } | 
				
			||||
                $jstmpw .= 'questions_answers_ponderation['.$questionId.']['.$i.'] = '.$this->weighting[$i].';'; | 
				
			||||
                $jstmpw .= 'questions_answers_correct['.$questionId.']['.$i.'] = '.$this->correct[$i].';'; | 
				
			||||
                $id++; | 
				
			||||
            } | 
				
			||||
            $js[] = 'questions_answers['.$questionId.'] = new Array('.substr($jstmp, 0, -1).');'; | 
				
			||||
            $js[] = 'questions_types['.$questionId.'] = "exact";'; | 
				
			||||
            $js[] = $jstmpw; | 
				
			||||
        } else { | 
				
			||||
            $id = 1; | 
				
			||||
            $jstmp = ''; | 
				
			||||
            $jstmpc = ''; | 
				
			||||
            foreach ($this->answer as $i => $answer) { | 
				
			||||
                $identifier = 'question_'.$questionId.'_unique_'.$i; | 
				
			||||
                $identifier_name = 'question_'.$questionId.'_unique_answer'; | 
				
			||||
                $html[] = | 
				
			||||
                    '<tr> | 
				
			||||
                    <td align="center" width="5%"> | 
				
			||||
                    <input name="'.$identifier_name.'" id="'.$identifier.'" value="'.$i.'" type="checkbox"/> | 
				
			||||
                    </td> | 
				
			||||
                    <td width="95%"> | 
				
			||||
                    <label for="'.$identifier.'">'.Security::remove_XSS($this->answer[$i]).'</label> | 
				
			||||
                    </td> | 
				
			||||
                    </tr>'; | 
				
			||||
                $jstmp .= $i.','; | 
				
			||||
                if ($this->correct[$i]) { | 
				
			||||
                    $jstmpc .= $i; | 
				
			||||
                } | 
				
			||||
                $jstmpw .= 'questions_answers_ponderation['.$questionId.']['.$i.'] = '.$this->weighting[$i].';'; | 
				
			||||
                $jstmpw .= 'questions_answers_correct['.$questionId.']['.$i.'] = '.$this->correct[$i].';'; | 
				
			||||
                $id++; | 
				
			||||
            } | 
				
			||||
            $js[] = 'questions_answers['.$questionId.'] = new Array('.substr($jstmp, 0, -1).');'; | 
				
			||||
            $js[] = 'questions_types['.$questionId.'] = \'mcua\';'; | 
				
			||||
            $js[] = $jstmpw; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $htmlResult = '<tr><td colspan="2"><table id="question_'.$questionId.'" width="100%">'; | 
				
			||||
        $htmlResult .= implode("\n", $html); | 
				
			||||
        $htmlResult .= '</table></td></tr>'; | 
				
			||||
 | 
				
			||||
        $js = implode("\n", $js); | 
				
			||||
 | 
				
			||||
        return [$js, $htmlResult]; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,56 @@ | 
				
			||||
<?php | 
				
			||||
/* For licensing terms, see /license.txt */ | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * This class handles the SCORM export of true/false questions. | 
				
			||||
 * | 
				
			||||
 * @package chamilo.exercise.scorm | 
				
			||||
 */ | 
				
			||||
class ScormAnswerTrueFalse extends Answer | 
				
			||||
{ | 
				
			||||
    /** | 
				
			||||
     * Return the XML flow for the possible answers. | 
				
			||||
     * That's one <response_lid>, containing several <flow_label>. | 
				
			||||
     * | 
				
			||||
     * @author Amand Tihon <amand@alrj.org> | 
				
			||||
     */ | 
				
			||||
    public function export() | 
				
			||||
    { | 
				
			||||
        $js = ''; | 
				
			||||
        $html = '<tr><td colspan="2"><table width="100%">'; | 
				
			||||
        $identifier = 'question_'.$this->questionJSId.'_tf'; | 
				
			||||
        $identifier_true = $identifier.'_true'; | 
				
			||||
        $identifier_false = $identifier.'_false'; | 
				
			||||
        $html .= | 
				
			||||
            '<tr> | 
				
			||||
                <td align="center" width="5%"> | 
				
			||||
                <input name="'.$identifier_true.'" id="'.$identifier_true.'" value="'.$this->trueGrade.'" type="radio" /> | 
				
			||||
                </td> | 
				
			||||
                <td width="95%"> | 
				
			||||
                <label for="'.$identifier_true.'">'.get_lang('True').'</label> | 
				
			||||
                </td> | 
				
			||||
                </tr>'; | 
				
			||||
        $html .= | 
				
			||||
            '<tr> | 
				
			||||
            <td align="center" width="5%"> | 
				
			||||
            <input name="'.$identifier_false.'" id="'.$identifier_false.'" value="'.$this->falseGrade.'" type="radio" /> | 
				
			||||
            </td> | 
				
			||||
            <td width="95%"> | 
				
			||||
            <label for="'.$identifier_false.'">'.get_lang('False').'</label> | 
				
			||||
            </td> | 
				
			||||
            </tr></table></td></tr>'; | 
				
			||||
        $js .= 'questions_answers['.$this->questionJSId.'] = new Array(\'true\',\'false\');'."\n"; | 
				
			||||
        $js .= 'questions_types['.$this->questionJSId.'] = \'tf\';'."\n"; | 
				
			||||
        if ($this->response === 'TRUE') { | 
				
			||||
            $js .= 'questions_answers_correct['.$this->questionJSId.'] = new Array(\'true\');'."\n"; | 
				
			||||
        } else { | 
				
			||||
            $js .= 'questions_answers_correct['.$this->questionJSId.'] = new Array(\'false\');'."\n"; | 
				
			||||
        } | 
				
			||||
        $jstmpw = 'questions_answers_ponderation['.$this->questionJSId.'] = new Array();'."\n"; | 
				
			||||
        $jstmpw .= 'questions_answers_ponderation['.$this->questionJSId.'][0] = 0;'."\n"; | 
				
			||||
        $jstmpw .= 'questions_answers_ponderation['.$this->questionJSId.'][1] = '.$this->weighting[1].";\n"; | 
				
			||||
        $js .= $jstmpw; | 
				
			||||
 | 
				
			||||
        return [$js, $html]; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,184 @@ | 
				
			||||
<?php | 
				
			||||
/* For licensing terms, see /license.txt */ | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * A SCORM item. It corresponds to a single question. | 
				
			||||
 * This class allows export from Chamilo SCORM 1.2 format of a single question. | 
				
			||||
 * It is not usable as-is, but must be subclassed, to support different kinds of questions. | 
				
			||||
 * | 
				
			||||
 * Every start_*() and corresponding end_*(), as well as export_*() methods return a string. | 
				
			||||
 * | 
				
			||||
 * Attached files are NOT exported. | 
				
			||||
 * | 
				
			||||
 * @package chamilo.exercise.scorm | 
				
			||||
 */ | 
				
			||||
class ScormAssessmentItem | 
				
			||||
{ | 
				
			||||
    public $question; | 
				
			||||
    public $question_ident; | 
				
			||||
    public $answer; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Constructor. | 
				
			||||
     * | 
				
			||||
     * @param ScormQuestion $question the Question object we want to export | 
				
			||||
     */ | 
				
			||||
    public function __construct($question) | 
				
			||||
    { | 
				
			||||
        $this->question = $question; | 
				
			||||
        $this->question->setAnswer(); | 
				
			||||
        $this->questionIdent = 'QST_'.$question->id; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Start the XML flow. | 
				
			||||
     * | 
				
			||||
     * This opens the <item> block, with correct attributes. | 
				
			||||
     */ | 
				
			||||
    public function start_page() | 
				
			||||
    { | 
				
			||||
        $head = ''; | 
				
			||||
        /*if ($this->standalone) { | 
				
			||||
            $charset = 'UTF-8'; | 
				
			||||
            $head = '<?xml version="1.0" encoding="'.$charset.'" standalone="no"?>';
 | 
				
			||||
            $head .= '<html>'; | 
				
			||||
        }*/ | 
				
			||||
 | 
				
			||||
        return $head; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * End the XML flow, closing the </item> tag. | 
				
			||||
     */ | 
				
			||||
    public function end_page() | 
				
			||||
    { | 
				
			||||
        /*if ($this->standalone) { | 
				
			||||
            return '</html>'; | 
				
			||||
        }*/ | 
				
			||||
 | 
				
			||||
        return ''; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Start document header. | 
				
			||||
     */ | 
				
			||||
    public function start_header() | 
				
			||||
    { | 
				
			||||
        /*if ($this->standalone) { | 
				
			||||
            return '<head>'; | 
				
			||||
        }*/ | 
				
			||||
 | 
				
			||||
        return ''; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Print CSS inclusion. | 
				
			||||
     */ | 
				
			||||
    public function css() | 
				
			||||
    { | 
				
			||||
        $css = ''; | 
				
			||||
//        if ($this->standalone) { | 
				
			||||
//            $css = '<style type="text/css" media="screen, projection">'; | 
				
			||||
//            $css .= '/*<![CDATA[*/'."\n"; | 
				
			||||
//            $css .= '/*]]>*/'."\n"; | 
				
			||||
//            $css .= '</style>'."\n"; | 
				
			||||
//            $css .= '<style type="text/css" media="print">'; | 
				
			||||
//            $css .= '/*<![CDATA[*/'."\n"; | 
				
			||||
//            $css .= '/*]]>*/'."\n"; | 
				
			||||
//            $css .= '</style>'; | 
				
			||||
//        } | 
				
			||||
 | 
				
			||||
        return $css; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * End document header. | 
				
			||||
     */ | 
				
			||||
    public function end_header() | 
				
			||||
    { | 
				
			||||
//        if ($this->standalone) { | 
				
			||||
//            return '</head>'; | 
				
			||||
//        } | 
				
			||||
 | 
				
			||||
        return ''; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Start the itemBody. | 
				
			||||
     */ | 
				
			||||
    public function start_js() | 
				
			||||
    { | 
				
			||||
        $js = '<script type="text/javascript" src="assets/api_wrapper.js"></script>'; | 
				
			||||
//        if ($this->standalone) { | 
				
			||||
//            return '<script>'; | 
				
			||||
//        } | 
				
			||||
 | 
				
			||||
        return $js; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * End the itemBody part. | 
				
			||||
     */ | 
				
			||||
    public function end_js() | 
				
			||||
    { | 
				
			||||
        /*if ($this->standalone) { | 
				
			||||
            return '</script>'; | 
				
			||||
        }*/ | 
				
			||||
 | 
				
			||||
        return ''; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Start the itemBody. | 
				
			||||
     */ | 
				
			||||
    public function start_body() | 
				
			||||
    { | 
				
			||||
        /*if ($this->standalone) { | 
				
			||||
            return '<body><form id="dokeos_scorm_form" method="post" action="">'; | 
				
			||||
        }*/ | 
				
			||||
 | 
				
			||||
        return ''; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * End the itemBody part. | 
				
			||||
     */ | 
				
			||||
    public function end_body() | 
				
			||||
    { | 
				
			||||
        /*if ($this->standalone) { | 
				
			||||
            return '<br /><input class="btn" type="button" id="dokeos_scorm_submit" name="dokeos_scorm_submit" value="OK" /></form></body>'; | 
				
			||||
        }*/ | 
				
			||||
 | 
				
			||||
        return ''; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Export the question as a SCORM Item. | 
				
			||||
     * This is a default behaviour, some classes may want to override this. | 
				
			||||
     * | 
				
			||||
     * @return string|array a string, the XML flow for an Item | 
				
			||||
     */ | 
				
			||||
    public function export() | 
				
			||||
    { | 
				
			||||
        list($js, $html) = $this->question->export(); | 
				
			||||
        /*if ($this->standalone) { | 
				
			||||
            $res = $this->start_page() | 
				
			||||
                .$this->start_header() | 
				
			||||
                .$this->css() | 
				
			||||
                .$this->start_js() | 
				
			||||
                .$this->common_js() | 
				
			||||
                .$js | 
				
			||||
                .$this->end_js() | 
				
			||||
                .$this->end_header() | 
				
			||||
                .$this->start_body() | 
				
			||||
                .$html | 
				
			||||
                .$this->end_body() | 
				
			||||
                .$this->end_page(); | 
				
			||||
 | 
				
			||||
            return $res; | 
				
			||||
        } else { | 
				
			||||
            return [$js, $html]; | 
				
			||||
        }*/ | 
				
			||||
        return [$js, $html]; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,221 @@ | 
				
			||||
<?php | 
				
			||||
/* For licensing terms, see /license.txt */ | 
				
			||||
 | 
				
			||||
use Chamilo\CourseBundle\Entity\CQuiz; | 
				
			||||
use Symfony\Component\Serializer\Encoder\JsonEncoder; | 
				
			||||
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; | 
				
			||||
use Symfony\Component\Serializer\Serializer; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * This class represents an entire exercise to be exported in SCORM. | 
				
			||||
 * It will be represented by a single <section> containing several <item>. | 
				
			||||
 * | 
				
			||||
 * Some properties cannot be exported, as SCORM does not support them : | 
				
			||||
 *   - type (one page or multiple pages) | 
				
			||||
 *   - start_date and end_date | 
				
			||||
 *   - max_attempts | 
				
			||||
 *   - show_answer | 
				
			||||
 *   - anonymous_attempts | 
				
			||||
 * | 
				
			||||
 * @author Julio Montoya | 
				
			||||
 * @author Amand Tihon <amand@alrj.org> | 
				
			||||
 * | 
				
			||||
 * @package chamilo.exercise.scorm | 
				
			||||
 */ | 
				
			||||
class ScormExercise | 
				
			||||
{ | 
				
			||||
    public $exercise; | 
				
			||||
    public $standalone; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * ScormExercise constructor. | 
				
			||||
     * | 
				
			||||
     * @param Exercise $exe | 
				
			||||
     * @param bool     $standalone | 
				
			||||
     */ | 
				
			||||
    public function __construct($exe, $standalone) | 
				
			||||
    { | 
				
			||||
        $this->exercise = $exe; | 
				
			||||
        $this->standalone = $standalone; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Start the XML flow. | 
				
			||||
     * | 
				
			||||
     * This opens the <item> block, with correct attributes. | 
				
			||||
     */ | 
				
			||||
    public function startPage() | 
				
			||||
    { | 
				
			||||
        $charset = 'UTF-8'; | 
				
			||||
        $head = '<?xml version="1.0" encoding="'.$charset.'" standalone="no"?><html>';
 | 
				
			||||
 | 
				
			||||
        return $head; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * End the XML flow, closing the </item> tag. | 
				
			||||
     */ | 
				
			||||
    public function end_page() | 
				
			||||
    { | 
				
			||||
        return '</html>'; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Start document header. | 
				
			||||
     */ | 
				
			||||
    public function start_header() | 
				
			||||
    { | 
				
			||||
        return '<head>'; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Common JS functions. | 
				
			||||
     */ | 
				
			||||
    public function common_js() | 
				
			||||
    { | 
				
			||||
        $js = file_get_contents(api_get_path(SYS_CODE_PATH).'exercise/export/scorm/common.js'); | 
				
			||||
 | 
				
			||||
        return $js."\n"; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * End the itemBody part. | 
				
			||||
     */ | 
				
			||||
    public function end_js() | 
				
			||||
    { | 
				
			||||
        return '</script>'; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Start the itemBody. | 
				
			||||
     */ | 
				
			||||
    public function start_body() | 
				
			||||
    { | 
				
			||||
        return '<body>'. | 
				
			||||
            '<h1>'.$this->exercise->selectTitle().'</h1><p>'.$this->exercise->selectDescription()."</p>". | 
				
			||||
            '<form id="chamilo_scorm_form" method="post" action="">'. | 
				
			||||
            '<table width="100%">'; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * End the itemBody part. | 
				
			||||
     */ | 
				
			||||
    public function end_body() | 
				
			||||
    { | 
				
			||||
        $button = '<input  | 
				
			||||
            id="chamilo_scorm_submit"  | 
				
			||||
            class="btn btn-primary"  | 
				
			||||
            type="button"  | 
				
			||||
            name="chamilo_scorm_submit"  | 
				
			||||
            value="OK" />'; | 
				
			||||
 | 
				
			||||
        return '</table><br />'.$button.'</form></body>'; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Export the question as a SCORM Item. | 
				
			||||
     * | 
				
			||||
     * This is a default behaviour, some classes may want to override this. | 
				
			||||
     * | 
				
			||||
     * @param $standalone: Boolean stating if it should be exported as a stand-alone question | 
				
			||||
     * | 
				
			||||
     * @return string string, the XML flow for an Item | 
				
			||||
     */ | 
				
			||||
    public function export() | 
				
			||||
    { | 
				
			||||
        global $charset; | 
				
			||||
 | 
				
			||||
        /*$head = ''; | 
				
			||||
        if ($this->standalone) { | 
				
			||||
            $head = '<?xml version = "1.0" encoding = "'.$charset.'" standalone = "no"?>'."\n"
 | 
				
			||||
                .'<!DOCTYPE questestinterop SYSTEM "ims_qtiasiv2p1.dtd">'."\n"; | 
				
			||||
        }*/ | 
				
			||||
 | 
				
			||||
        list($js, $html) = $this->exportQuestions(); | 
				
			||||
        $res = $this->startPage() | 
				
			||||
            .$this->start_header() | 
				
			||||
            .$this->css() | 
				
			||||
            .$this->globalAssets() | 
				
			||||
            .$this->start_js() | 
				
			||||
            .$this->common_js() | 
				
			||||
            .$js | 
				
			||||
            .$this->end_js() | 
				
			||||
            .$this->end_header() | 
				
			||||
            .$this->start_body() | 
				
			||||
            .$html | 
				
			||||
            .$this->end_body() | 
				
			||||
            .$this->end_page(); | 
				
			||||
 | 
				
			||||
        return $res; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Export the questions, as a succession of <items>. | 
				
			||||
     * | 
				
			||||
     * @author Amand Tihon <amand@alrj.org> | 
				
			||||
     */ | 
				
			||||
    public function exportQuestions() | 
				
			||||
    { | 
				
			||||
        $js = $html = ''; | 
				
			||||
        $encoders = [new JsonEncoder()]; | 
				
			||||
        $normalizers = [new ObjectNormalizer()]; | 
				
			||||
 | 
				
			||||
        $em = Database::getManager(); | 
				
			||||
        // Export cquiz data | 
				
			||||
        /** @var CQuiz $exercise */ | 
				
			||||
        $exercise = $em->find('ChamiloCourseBundle:CQuiz', $this->exercise->iId); | 
				
			||||
        $exercise->setDescription(''); | 
				
			||||
        $exercise->setTextWhenFinished(''); | 
				
			||||
 | 
				
			||||
        $serializer = new Serializer($normalizers, $encoders); | 
				
			||||
        $jsonContent = $serializer->serialize($exercise, 'json'); | 
				
			||||
        $js .= "var exerciseInfo = JSON.parse('".$jsonContent."');\n"; | 
				
			||||
 | 
				
			||||
        $counter = 0; | 
				
			||||
        $scormQuestion = new ScormQuestion(); | 
				
			||||
        foreach ($this->exercise->selectQuestionList() as $q) { | 
				
			||||
            list($jstmp, $htmltmp) = $scormQuestion->exportQuestionToScorm($q, $counter); | 
				
			||||
            $js .= $jstmp."\n"; | 
				
			||||
            $html .= $htmltmp."\n"; | 
				
			||||
            $counter++; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        return [$js, $html]; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Print CSS inclusion. | 
				
			||||
     */ | 
				
			||||
    private function css() | 
				
			||||
    { | 
				
			||||
        return ''; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * End document header. | 
				
			||||
     */ | 
				
			||||
    private function end_header() | 
				
			||||
    { | 
				
			||||
        return '</head>'; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Start the itemBody. | 
				
			||||
     */ | 
				
			||||
    private function start_js() | 
				
			||||
    { | 
				
			||||
        return '<script>'; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * @return string | 
				
			||||
     */ | 
				
			||||
    private function globalAssets() | 
				
			||||
    { | 
				
			||||
        $assets = '<script type="text/javascript" src="assets/jquery/jquery.min.js"></script>'."\n"; | 
				
			||||
        $assets .= '<script type="text/javascript" src="assets/api_wrapper.js"></script>'."\n"; | 
				
			||||
        $assets .= '<link href="assets/bootstrap/bootstrap.min.css" rel="stylesheet" media="screen" type="text/css" />'; | 
				
			||||
 | 
				
			||||
        return $assets; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,223 @@ | 
				
			||||
<?php | 
				
			||||
/* For licensing terms, see /license.txt */ | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * The ScormQuestion class is a gateway to getting the answers exported | 
				
			||||
 * (the question is just an HTML text, while the answers are the most important). | 
				
			||||
 * It is important to note that the SCORM export process is done in two parts. | 
				
			||||
 * First, the HTML part (which is the presentation), and second the JavaScript | 
				
			||||
 * part (the process). | 
				
			||||
 * The two bits are separate to allow for a one-big-javascript and a one-big-html | 
				
			||||
 * files to be built. Each export function thus returns an array of HTML+JS. | 
				
			||||
 * | 
				
			||||
 * | 
				
			||||
 * @author Claro Team <cvs@claroline.net> | 
				
			||||
 * @author Yannick Warnier <yannick.warnier@beeznest.com> | 
				
			||||
 * | 
				
			||||
 * @package chamilo.exercise.scorm | 
				
			||||
 */ | 
				
			||||
class ScormQuestion extends Question | 
				
			||||
{ | 
				
			||||
    public $js_id; | 
				
			||||
    public $answer; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * ScormQuestion constructor. | 
				
			||||
     */ | 
				
			||||
    public function __construct() | 
				
			||||
    { | 
				
			||||
        parent::__construct(); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Returns the HTML + JS flow corresponding to one question. | 
				
			||||
     * | 
				
			||||
     * @param int  $questionId The question ID | 
				
			||||
     * @param bool $standalone (ie including XML tag, DTD declaration, etc) | 
				
			||||
     * @param int  $jsId       The JavaScript ID for this question. | 
				
			||||
     *                         Due to the nature of interactions, we must have a natural sequence for | 
				
			||||
     *                         questions in the generated JavaScript. | 
				
			||||
     * | 
				
			||||
     * @return string|array | 
				
			||||
     */ | 
				
			||||
    public function exportQuestionToScorm( | 
				
			||||
        $questionId, | 
				
			||||
        $jsId | 
				
			||||
    ) { | 
				
			||||
        $question = self::read($questionId); | 
				
			||||
        if (!$question) { | 
				
			||||
            return ''; | 
				
			||||
        } | 
				
			||||
        $this->id = $question->id; | 
				
			||||
        $this->js_id = $jsId; | 
				
			||||
        $this->type = $question->type; | 
				
			||||
        $this->question = $question->question; | 
				
			||||
        $this->description = $question->description; | 
				
			||||
        $this->weighting = $question->weighting; | 
				
			||||
        $this->position = $question->position; | 
				
			||||
        $this->picture = $question->picture; | 
				
			||||
        $assessmentItem = new ScormAssessmentItem($this); | 
				
			||||
 | 
				
			||||
        return $assessmentItem->export(); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Include the correct answer class and create answer. | 
				
			||||
     */ | 
				
			||||
    public function setAnswer() | 
				
			||||
    { | 
				
			||||
        switch ($this->type) { | 
				
			||||
            case MCUA: | 
				
			||||
                $this->answer = new ScormAnswerMultipleChoice($this->id); | 
				
			||||
                $this->answer->questionJSId = $this->js_id; | 
				
			||||
                break; | 
				
			||||
            case MCMA: | 
				
			||||
            case GLOBAL_MULTIPLE_ANSWER: | 
				
			||||
                $this->answer = new ScormAnswerMultipleChoice($this->id); | 
				
			||||
                $this->answer->questionJSId = $this->js_id; | 
				
			||||
                break; | 
				
			||||
            case TF: | 
				
			||||
                $this->answer = new ScormAnswerTrueFalse($this->id); | 
				
			||||
                $this->answer->questionJSId = $this->js_id; | 
				
			||||
                break; | 
				
			||||
            case FIB: | 
				
			||||
                $this->answer = new ScormAnswerFillInBlanks($this->id); | 
				
			||||
                $this->answer->questionJSId = $this->js_id; | 
				
			||||
                break; | 
				
			||||
            case MATCHING: | 
				
			||||
            case MATCHING_DRAGGABLE: | 
				
			||||
            case DRAGGABLE: | 
				
			||||
                $this->answer = new ScormAnswerMatching($this->id); | 
				
			||||
                $this->answer->questionJSId = $this->js_id; | 
				
			||||
                break; | 
				
			||||
            case ORAL_EXPRESSION: | 
				
			||||
            case FREE_ANSWER: | 
				
			||||
                $this->answer = new ScormAnswerFree($this->id); | 
				
			||||
                $this->answer->questionJSId = $this->js_id; | 
				
			||||
                break; | 
				
			||||
            case HOT_SPOT: | 
				
			||||
                $this->answer = new ScormAnswerHotspot($this->id); | 
				
			||||
                $this->answer->questionJSId = $this->js_id; | 
				
			||||
                break; | 
				
			||||
            case MULTIPLE_ANSWER_COMBINATION: | 
				
			||||
                $this->answer = new ScormAnswerMultipleChoice($this->id); | 
				
			||||
                $this->answer->questionJSId = $this->js_id; | 
				
			||||
                break; | 
				
			||||
            case HOT_SPOT_ORDER: | 
				
			||||
                $this->answer = new ScormAnswerHotspot($this->id); | 
				
			||||
                $this->answer->questionJSId = $this->js_id; | 
				
			||||
                break; | 
				
			||||
            case HOT_SPOT_DELINEATION: | 
				
			||||
                $this->answer = new ScormAnswerHotspot($this->id); | 
				
			||||
                $this->answer->questionJSId = $this->js_id; | 
				
			||||
                break; | 
				
			||||
            // not supported | 
				
			||||
            case UNIQUE_ANSWER_NO_OPTION: | 
				
			||||
            case MULTIPLE_ANSWER_TRUE_FALSE: | 
				
			||||
            case MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE: | 
				
			||||
            case UNIQUE_ANSWER_IMAGE: | 
				
			||||
            case CALCULATED_ANSWER: | 
				
			||||
                $this->answer = new ScormAnswerMultipleChoice($this->id); | 
				
			||||
                $this->answer->questionJSId = $this->js_id; | 
				
			||||
                break; | 
				
			||||
            default: | 
				
			||||
                $this->answer = new stdClass(); | 
				
			||||
                $this->answer->questionJSId = $this->js_id; | 
				
			||||
                break; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        return true; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * @throws Exception | 
				
			||||
     * | 
				
			||||
     * @return array | 
				
			||||
     */ | 
				
			||||
    public function export() | 
				
			||||
    { | 
				
			||||
        $html = $this->getQuestionHTML(); | 
				
			||||
        $js = $this->getQuestionJS(); | 
				
			||||
 | 
				
			||||
        if (is_object($this->answer) && $this->answer instanceof Answer) { | 
				
			||||
            list($js2, $html2) = $this->answer->export(); | 
				
			||||
            $js .= $js2; | 
				
			||||
            $html .= $html2; | 
				
			||||
        } else { | 
				
			||||
            throw new \Exception('Question not supported. Exercise: '.$this->selectTitle()); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        return [$js, $html]; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * {@inheritdoc} | 
				
			||||
     */ | 
				
			||||
    public function createAnswersForm($form) | 
				
			||||
    { | 
				
			||||
        return true; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * {@inheritdoc} | 
				
			||||
     */ | 
				
			||||
    public function processAnswersCreation($form, $exercise) | 
				
			||||
    { | 
				
			||||
        return true; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Returns an HTML-formatted question. | 
				
			||||
     */ | 
				
			||||
    public function getQuestionHTML() | 
				
			||||
    { | 
				
			||||
        $title = $this->selectTitle(); | 
				
			||||
        $description = $this->selectDescription(); | 
				
			||||
        $cols = 2; | 
				
			||||
        $s = '<tr> | 
				
			||||
            <td colspan="'.$cols.'" id="question_'.$this->id.'_title" valign="middle" style="background-color:#d6d6d6;"> | 
				
			||||
            '.$title.' | 
				
			||||
            </td> | 
				
			||||
            </tr> | 
				
			||||
            <tr> | 
				
			||||
            <td valign="top" colspan="'.$cols.'"> | 
				
			||||
            <i>'.$description.'</i> | 
				
			||||
            </td> | 
				
			||||
            </tr>'; | 
				
			||||
 | 
				
			||||
        return $s; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Return the JavaScript code bound to the question. | 
				
			||||
     */ | 
				
			||||
    public function getQuestionJS() | 
				
			||||
    { | 
				
			||||
        $weight = $this->selectWeighting(); | 
				
			||||
        $js = ' | 
				
			||||
            questions.push('.$this->js_id.'); | 
				
			||||
            $(document).ready(function() {          | 
				
			||||
                if (exerciseInfo.randomAnswers == true) { | 
				
			||||
                    $("#question_'.$this->js_id.'").shuffleRows();                     | 
				
			||||
                }  | 
				
			||||
            });'; | 
				
			||||
        $js .= "\n"; | 
				
			||||
 | 
				
			||||
        switch ($this->type) { | 
				
			||||
            case ORAL_EXPRESSION: | 
				
			||||
                /*$script = file_get_contents(api_get_path(LIBRARY_PATH) . 'javascript/rtc/RecordRTC.js'); | 
				
			||||
                $script .= file_get_contents(api_get_path(LIBRARY_PATH) . 'wami-recorder/recorder.js'); | 
				
			||||
                $script .= file_get_contents(api_get_path(LIBRARY_PATH) . 'wami-recorder/gui.js'); | 
				
			||||
                $js .= $script;*/ | 
				
			||||
                break; | 
				
			||||
            case HOT_SPOT: | 
				
			||||
                //put the max score to 0 to avoid discounting the points of | 
				
			||||
                //non-exported quiz types in the SCORM | 
				
			||||
                $weight = 0; | 
				
			||||
                break; | 
				
			||||
        } | 
				
			||||
        $js .= 'questions_score_max['.$this->js_id.'] = '.$weight.";"; | 
				
			||||
 | 
				
			||||
        return $js; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,25 @@ | 
				
			||||
var questions = new Array(); | 
				
			||||
var questions_answers = new Array(); | 
				
			||||
var questions_answers_correct = new Array(); | 
				
			||||
var questions_types = new Array(); | 
				
			||||
var questions_score_max = new Array(); | 
				
			||||
var questions_answers_ponderation = new Array(); | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Adds the event listener | 
				
			||||
 */ | 
				
			||||
function addListeners(e) { | 
				
			||||
    loadPage(); | 
				
			||||
    var myButton = document.getElementById('chamilo_scorm_submit'); | 
				
			||||
    addEvent(myButton, 'click', doQuit, false); | 
				
			||||
    addEvent(myButton, 'click', disableButton, false); | 
				
			||||
    addEvent(window, 'unload', unloadPage, false); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Disables the submit button on SCORM result submission **/ | 
				
			||||
function disableButton() { | 
				
			||||
    var mybtn = document.getElementById('chamilo_scorm_submit'); | 
				
			||||
    mybtn.setAttribute('disabled', 'disabled'); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
addEvent(window,'load', addListeners, false); | 
				
			||||
									
										
											File diff suppressed because it is too large
											Load Diff
										
									
								
							
						@ -0,0 +1,27 @@ | 
				
			||||
<?php | 
				
			||||
/* For licensing terms, see /license.txt */ | 
				
			||||
/** | 
				
			||||
 * Responses to AJAX calls. | 
				
			||||
 */ | 
				
			||||
require_once __DIR__.'/../global.inc.php'; | 
				
			||||
 | 
				
			||||
$action = isset($_REQUEST['a']) ? $_REQUEST['a'] : ''; | 
				
			||||
$isAllowedToEdit = api_is_allowed_to_edit(); | 
				
			||||
 | 
				
			||||
switch ($action) { | 
				
			||||
    case 'delete_user_in_usergroup': | 
				
			||||
        if ($isAllowedToEdit) { | 
				
			||||
            $userGroup = new UserGroup(); | 
				
			||||
            $userId = isset($_REQUEST['id']) ? $_REQUEST['id'] : 0; | 
				
			||||
            $userIdList = explode(',', $userId); | 
				
			||||
            $groupId = isset($_REQUEST['group_id']) ? $_REQUEST['group_id'] : 0; | 
				
			||||
            foreach ($userIdList as $userId) { | 
				
			||||
                $userGroup->delete_user_rel_group($userId, $groupId); | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        break; | 
				
			||||
    default: | 
				
			||||
        echo ''; | 
				
			||||
        break; | 
				
			||||
} | 
				
			||||
exit; | 
				
			||||
@ -0,0 +1,37 @@ | 
				
			||||
<?php | 
				
			||||
/* For licensing terms, see /license.txt */ | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Class HookCreateCourse. | 
				
			||||
 */ | 
				
			||||
class HookCreateCourse extends HookEvent implements HookCreateCourseEventInterface | 
				
			||||
{ | 
				
			||||
    /** | 
				
			||||
     * HookCreateCourse constructor. | 
				
			||||
     * | 
				
			||||
     * @throws Exception | 
				
			||||
     */ | 
				
			||||
    protected function __construct() | 
				
			||||
    { | 
				
			||||
        parent::__construct('HookCreateCourse'); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Update all the observers. | 
				
			||||
     * | 
				
			||||
     * @param int $type | 
				
			||||
     * | 
				
			||||
     * @return int | 
				
			||||
     */ | 
				
			||||
    public function notifyCreateCourse($type) | 
				
			||||
    { | 
				
			||||
        $this->eventData['type'] = $type; | 
				
			||||
 | 
				
			||||
        /** @var HookCreateCourseObserverInterface $observer */ | 
				
			||||
        foreach ($this->observers as $observer) { | 
				
			||||
            $observer->hookCreateCourse($this); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        return 1; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,23 @@ | 
				
			||||
<?php | 
				
			||||
/* For licensing terms, see /license.txt */ | 
				
			||||
/** | 
				
			||||
 * This file contains all Hook interfaces and their relation. | 
				
			||||
 * They are used for Hook classes. | 
				
			||||
 * | 
				
			||||
 * @package chamilo.library.hook | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Interface HookCreateUserEventInterface. | 
				
			||||
 */ | 
				
			||||
interface HookCreateCourseEventInterface extends HookEventInterface | 
				
			||||
{ | 
				
			||||
    /** | 
				
			||||
     * Update all the observers. | 
				
			||||
     * | 
				
			||||
     * @param int $type | 
				
			||||
     * | 
				
			||||
     * @return int | 
				
			||||
     */ | 
				
			||||
    public function notifyCreateCourse($type); | 
				
			||||
} | 
				
			||||
@ -0,0 +1,21 @@ | 
				
			||||
<?php | 
				
			||||
/* For licensing terms, see /license.txt */ | 
				
			||||
/** | 
				
			||||
 * This file contains all Hook interfaces and their relation. | 
				
			||||
 * They are used for Hook classes. | 
				
			||||
 * | 
				
			||||
 * @package chamilo.library.hook | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Interface CreateUserHookInterface. | 
				
			||||
 */ | 
				
			||||
interface HookCreateCourseObserverInterface extends HookObserverInterface | 
				
			||||
{ | 
				
			||||
    /** | 
				
			||||
     * @param HookCreateCourseEventInterface $hook | 
				
			||||
     * | 
				
			||||
     * @return int | 
				
			||||
     */ | 
				
			||||
    public function hookCreateCourse(HookCreateCourseEventInterface $hook); | 
				
			||||
} | 
				
			||||
@ -1,553 +0,0 @@ | 
				
			||||
/** | 
				
			||||
 * JavaScript functions to handle standard behaviors of a QuickForm advmultiselect element | 
				
			||||
 * | 
				
			||||
 * @category   HTML | 
				
			||||
 * @package    HTML_QuickForm_advmultiselect | 
				
			||||
 * @author     Laurent Laville <pear@laurent-laville.org> | 
				
			||||
 * @copyright  2007-2009 Laurent Laville | 
				
			||||
 * @license    http://www.opensource.org/licenses/bsd-license.php  New BSD License
 | 
				
			||||
 * @version    CVS: $Id: qfamsHandler.js,v 1.13 2009/02/06 09:49:22 farell Exp $ | 
				
			||||
 * @since      File available since Release 1.3.0 | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
if (typeof QFAMS === "undefined" || !QFAMS) { | 
				
			||||
    /** | 
				
			||||
     * The QFAMS global namespace object.  If QFAMS is already defined, the | 
				
			||||
     * existing QFAMS object will not be overwritten so that defined | 
				
			||||
     * namespaces are preserved. | 
				
			||||
     * @class   QFAMS | 
				
			||||
     * @static | 
				
			||||
     * @public | 
				
			||||
     * @since   1.5.0 | 
				
			||||
     */ | 
				
			||||
    var QFAMS = {}; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * QFAMS.env is used to keep track of end-user preferences | 
				
			||||
 * for persistant values. | 
				
			||||
 * | 
				
			||||
 * @class QFAMS.env | 
				
			||||
 * @static | 
				
			||||
 */ | 
				
			||||
QFAMS.env = QFAMS.env || { | 
				
			||||
    /** | 
				
			||||
     * Keeps the persistant selection preference when items are selected or unselected | 
				
			||||
     * | 
				
			||||
     * @property persistantSelection | 
				
			||||
     * @type     Boolean | 
				
			||||
     */ | 
				
			||||
    persistantSelection: false, | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Keeps the persistant selection preference when items are moved up or down | 
				
			||||
     * | 
				
			||||
     * @property persistantMove | 
				
			||||
     * @type     Boolean | 
				
			||||
     */ | 
				
			||||
    persistantMove: true | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Uses QFAMS.updateCounter as a | 
				
			||||
 * text tools to replace all childs of 'c' element by a new text node of 'v' value | 
				
			||||
 * | 
				
			||||
 * @param      dom element   c    html element; <span> is best use in most case | 
				
			||||
 * @param      string        v    new counter value | 
				
			||||
 * | 
				
			||||
 * @method     updateCounter | 
				
			||||
 * @static | 
				
			||||
 * @return     void | 
				
			||||
 * @public | 
				
			||||
 * @since      1.5.0 | 
				
			||||
 */ | 
				
			||||
QFAMS.updateCounter = function (c, v) { | 
				
			||||
    var i; | 
				
			||||
    var nodeText = null; | 
				
			||||
 | 
				
			||||
    if (c !== null) { | 
				
			||||
        // remove all previous child nodes of 'c' element
 | 
				
			||||
        if (c.childNodes) { | 
				
			||||
            for (i = 0; i < c.childNodes.length; i++) { | 
				
			||||
                c.removeChild(c.childNodes[i]); | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        // add new text value 'v'
 | 
				
			||||
        nodeText = document.createTextNode(v); | 
				
			||||
        c.appendChild(nodeText); | 
				
			||||
    } | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Uses QFAMS.updateLiveCounter as a | 
				
			||||
 * standard onclick event handler to dynamic change value of counter | 
				
			||||
 * that display current selection | 
				
			||||
 * | 
				
			||||
 * @method     updateLiveCounter | 
				
			||||
 * @static | 
				
			||||
 * @return     void | 
				
			||||
 * @private | 
				
			||||
 * @since      1.5.0 | 
				
			||||
 */ | 
				
			||||
QFAMS.updateLiveCounter =  function () { | 
				
			||||
    var lbl           = this.parentNode; | 
				
			||||
    var selectedCount = 0; | 
				
			||||
 | 
				
			||||
    // Find all the checkboxes...
 | 
				
			||||
    var div    = lbl.parentNode; | 
				
			||||
    var inputs = div.getElementsByTagName('input'); | 
				
			||||
    for (var i = 0; i < inputs.length; i++) { | 
				
			||||
        if (inputs[i].checked == 1) { | 
				
			||||
            selectedCount++; | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
    var e         = div.id; | 
				
			||||
    var qfamsName = e.substring(e.indexOf('_', 0) + 1, e.length); | 
				
			||||
    // updates item count
 | 
				
			||||
    var span = document.getElementById(qfamsName + '_selected'); | 
				
			||||
    QFAMS.updateCounter(span, selectedCount + '/' + inputs.length); | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Uses QFAMS.editSelection | 
				
			||||
 * in single select box mode, to edit current selection and update live counter | 
				
			||||
 * | 
				
			||||
 * @param      string        qfamsName      QuickForm advmultiselect element name | 
				
			||||
 * @param      integer       selectMode     Selection mode (0 = uncheck, 1 = check, 2 = toggle) | 
				
			||||
 * | 
				
			||||
 * @method     editSelection | 
				
			||||
 * @static | 
				
			||||
 * @return     void | 
				
			||||
 * @public | 
				
			||||
 * @since      1.5.0 | 
				
			||||
 */ | 
				
			||||
QFAMS.editSelection = function (qfamsName, selectMode) { | 
				
			||||
    if (selectMode !== 0 && selectMode !== 1 && selectMode !== 2) { | 
				
			||||
        return; | 
				
			||||
    } | 
				
			||||
    var selectedCount = 0; | 
				
			||||
 | 
				
			||||
    // Find all the checkboxes...
 | 
				
			||||
    var ams    = document.getElementById('qfams_' + qfamsName); | 
				
			||||
    var inputs = ams.getElementsByTagName('input'); | 
				
			||||
 | 
				
			||||
    // Loop through all checkboxes (input element)
 | 
				
			||||
    for (var i = 0; i < inputs.length; i++) { | 
				
			||||
        if (selectMode === 2) { | 
				
			||||
            if (inputs[i].checked == 0) { | 
				
			||||
                inputs[i].checked = 1; | 
				
			||||
            } else if (inputs[i].checked == 1) { | 
				
			||||
                inputs[i].checked = 0; | 
				
			||||
            } | 
				
			||||
        } else { | 
				
			||||
            inputs[i].checked = selectMode; | 
				
			||||
        } | 
				
			||||
        if (inputs[i].checked == 1) { | 
				
			||||
            selectedCount++; | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    // updates selected item count
 | 
				
			||||
    var span = document.getElementById(qfamsName + '_selected'); | 
				
			||||
    QFAMS.updateCounter(span, selectedCount + '/' + inputs.length); | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Uses QFAMS.moveSelection | 
				
			||||
 * in double select box mode, to move current selection and update live counter | 
				
			||||
 * | 
				
			||||
 * @param      string        qfamsName      QuickForm advmultiselect element name | 
				
			||||
 * @param      dom element   selectLeft     Data source list | 
				
			||||
 * @param      dom element   selectRight    Target data list | 
				
			||||
 * @param      dom element   selectHidden   Full data source (selected, unselected) | 
				
			||||
 *                                          private usage | 
				
			||||
 * @param      string        action         Action name (add, remove, all, none, toggle) | 
				
			||||
 * @param      string        arrange        Sort option (none, asc, desc) | 
				
			||||
 * | 
				
			||||
 * @method     moveSelection | 
				
			||||
 * @static | 
				
			||||
 * @return     void | 
				
			||||
 * @public | 
				
			||||
 * @since      1.5.0 | 
				
			||||
 */ | 
				
			||||
QFAMS.moveSelection = function (qfamsName, selectLeft, selectRight, selectHidden, action, arrange) { | 
				
			||||
    var isIE = /*@cc_on!@*/false; //IE detector
 | 
				
			||||
    var source = null; | 
				
			||||
    var target = null; | 
				
			||||
    var option; | 
				
			||||
    var c      = null; | 
				
			||||
    var s      = null; | 
				
			||||
    var i; | 
				
			||||
    var maxFrom, maxTo; | 
				
			||||
 | 
				
			||||
    if (action === 'add' || action === 'all' || action === 'toggle') { | 
				
			||||
        source = selectLeft; | 
				
			||||
        target = selectRight; | 
				
			||||
    } else { | 
				
			||||
        source = selectRight; | 
				
			||||
        target = selectLeft; | 
				
			||||
    } | 
				
			||||
    // Don't do anything if nothing selected. Otherwise we throw javascript errors.
 | 
				
			||||
    if (source.selectedIndex === -1 && (action === 'add' || action === 'remove')) { | 
				
			||||
        return; | 
				
			||||
    } | 
				
			||||
    maxFrom = source.options.length; | 
				
			||||
    maxTo   = target.options.length; | 
				
			||||
 | 
				
			||||
    // check if target list is empty and remove fake empty option (tip to be XHTML compliant)
 | 
				
			||||
    if (maxTo > 0 && target.options[0].value === "") { | 
				
			||||
        target.removeAttribute("disabled"); | 
				
			||||
        target.options[0] = null; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    // Add items to the 'TO' list.
 | 
				
			||||
    for (i = (maxFrom - 1); i >= 0; i--) { | 
				
			||||
        if (action === 'all' || action === 'none' || action === 'toggle' || source.options[i].selected === true) { | 
				
			||||
            if (source.options[i].disabled === false) { | 
				
			||||
                if (isIE) { | 
				
			||||
                    option = source.options[i].removeNode(true); | 
				
			||||
                    option.selected = QFAMS.env.persistantSelection; | 
				
			||||
                    target.appendChild(option); | 
				
			||||
                } else { | 
				
			||||
                    option = source.options[i].cloneNode(true); | 
				
			||||
                    option.selected = QFAMS.env.persistantSelection; | 
				
			||||
                    target.options[target.options.length] = option; | 
				
			||||
                } | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    // Remove items from the 'FROM' list.
 | 
				
			||||
    if (!isIE) { | 
				
			||||
        for (i = (maxFrom - 1); i >= 0; i--) { | 
				
			||||
            if (action === 'all' || action === 'none' || action === 'toggle' || source.options[i].selected === true) { | 
				
			||||
                if (source.options[i].disabled === false) { | 
				
			||||
                    source.options[i] = null; | 
				
			||||
                } | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    // Add items to the 'FROM' list for toggle function
 | 
				
			||||
    if (action === 'toggle') { | 
				
			||||
        for (i = (maxTo - 1); i >= 0; i--) { | 
				
			||||
            if (target.options[i].disabled === false) { | 
				
			||||
                if (isIE) { | 
				
			||||
                    option = target.options[i].removeNode(true); | 
				
			||||
                    option.selected = QFAMS.env.persistantSelection; | 
				
			||||
                    source.appendChild(option); | 
				
			||||
                } else { | 
				
			||||
                    option = target.options[i].cloneNode(true); | 
				
			||||
                    option.selected = QFAMS.env.persistantSelection; | 
				
			||||
                    source.options[source.options.length] = option; | 
				
			||||
                } | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        if (!isIE) { | 
				
			||||
            for (i = (maxTo - 1); i >= 0; i--) { | 
				
			||||
                if (target.options[i].disabled === false) { | 
				
			||||
                    target.options[i] = null; | 
				
			||||
                } | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    // updates unselected item count
 | 
				
			||||
    c = document.getElementById(qfamsName + '_unselected'); | 
				
			||||
    s = document.getElementById(qfamsName + '-f'); | 
				
			||||
    QFAMS.updateCounter(c, s.length); | 
				
			||||
 | 
				
			||||
    // updates selected item count
 | 
				
			||||
    c = document.getElementById(qfamsName + '_selected'); | 
				
			||||
    s = document.getElementById(qfamsName + '-t'); | 
				
			||||
    QFAMS.updateCounter(c, s.length); | 
				
			||||
 | 
				
			||||
    // Sort list if required
 | 
				
			||||
    if (arrange !== 'none') { | 
				
			||||
        QFAMS.sortList(target, QFAMS.compareText, arrange); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    // Set the appropriate items as 'selected in the hidden select.
 | 
				
			||||
    // These are the values that will actually be posted with the form.
 | 
				
			||||
    QFAMS.updateHidden(selectHidden, selectRight); | 
				
			||||
 | 
				
			||||
    // Order alphabetically
 | 
				
			||||
 | 
				
			||||
    //var sourceId = $(source).attr('id');
 | 
				
			||||
    var targetId = $(target).attr('id'); | 
				
			||||
    var options = $('#' + targetId +' option'); | 
				
			||||
 | 
				
			||||
    var arr = options.map(function(_, o) { return { t: $(o).text(), v: o.value }; }).get(); | 
				
			||||
    arr.sort(function (o1, o2) { | 
				
			||||
        //return o1.t > o2.t ? 1 : o1.t < o2.t ? -1 : 0;
 | 
				
			||||
        // Ignore case
 | 
				
			||||
        var t1 = o1.t.toLowerCase(), t2 = o2.t.toLowerCase(); | 
				
			||||
        return t1 > t2 ? 1 : t1 < t2 ? -1 : 0; | 
				
			||||
    }); | 
				
			||||
 | 
				
			||||
    options.each(function(i, o) { | 
				
			||||
        o.value = arr[i].v; | 
				
			||||
        $(o).text(arr[i].t); | 
				
			||||
    }); | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Uses QFAMS.sortList to | 
				
			||||
 * sort selection list if option is given in HTML_QuickForm_advmultiselect class constructor | 
				
			||||
 * | 
				
			||||
 * @param      dom element   list           Selection data list | 
				
			||||
 * @param      prototype     compareFunction to sort each element of a list | 
				
			||||
 * @param      string        arrange        Sort option (none, asc, desc) | 
				
			||||
 * | 
				
			||||
 * @method     sortList | 
				
			||||
 * @static | 
				
			||||
 * @return     void | 
				
			||||
 * @private | 
				
			||||
 * @since      1.5.0 | 
				
			||||
 */ | 
				
			||||
QFAMS.sortList = function (list, compareFunction, arrange) | 
				
			||||
{ | 
				
			||||
    var i; | 
				
			||||
    var options = new Array(list.options.length); | 
				
			||||
 | 
				
			||||
    for (i = 0; i < options.length; i++) { | 
				
			||||
        options[i] = new Option(list.options[i].text, | 
				
			||||
                                list.options[i].value, | 
				
			||||
                                list.options[i].defaultSelected, | 
				
			||||
                                list.options[i].selected); | 
				
			||||
    } | 
				
			||||
    options.sort(compareFunction); | 
				
			||||
    if (arrange === 'desc') { | 
				
			||||
        options.reverse(); | 
				
			||||
    } | 
				
			||||
    list.options.length = 0; | 
				
			||||
    for (i = 0; i < options.length; i++) { | 
				
			||||
        list.options[i] = options[i]; | 
				
			||||
    } | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * QFAMS.compareText | 
				
			||||
 * is a callback function to sort each element of two lists A and B | 
				
			||||
 * | 
				
			||||
 * @param      string        option1        single element of list A | 
				
			||||
 * @param      string        option2        single element of list B | 
				
			||||
 * | 
				
			||||
 * @method     compareText | 
				
			||||
 * @static | 
				
			||||
 * @return     integer       -1 if option1 is less than option2, | 
				
			||||
 *                            0 if option1 is equal to option2 | 
				
			||||
 *                            1 if option1 is greater than option2 | 
				
			||||
 * @private | 
				
			||||
 * @since      1.5.0 | 
				
			||||
 */ | 
				
			||||
QFAMS.compareText = function (option1, option2) { | 
				
			||||
    if (option1.text === option2.text) { | 
				
			||||
        return 0; | 
				
			||||
    } | 
				
			||||
    return option1.text < option2.text ? -1 : 1; | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * QFAMS.updateHidden | 
				
			||||
 * updates the private list that handle selection of all elements (selected and unselected) | 
				
			||||
 * | 
				
			||||
 * @param      dom element   h              hidden list (contains all elements) | 
				
			||||
 * @param      dom element   r              selection list (contains only elements selected) | 
				
			||||
 * | 
				
			||||
 * @method     updateHidden | 
				
			||||
 * @static | 
				
			||||
 * @return     void | 
				
			||||
 * @private | 
				
			||||
 * @since      1.5.0 | 
				
			||||
 */ | 
				
			||||
QFAMS.updateHidden = function (h, r) { | 
				
			||||
    var i; | 
				
			||||
 | 
				
			||||
    for (i = 0; i < h.length; i++) { | 
				
			||||
        h.options[i].selected = false; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    for (i = 0; i < r.length; i++) { | 
				
			||||
        h.options[h.length] = new Option(r.options[i].text, r.options[i].value); | 
				
			||||
        h.options[h.length - 1].selected = true; | 
				
			||||
    } | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * With QFAMS.moveUp | 
				
			||||
 * end-user may arrange and element up to the selection list | 
				
			||||
 * | 
				
			||||
 * @param      dom element   l              selection list (contains only elements selected) | 
				
			||||
 * @param      dom element   h              hidden list (contains all elements) | 
				
			||||
 * | 
				
			||||
 * @method     moveUp | 
				
			||||
 * @static | 
				
			||||
 * @return     void | 
				
			||||
 * @public | 
				
			||||
 * @since      1.5.0 | 
				
			||||
 */ | 
				
			||||
QFAMS.moveUp = function (l, h) { | 
				
			||||
    var indice = l.selectedIndex; | 
				
			||||
    if (indice < 0) { | 
				
			||||
        return; | 
				
			||||
    } | 
				
			||||
    if (indice > 0) { | 
				
			||||
        QFAMS.moveSwap(l, indice, indice - 1); | 
				
			||||
        QFAMS.updateHidden(h, l); | 
				
			||||
    } | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * With QFAMS.moveDown | 
				
			||||
 * end-user may arrange and element down to the selection list | 
				
			||||
 * | 
				
			||||
 * @param      dom element   l              selection list (contains only elements selected) | 
				
			||||
 * @param      dom element   h              hidden list (contains all elements) | 
				
			||||
 * | 
				
			||||
 * @method     moveDown | 
				
			||||
 * @static | 
				
			||||
 * @return     void | 
				
			||||
 * @public | 
				
			||||
 * @since      1.5.0 | 
				
			||||
 */ | 
				
			||||
QFAMS.moveDown = function (l, h) { | 
				
			||||
    var indice = l.selectedIndex; | 
				
			||||
    if (indice < 0) { | 
				
			||||
        return; | 
				
			||||
    } | 
				
			||||
    if (indice < l.options.length - 1) { | 
				
			||||
        QFAMS.moveSwap(l, indice, indice + 1); | 
				
			||||
        QFAMS.updateHidden(h, l); | 
				
			||||
    } | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * With QFAMS.moveTop | 
				
			||||
 * end-user may arrange and element up to the top of selection list | 
				
			||||
 * | 
				
			||||
 * @param      dom element   l              selection list (contains only elements selected) | 
				
			||||
 * @param      dom element   h              hidden list (contains all elements) | 
				
			||||
 * | 
				
			||||
 * @method     moveTop | 
				
			||||
 * @static | 
				
			||||
 * @return     void | 
				
			||||
 * @public | 
				
			||||
 * @since      1.5.0 | 
				
			||||
 */ | 
				
			||||
QFAMS.moveTop = function (l, h) { | 
				
			||||
    var indice = l.selectedIndex; | 
				
			||||
    if (indice < 0) { | 
				
			||||
        return; | 
				
			||||
    } | 
				
			||||
    while (indice > 0) { | 
				
			||||
        QFAMS.moveSwap(l, indice, indice - 1); | 
				
			||||
        QFAMS.updateHidden(h, l); | 
				
			||||
        indice--; | 
				
			||||
    } | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * With QFAMS.moveBottom | 
				
			||||
 * end-user may arrange and element down to the bottom of selection list | 
				
			||||
 * | 
				
			||||
 * @param      dom element   l              selection list (contains only elements selected) | 
				
			||||
 * @param      dom element   h              hidden list (contains all elements) | 
				
			||||
 * | 
				
			||||
 * @method     moveBottom | 
				
			||||
 * @static | 
				
			||||
 * @return     void | 
				
			||||
 * @public | 
				
			||||
 * @since      1.5.0 | 
				
			||||
 */ | 
				
			||||
QFAMS.moveBottom = function (l, h) { | 
				
			||||
    var indice = l.selectedIndex; | 
				
			||||
    if (indice < 0) { | 
				
			||||
        return; | 
				
			||||
    } | 
				
			||||
    while (indice < l.options.length - 1) { | 
				
			||||
        QFAMS.moveSwap(l, indice, indice + 1); | 
				
			||||
        QFAMS.updateHidden(h, l); | 
				
			||||
        indice++; | 
				
			||||
    } | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * With QFAMS.moveSwap | 
				
			||||
 * end-user may invert two elements position in the selection list | 
				
			||||
 * | 
				
			||||
 * @param      dom element   l              selection list (contains only elements selected) | 
				
			||||
 * @param      integer       i              element source indice | 
				
			||||
 * @param      integer       j              element target indice | 
				
			||||
 * | 
				
			||||
 * @method     moveSwap | 
				
			||||
 * @static | 
				
			||||
 * @return     void | 
				
			||||
 * @public | 
				
			||||
 * @since      1.5.0 | 
				
			||||
 */ | 
				
			||||
QFAMS.moveSwap = function (l, i, j) { | 
				
			||||
    var node; | 
				
			||||
 | 
				
			||||
    node = l.replaceChild(l.options[i], l.options[j]); | 
				
			||||
    if (i > j) { | 
				
			||||
        l.insertBefore(node, l.options[j].nextSibling); | 
				
			||||
    } else { | 
				
			||||
        l.insertBefore(node, l.options[i]); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    if (QFAMS.env.persistantMove) { | 
				
			||||
        l.selectedIndex = j; | 
				
			||||
    } else { | 
				
			||||
        l.selectedIndex = -1; | 
				
			||||
    } | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Uses QFAMS.init to | 
				
			||||
 * initialize onclick event handler for all checkbox element | 
				
			||||
 * of a QuickForm advmultiselect element with single select box. | 
				
			||||
 * | 
				
			||||
 * @method     init | 
				
			||||
 * @static | 
				
			||||
 * @return     void | 
				
			||||
 * @public | 
				
			||||
 * @since      1.5.0 | 
				
			||||
 */ | 
				
			||||
QFAMS.init = function (elm) | 
				
			||||
{ | 
				
			||||
    var e, i; | 
				
			||||
 | 
				
			||||
    for (e = 0; e < elm.length; e++) { | 
				
			||||
        var div = document.getElementById('qfams_' + elm[e]); | 
				
			||||
        if (div !== null) { | 
				
			||||
            var inputs = div.getElementsByTagName('input'); | 
				
			||||
            if (inputs !== null) { | 
				
			||||
                for (i = 0; i < inputs.length; i++) { | 
				
			||||
                    inputs[i].onclick = QFAMS.updateLiveCounter; | 
				
			||||
                } | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
$(function() { | 
				
			||||
 | 
				
			||||
    $('.advmultiselect_checkbox').click(function() { | 
				
			||||
        var id = $(this).attr('id'); | 
				
			||||
        var selectName = id + '-f'; | 
				
			||||
        var selectId = selectName.replace('_select_all', ''); | 
				
			||||
        var selectDestinationId = selectId.replace('-f', '-t'); | 
				
			||||
 | 
				
			||||
        $('#'+selectDestinationId).prop("disabled", false); | 
				
			||||
 | 
				
			||||
        var checked = !$('#'+ id).is(':checked'); | 
				
			||||
        if (!checked) { | 
				
			||||
            $('#users-f option').prop('selected', true); | 
				
			||||
            QFAMS.moveSelection('users', this.form.elements['users-f[]'], this.form.elements['users-t[]'], this.form.elements['users[]'], 'add', 'none'); | 
				
			||||
        } else { | 
				
			||||
            $('#users-t option').prop('selected', true); | 
				
			||||
            QFAMS.moveSelection('users', this.form.elements['users-f[]'], this.form.elements['users-t[]'], this.form.elements['users[]'], 'remove', 'none'); | 
				
			||||
        } | 
				
			||||
    }); | 
				
			||||
}); | 
				
			||||
@ -0,0 +1,397 @@ | 
				
			||||
<?php | 
				
			||||
/* For licensing terms, see /license.txt */ | 
				
			||||
 | 
				
			||||
use Chamilo\CoreBundle\Entity\Repository\LegalRepository; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * @package chamilo.messages | 
				
			||||
 */ | 
				
			||||
$cidReset = true; | 
				
			||||
 | 
				
			||||
require_once __DIR__.'/../inc/global.inc.php'; | 
				
			||||
 | 
				
			||||
api_block_anonymous_users(); | 
				
			||||
 | 
				
			||||
if (!api_get_configuration_value('enable_gdpr')) { | 
				
			||||
    api_not_allowed(true); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
$userId = api_get_user_id(); | 
				
			||||
$userInfo = api_get_user_info(); | 
				
			||||
 | 
				
			||||
$substitutionTerms = [ | 
				
			||||
    'password' => get_lang('EncryptedData'), | 
				
			||||
    'salt' => get_lang('RandomData'), | 
				
			||||
    'empty' => get_lang('NoData'), | 
				
			||||
]; | 
				
			||||
 | 
				
			||||
$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : ''; | 
				
			||||
$formToString = ''; | 
				
			||||
 | 
				
			||||
if (api_get_setting('allow_terms_conditions') === 'true') { | 
				
			||||
    $form = new FormValidator('delete_term', 'post', api_get_self().'?action=delete_legal&user_id='.$userId); | 
				
			||||
    $form->addHtml(Display::return_message(get_lang('WhyYouWantToDeleteYourLegalAgreement'))); | 
				
			||||
    $form->addTextarea('explanation', get_lang('ExplanationDeleteLegal'), [], true); | 
				
			||||
    $form->addHidden('action', 'delete_legal'); | 
				
			||||
    $form->addButtonSave(get_lang('DeleteLegal')); | 
				
			||||
    $formToString = $form->returnForm(); | 
				
			||||
 | 
				
			||||
    $formDelete = new FormValidator('delete_account', 'post', api_get_self().'?action=delete_account&user_id='.$userId); | 
				
			||||
    $formDelete->addTextarea('explanation', get_lang('ExplanationDeleteAccount'), [], true); | 
				
			||||
    $formDelete->addHidden('action', 'delete_account'); | 
				
			||||
    $formDelete->addButtonDelete(get_lang('DeleteAccount')); | 
				
			||||
    $formToString .= $formDelete->returnForm(); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
switch ($action) { | 
				
			||||
    case 'send_legal': | 
				
			||||
        $language = api_get_interface_language(); | 
				
			||||
        $language = api_get_language_id($language); | 
				
			||||
        $terms = LegalManager::get_last_condition($language); | 
				
			||||
        if (!$terms) { | 
				
			||||
            //look for the default language | 
				
			||||
            $language = api_get_setting('platformLanguage'); | 
				
			||||
            $language = api_get_language_id($language); | 
				
			||||
            $terms = LegalManager::get_last_condition($language); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $legalAcceptType = $terms['version'].':'.$terms['language_id'].':'.time(); | 
				
			||||
        UserManager::update_extra_field_value( | 
				
			||||
            $userId, | 
				
			||||
            'legal_accept', | 
				
			||||
            $legalAcceptType | 
				
			||||
        ); | 
				
			||||
 | 
				
			||||
        Event::addEvent( | 
				
			||||
            LOG_TERM_CONDITION_ACCEPTED, | 
				
			||||
            LOG_USER_OBJECT, | 
				
			||||
            api_get_user_info($userId), | 
				
			||||
            api_get_utc_datetime() | 
				
			||||
        ); | 
				
			||||
 | 
				
			||||
        $bossList = UserManager::getStudentBossList($userId); | 
				
			||||
        if (!empty($bossList)) { | 
				
			||||
            $bossList = array_column($bossList, 'boss_id'); | 
				
			||||
            $currentUserInfo = api_get_user_info($userId); | 
				
			||||
            foreach ($bossList as $bossId) { | 
				
			||||
                $subjectEmail = sprintf( | 
				
			||||
                    get_lang('UserXSignedTheAgreement'), | 
				
			||||
                    $currentUserInfo['complete_name'] | 
				
			||||
                ); | 
				
			||||
                $contentEmail = sprintf( | 
				
			||||
                    get_lang('UserXSignedTheAgreementTheDateY'), | 
				
			||||
                    $currentUserInfo['complete_name'], | 
				
			||||
                    api_get_local_time($time) | 
				
			||||
                ); | 
				
			||||
 | 
				
			||||
                MessageManager::send_message_simple( | 
				
			||||
                    $bossId, | 
				
			||||
                    $subjectEmail, | 
				
			||||
                    $contentEmail, | 
				
			||||
                    $user_id | 
				
			||||
                ); | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        Display::addFlash(Display::return_message(get_lang('Saved'))); | 
				
			||||
        break; | 
				
			||||
    case 'delete_account': | 
				
			||||
        if ($formDelete->validate()) { | 
				
			||||
            $explanation = $formDelete->getSubmitValue('explanation'); | 
				
			||||
            UserManager::createDataPrivacyExtraFields(); | 
				
			||||
 | 
				
			||||
            // Remove delete agreement if it was sent: | 
				
			||||
            UserManager::update_extra_field_value( | 
				
			||||
                $userId, | 
				
			||||
                'request_for_legal_agreement_consent_removal', | 
				
			||||
                '' | 
				
			||||
            ); | 
				
			||||
 | 
				
			||||
            UserManager::update_extra_field_value( | 
				
			||||
                $userId, | 
				
			||||
                'request_for_legal_agreement_consent_removal_justification', | 
				
			||||
                '' | 
				
			||||
            ); | 
				
			||||
 | 
				
			||||
            UserManager::update_extra_field_value( | 
				
			||||
                $userId, | 
				
			||||
                'request_for_delete_account', | 
				
			||||
                1 | 
				
			||||
            ); | 
				
			||||
            UserManager::update_extra_field_value( | 
				
			||||
                $userId, | 
				
			||||
                'request_for_delete_account_justification', | 
				
			||||
                $explanation | 
				
			||||
            ); | 
				
			||||
 | 
				
			||||
            Display::addFlash(Display::return_message(get_lang('Saved'))); | 
				
			||||
            Event::addEvent( | 
				
			||||
                LOG_USER_DELETE_ACCOUNT_REQUEST, | 
				
			||||
                LOG_USER_OBJECT, | 
				
			||||
                $userInfo | 
				
			||||
            ); | 
				
			||||
 | 
				
			||||
            $url = api_get_path(WEB_CODE_PATH).'admin/'; | 
				
			||||
            $link = Display::url($url, $url); | 
				
			||||
            $subject = get_lang('RequestForDeleteAccount'); | 
				
			||||
            $content = sprintf( | 
				
			||||
                get_lang('TheUserXAskDeleteAccountWithJustifactionXGoHereX'), | 
				
			||||
                $userInfo['complete_name'], | 
				
			||||
                $explanation, | 
				
			||||
                $link | 
				
			||||
            ); | 
				
			||||
 | 
				
			||||
            $email = api_get_configuration_value('data_protection_officer_email'); | 
				
			||||
            if (!empty($email)) { | 
				
			||||
                api_mail_html('', $email, $subject, $content); | 
				
			||||
            } else { | 
				
			||||
                MessageManager::sendMessageToAllAdminUsers(api_get_user_id(), $subject, $content); | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        break; | 
				
			||||
    case 'delete_legal': | 
				
			||||
        if ($form->validate()) { | 
				
			||||
            $explanation = $form->getSubmitValue('explanation'); | 
				
			||||
 | 
				
			||||
            UserManager::createDataPrivacyExtraFields(); | 
				
			||||
 | 
				
			||||
            UserManager::update_extra_field_value( | 
				
			||||
                $userId, | 
				
			||||
                'request_for_legal_agreement_consent_removal', | 
				
			||||
                1 | 
				
			||||
            ); | 
				
			||||
 | 
				
			||||
            UserManager::update_extra_field_value( | 
				
			||||
                $userId, | 
				
			||||
                'request_for_legal_agreement_consent_removal_justification', | 
				
			||||
                $explanation | 
				
			||||
            ); | 
				
			||||
 | 
				
			||||
            /*$extraFieldValue = new ExtraFieldValue('user'); | 
				
			||||
            $value = $extraFieldValue->get_values_by_handler_and_field_variable( | 
				
			||||
                $userId, | 
				
			||||
                'legal_accept' | 
				
			||||
            ); | 
				
			||||
            $result = $extraFieldValue->delete($value['id']);*/ | 
				
			||||
 | 
				
			||||
            Display::addFlash(Display::return_message(get_lang('Sent'))); | 
				
			||||
 | 
				
			||||
            Event::addEvent( | 
				
			||||
                LOG_USER_REMOVED_LEGAL_ACCEPT, | 
				
			||||
                LOG_USER_OBJECT, | 
				
			||||
                $userInfo | 
				
			||||
            ); | 
				
			||||
 | 
				
			||||
            $url = api_get_path(WEB_CODE_PATH).'admin/'; | 
				
			||||
            $link = Display::url($url, $url); | 
				
			||||
            $subject = get_lang('RequestForLegalConsentRemoval'); | 
				
			||||
            $content = sprintf( | 
				
			||||
                get_lang('TheUserXAskRemovalWithJustifactionXGoHereX'), | 
				
			||||
                $userInfo['complete_name'], | 
				
			||||
                $explanation, | 
				
			||||
                $link | 
				
			||||
            ); | 
				
			||||
 | 
				
			||||
            $email = api_get_configuration_value('data_protection_officer_email'); | 
				
			||||
            if (!empty($email)) { | 
				
			||||
                api_mail_html('', $email, $subject, $content); | 
				
			||||
            } else { | 
				
			||||
                MessageManager::sendMessageToAllAdminUsers(api_get_user_id(), $subject, $content); | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        break; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
$propertiesToJson = UserManager::getRepository()->getPersonalDataToJson($userId, $substitutionTerms); | 
				
			||||
 | 
				
			||||
if (!empty($_GET['export'])) { | 
				
			||||
    $filename = md5(mt_rand(0, 1000000)).'.json'; | 
				
			||||
    $path = api_get_path(SYS_ARCHIVE_PATH).$filename; | 
				
			||||
    $writeResult = file_put_contents($path, $propertiesToJson); | 
				
			||||
    if ($writeResult !== false) { | 
				
			||||
        DocumentManager::file_send_for_download($path, true, $filename); | 
				
			||||
        exit; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
$allowSocial = api_get_setting('allow_social_tool') === 'true'; | 
				
			||||
 | 
				
			||||
$nameTools = get_lang('PersonalDataReport'); | 
				
			||||
$show_message = null; | 
				
			||||
 | 
				
			||||
if ($allowSocial) { | 
				
			||||
    $this_section = SECTION_SOCIAL; | 
				
			||||
    $interbreadcrumb[] = [ | 
				
			||||
        'url' => api_get_path(WEB_PATH).'main/social/home.php', | 
				
			||||
        'name' => get_lang('SocialNetwork'), | 
				
			||||
    ]; | 
				
			||||
} else { | 
				
			||||
    $this_section = SECTION_MYPROFILE; | 
				
			||||
    $interbreadcrumb[] = [ | 
				
			||||
        'url' => api_get_path(WEB_PATH).'main/auth/profile.php', | 
				
			||||
        'name' => get_lang('Profile'), | 
				
			||||
    ]; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
$interbreadcrumb[] = ['url' => '#', 'name' => get_lang('PersonalDataReport')]; | 
				
			||||
 | 
				
			||||
// LEFT CONTENT | 
				
			||||
$socialMenuBlock = ''; | 
				
			||||
if ($allowSocial) { | 
				
			||||
    // Block Social Menu | 
				
			||||
    $socialMenuBlock = SocialManager::show_social_menu('personal-data'); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
// MAIN CONTENT | 
				
			||||
$personalDataContent = '<ul>'; | 
				
			||||
$properties = json_decode($propertiesToJson); | 
				
			||||
 | 
				
			||||
foreach ($properties as $key => $value) { | 
				
			||||
    if (is_array($value) || is_object($value)) { | 
				
			||||
        switch ($key) { | 
				
			||||
            case 'extraFields': | 
				
			||||
                $personalDataContent .= '<li>'.$key.': </li><ul>'; | 
				
			||||
                foreach ($value as $subValue) { | 
				
			||||
                    $personalDataContent .= '<li>'.$subValue->variable.': '.$subValue->value.'</li>'; | 
				
			||||
                } | 
				
			||||
                $personalDataContent .= '</ul>'; | 
				
			||||
                break; | 
				
			||||
            case 'portals': | 
				
			||||
            case 'roles': | 
				
			||||
            case 'achievedSkills': | 
				
			||||
            case 'sessionAsGeneralCoach': | 
				
			||||
            case 'classes': | 
				
			||||
            case 'courses': | 
				
			||||
            case 'groupNames': | 
				
			||||
            case 'groups': | 
				
			||||
                $personalDataContent .= '<li>'.$key.': </li><ul>'; | 
				
			||||
                foreach ($value as $subValue) { | 
				
			||||
                    $personalDataContent .= '<li>'.$subValue.'</li>'; | 
				
			||||
                } | 
				
			||||
                $personalDataContent .= '</ul>'; | 
				
			||||
                break; | 
				
			||||
            case 'sessionCourseSubscriptions': | 
				
			||||
                $personalDataContent .= '<li>'.$key.': </li><ul>'; | 
				
			||||
                foreach ($value as $session => $courseList) { | 
				
			||||
                    $personalDataContent .= '<li>'.$session.'<ul>'; | 
				
			||||
                    foreach ($courseList as $course) { | 
				
			||||
                        $personalDataContent .= '<li>'.$course.'</li>'; | 
				
			||||
                    } | 
				
			||||
                    $personalDataContent .= '</ul>'; | 
				
			||||
                } | 
				
			||||
                $personalDataContent .= '</ul>'; | 
				
			||||
                break; | 
				
			||||
            default: | 
				
			||||
                //var_dump($key); | 
				
			||||
                break; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        /*foreach ($value as $subValue) { | 
				
			||||
            foreach ($subValue as $subSubValue) { | 
				
			||||
                var_dump($subSubValue); | 
				
			||||
                //$personalDataContent .= '<li>'.$subSubValue.'</li>'; | 
				
			||||
            } | 
				
			||||
        }*/ | 
				
			||||
        //skip in some cases | 
				
			||||
        /*sif (!empty($value['date'])) { | 
				
			||||
            $personalDataContent .= '<li>'.$key.': '.$value['date'].'</li>'; | 
				
			||||
        } else { | 
				
			||||
            $personalDataContent .= '<li>'.$key.': '.get_lang('ComplexDataNotShown').'</li>'; | 
				
			||||
        }*/ | 
				
			||||
    } else { | 
				
			||||
        $personalDataContent .= '<li>'.$key.': '.$value.'</li>'; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
$personalDataContent .= '</ul>'; | 
				
			||||
 | 
				
			||||
// Check terms acceptation | 
				
			||||
$permitionBlock = ''; | 
				
			||||
if (api_get_setting('allow_terms_conditions') === 'true') { | 
				
			||||
    $extraFieldValue = new ExtraFieldValue('user'); | 
				
			||||
    $value = $extraFieldValue->get_values_by_handler_and_field_variable( | 
				
			||||
        $userId, | 
				
			||||
        'legal_accept' | 
				
			||||
    ); | 
				
			||||
    $permitionBlock .= Display::return_icon('accept_na.png', get_lang('NotAccepted')); | 
				
			||||
    if (isset($value['value']) && !empty($value['value'])) { | 
				
			||||
        list($legalId, $legalLanguageId, $legalTime) = explode(':', $value['value']); | 
				
			||||
        $permitionBlock = get_lang('CurrentStatus').': '. | 
				
			||||
            Display::return_icon('accept.png', get_lang('LegalAgreementAccepted')).get_lang('LegalAgreementAccepted'). | 
				
			||||
            '<br />'; | 
				
			||||
        $permitionBlock .= get_lang('Date').': '.api_get_local_time($legalTime).'<br />'; | 
				
			||||
        $permitionBlock .= $formToString; | 
				
			||||
 | 
				
			||||
    /*$permitionBlock .= Display::url( | 
				
			||||
        get_lang('DeleteLegal'), | 
				
			||||
        api_get_self().'?action=delete_legal&user_id='.$userId, | 
				
			||||
        ['class' => 'btn btn-danger btn-xs'] | 
				
			||||
    );*/ | 
				
			||||
    } else { | 
				
			||||
        // @TODO add action handling for button | 
				
			||||
        $permitionBlock .= Display::url( | 
				
			||||
            get_lang('SendLegal'), | 
				
			||||
            api_get_self().'?action=send_legal&user_id='.$userId, | 
				
			||||
            ['class' => 'btn btn-primary btn-xs'] | 
				
			||||
        ); | 
				
			||||
    } | 
				
			||||
} else { | 
				
			||||
    $permitionBlock .= get_lang('NoTermsAndConditionsAvailable'); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
//Build the final array to pass to template | 
				
			||||
$personalData = []; | 
				
			||||
$personalData['data'] = $personalDataContent; | 
				
			||||
//$personalData['responsible'] = api_get_setting('personal_data_responsible_org'); | 
				
			||||
 | 
				
			||||
$em = Database::getManager(); | 
				
			||||
/** @var LegalRepository $legalTermsRepo */ | 
				
			||||
$legalTermsRepo = $em->getRepository('ChamiloCoreBundle:Legal'); | 
				
			||||
// Get data about the treatment of data | 
				
			||||
$treatmentTypes = LegalManager::getTreatmentTypeList(); | 
				
			||||
 | 
				
			||||
foreach ($treatmentTypes as $id => $item) { | 
				
			||||
    $personalData['treatment'][$item]['title'] = get_lang('PersonalData'.ucfirst($item).'Title'); | 
				
			||||
    $legalTerm = $legalTermsRepo->findOneByTypeAndLanguage($id, api_get_language_id($user_language)); | 
				
			||||
    $legalTermContent = ''; | 
				
			||||
    if (!empty($legalTerm[0]) && is_array($legalTerm[0])) { | 
				
			||||
        $legalTermContent = $legalTerm[0]['content']; | 
				
			||||
    } | 
				
			||||
    $personalData['treatment'][$item]['content'] = $legalTermContent; | 
				
			||||
} | 
				
			||||
$officerName = api_get_configuration_value('data_protection_officer_name'); | 
				
			||||
$officerRole = api_get_configuration_value('data_protection_officer_role'); | 
				
			||||
$officerEmail = api_get_configuration_value('data_protection_officer_email'); | 
				
			||||
if (!empty($officerName)) { | 
				
			||||
    $personalData['officer_name'] = $officerName; | 
				
			||||
    $personalData['officer_role'] = $officerRole; | 
				
			||||
    $personalData['officer_email'] = $officerEmail; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
$tpl = new Template(null); | 
				
			||||
 | 
				
			||||
$actions = Display::url( | 
				
			||||
    Display::return_icon('excel.png', get_lang('Export'), [], ICON_SIZE_MEDIUM), | 
				
			||||
    api_get_path(WEB_CODE_PATH).'social/personal_data.php?export=1' | 
				
			||||
); | 
				
			||||
 | 
				
			||||
$tpl->assign('actions', Display::toolbarAction('toolbar', [$actions])); | 
				
			||||
 | 
				
			||||
$termLink = ''; | 
				
			||||
if (api_get_setting('allow_terms_conditions') === 'true') { | 
				
			||||
    $url = api_get_path(WEB_CODE_PATH).'social/terms.php'; | 
				
			||||
    $termLink = Display::url($url, $url); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
// Block Social Avatar | 
				
			||||
SocialManager::setSocialUserBlock($tpl, api_get_user_id(), 'messages'); | 
				
			||||
if (api_get_setting('allow_social_tool') === 'true') { | 
				
			||||
    $tpl->assign('social_menu_block', $socialMenuBlock); | 
				
			||||
    $tpl->assign('personal_data', $personalData); | 
				
			||||
} else { | 
				
			||||
    $tpl->assign('social_menu_block', ''); | 
				
			||||
    $tpl->assign('personal_data_block', $personalDataContent); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
$tpl->assign('permission', $permitionBlock); | 
				
			||||
$tpl->assign('term_link', $termLink); | 
				
			||||
$socialLayout = $tpl->get_template('social/personal_data.tpl'); | 
				
			||||
$tpl->display($socialLayout); | 
				
			||||
@ -0,0 +1,52 @@ | 
				
			||||
<?php | 
				
			||||
/* For licensing terms, see /license.txt */ | 
				
			||||
 | 
				
			||||
$cidReset = true; | 
				
			||||
 | 
				
			||||
require_once __DIR__.'/../inc/global.inc.php'; | 
				
			||||
 | 
				
			||||
if (api_get_setting('allow_terms_conditions') !== 'true') { | 
				
			||||
    api_not_allowed(true); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
api_block_anonymous_users(); | 
				
			||||
 | 
				
			||||
$language = api_get_interface_language(); | 
				
			||||
$language = api_get_language_id($language); | 
				
			||||
$term = LegalManager::get_last_condition($language); | 
				
			||||
 | 
				
			||||
if (!$term) { | 
				
			||||
    // look for the default language | 
				
			||||
    $language = api_get_setting('platformLanguage'); | 
				
			||||
    $language = api_get_language_id($language); | 
				
			||||
    $term = LegalManager::get_last_condition($language); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
$socialMenuBlock = ''; | 
				
			||||
$allowSocial = api_get_setting('allow_social_tool') === 'true'; | 
				
			||||
 | 
				
			||||
if ($allowSocial) { | 
				
			||||
    // Block Social Menu | 
				
			||||
    $socialMenuBlock = SocialManager::show_social_menu('personal-data'); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
$tpl = new Template(null); | 
				
			||||
 | 
				
			||||
$actions = Display::url( | 
				
			||||
    Display::return_icon('back.png', get_lang('Back'), [], ICON_SIZE_MEDIUM), | 
				
			||||
    api_get_path(WEB_CODE_PATH).'social/personal_data.php' | 
				
			||||
); | 
				
			||||
 | 
				
			||||
$tpl->assign('actions', Display::toolbarAction('toolbar', [$actions])); | 
				
			||||
 | 
				
			||||
// Block Social Avatar | 
				
			||||
SocialManager::setSocialUserBlock($tpl, api_get_user_id(), 'messages'); | 
				
			||||
if (api_get_setting('allow_social_tool') === 'true') { | 
				
			||||
    $tpl->assign('social_menu_block', $socialMenuBlock); | 
				
			||||
} else { | 
				
			||||
    $tpl->assign('social_menu_block', ''); | 
				
			||||
} | 
				
			||||
$tpl->assign('term', $term); | 
				
			||||
 | 
				
			||||
$socialLayout = $tpl->get_template('social/terms.tpl'); | 
				
			||||
$tpl->display($socialLayout); | 
				
			||||
					Loading…
					
					
				
		Reference in new issue