/**
 * Copy a profile_sync field to another profile field
 *
 * @param string $event  the name of the event
 * @param string $type   the type of the event
 * @param mixed  $object supplied object
 *
 * @return void
 */
function theme_haarlem_intranet_profile_sync_zakelijkemail($event, $type, $object)
{
    if (empty($object) || !is_array($object)) {
        return;
    }
    $user = elgg_extract('entity', $object);
    if (empty($user) || !elgg_instanceof($user, 'user')) {
        return;
    }
    $site = elgg_get_site_entity();
    // handle zakelijkemail
    $source_row = elgg_extract('source_row', $object);
    if (empty($source_row)) {
        return;
    }
    // duplicate email to profile field
    $email = elgg_extract('zakelijkemail', $source_row);
    $email = profile_sync_filter_var($email);
    if (!empty($email)) {
        // new value?
        if ($user->haarlem_email !== $email) {
            // default access
            $access = ACCESS_LOGGED_IN;
            if ($site instanceof Subsite) {
                $access = $site->getACL();
            }
            // get the access of existing profile data
            $access = profile_sync_get_profile_field_access($user->getGUID(), 'haarlem_email', $access);
            // save new value
            $user->setMetadata('haarlem_email', $email, '', false, $user->getGUID(), $access);
        }
    } elseif (isset($user->haarlem_email)) {
        // only unset if not set
        unset($user->haarlem_email);
    }
}
Example #2
0
/**
 * Run the profile synchronization based on the provided configuration
 *
 * @param ElggObject $sync_config The sync configuration
 *
 * @return void
 */
function profile_sync_proccess_configuration(ElggObject $sync_config)
{
    if (!elgg_instanceof($sync_config, 'object', 'profile_sync_config')) {
        return;
    }
    $datasource = $sync_config->getContainerEntity();
    if (!elgg_instanceof($datasource, 'object', 'profile_sync_datasource')) {
        return;
    }
    $sync_match = json_decode($sync_config->sync_match, true);
    $datasource_id = $sync_config->datasource_id;
    $profile_id = $sync_config->profile_id;
    $lastrun = (int) $sync_config->lastrun;
    $ban_user = (bool) $sync_config->ban_user;
    $unban_user = (bool) $sync_config->unban_user;
    profile_sync_log($sync_config->getGUID(), "Last run timestamp: {$lastrun} (" . date(elgg_echo('friendlytime:date_format'), $lastrun) . ")" . PHP_EOL);
    $profile_fields = elgg_get_config('profile_fields');
    if (!$ban_user && !$unban_user && empty($sync_match) || $datasource_id === '' || empty($profile_id)) {
        profile_sync_log($sync_config->getGUID(), 'Configuration error', true);
        return;
    }
    if (!in_array($profile_id, ['name', 'username', 'email']) && !array_key_exists($profile_id, $profile_fields)) {
        profile_sync_log($sync_config->getGUID(), "Invalid profile identifier: {$profile_id}", true);
        return;
    }
    switch ($datasource->datasource_type) {
        case 'mysql':
            $sync_source = new ProfileSyncMySQL($datasource, $lastrun);
            break;
        case 'csv':
            $sync_source = new ProfileSyncCSV($datasource, $lastrun);
            break;
        default:
            profile_sync_log($sync_config->getGUID(), "Invalid datasource type: {$datasource->datasource_type}", true);
            return;
            break;
    }
    if (!$sync_source->connect()) {
        profile_sync_log($sync_config->getGUID(), 'Unable to connect to the datasource', true);
        return;
    }
    $datasource_id_fallback = $sync_config->datasource_id_fallback;
    $profile_id_fallback = $sync_config->profile_id_fallback;
    $create_user = (bool) $sync_config->create_user;
    $notify_user = (bool) $sync_config->notify_user;
    $create_user_name = false;
    $create_user_email = false;
    $create_user_username = false;
    if ($create_user) {
        profile_sync_log($sync_config->getGUID(), 'User creation is allowed');
        foreach ($sync_match as $datasource_col => $datasource_config) {
            list($datasource_col) = explode(PROFILE_SYNC_DATASOURCE_COL_SEPERATOR, $datasource_col);
            switch ($datasource_config['profile_field']) {
                case 'name':
                    $create_user_name = $datasource_col;
                    break;
                case 'email':
                    $create_user_email = $datasource_col;
                    break;
                case 'username':
                    $create_user_username = $datasource_col;
                    break;
            }
        }
        if ($create_user_name === false || $create_user_username === false || $create_user_email === false) {
            profile_sync_log($sync_config->getGUID(), 'Missing information to create users');
            profile_sync_log($sync_config->getGUID(), "- name: {$create_user_name}");
            profile_sync_log($sync_config->getGUID(), "- email: {$create_user_email}");
            profile_sync_log($sync_config->getGUID(), "- username: {$create_user_username}");
            $create_user = false;
        }
    }
    if ($ban_user) {
        profile_sync_log($sync_config->getGUID(), 'Matching users will be banned');
    }
    if ($unban_user) {
        profile_sync_log($sync_config->getGUID(), 'Matching users will be unbanned');
    }
    if ($ban_user && $create_user) {
        profile_sync_log($sync_config->getGUID(), 'Both create and ban users is allowed, don\'t know what to do', true);
        return;
    }
    if ($unban_user && $create_user) {
        profile_sync_log($sync_config->getGUID(), 'Both create and unban users is allowed, don\'t know what to do', true);
        return;
    }
    if ($ban_user && $unban_user) {
        profile_sync_log($sync_config->getGUID(), 'Both ban and unban users is allowed, don\'t know what to do', true);
        return;
    }
    // start the sync process
    set_time_limit(0);
    _elgg_services()->db->disableQueryCache();
    $default_access = get_default_access();
    $ia = elgg_set_ignore_access(true);
    $site = elgg_get_site_entity();
    // we want to cache entity metadata on first __get()
    $metadata_cache = _elgg_services()->metadataCache;
    if ($metadata_cache instanceof ElggVolatileMetadataCache) {
        // elgg 1.10
        $metadata_cache->setIgnoreAccess(false);
    }
    $counters = ['source rows' => 0, 'empty source id' => 0, 'duplicate email' => 0, 'duplicate name' => 0, 'duplicate profile field' => 0, 'user not found' => 0, 'user created' => 0, 'user banned' => 0, 'user unbanned' => 0, 'empty attributes' => 0, 'invalid profile field' => 0, 'invalid source field' => 0, 'processed users' => 0];
    $base_location = '';
    if ($sync_source instanceof ProfileSyncCSV) {
        // get base path
        $csv_location = $datasource->csv_location;
        $csv_filename = basename($csv_location);
        $base_location = rtrim(str_ireplace($csv_filename, '', $csv_location), DIRECTORY_SEPARATOR);
    }
    while (($source_row = $sync_source->fetchRow()) !== false) {
        $counters['source rows']++;
        // let other plugins change the row data
        $params = ['datasource' => $datasource, 'sync_config' => $sync_config, 'source_row' => $source_row];
        $source_row = elgg_trigger_plugin_hook('source_row', 'profile_sync', $params, $source_row);
        if (!is_array($source_row) || empty($source_row[$datasource_id])) {
            $counters["empty source id"]++;
            continue;
        }
        // find user
        $datasource_used_id = $datasource_id;
        $profile_used_id = $profile_id;
        $datasource_unique_id = elgg_extract($datasource_id, $source_row);
        $user = profile_sync_find_user($profile_id, $datasource_unique_id, $sync_config, $counters);
        // fallback user
        if (empty($user) && $datasource_id_fallback !== '' && !empty($source_row[$datasource_id_fallback]) && !empty($profile_id_fallback)) {
            // 			profile_sync_log($sync_config->getGUID(), "User not found: {$profile_id} => {$datasource_unique_id} trying fallback");
            $profile_used_id = $profile_id_fallback;
            $datasource_used_id = $datasource_id_fallback;
            $datasource_unique_id = elgg_extract($datasource_id_fallback, $source_row);
            $user = profile_sync_find_user($profile_id_fallback, $datasource_unique_id, $sync_config, $counters);
        }
        // check if we need to create a user
        if (empty($user) && $create_user) {
            $pwd = generate_random_cleartext_password();
            try {
                // convert to utf-8
                $username = profile_sync_filter_var($source_row[$create_user_username]);
                $name = profile_sync_filter_var($source_row[$create_user_name]);
                $email = profile_sync_filter_var($source_row[$create_user_email]);
                $user_guid = register_user($username, $pwd, $name, $email);
                if (!empty($user_guid)) {
                    $counters['user created']++;
                    profile_sync_log($sync_config->getGUID(), "Created user: {$name}");
                    $user = get_user($user_guid);
                    if ($notify_user) {
                        $subject = elgg_echo('useradd:subject');
                        $body = elgg_echo('useradd:body', [$user->name, $site->name, $site->url, $user->username, $pwd]);
                        notify_user($user->getGUID(), $site->getGUID(), $subject, $body);
                    }
                }
            } catch (RegistrationException $r) {
                $name = profile_sync_filter_var($source_row[$create_user_name]);
                profile_sync_log($sync_config->getGUID(), "Failure creating user: {$name} - {$r->getMessage()}");
            }
        }
        // did we get a user
        if (empty($user)) {
            $counters['user not found']++;
            profile_sync_log($sync_config->getGUID(), "User not found: {$profile_used_id} => {$datasource_unique_id}");
            continue;
        } else {
            $counters['processed users']++;
        }
        // ban the user
        if ($ban_user) {
            // already banned?
            if (!$user->isBanned()) {
                $counters['user banned']++;
                $user->ban("Profile Sync: {$sync_config->title}");
                profile_sync_log($sync_config->getGUID(), "User banned: {$user->name} ({$user->username})");
            }
            continue;
        }
        // unban the user
        if ($unban_user) {
            // already banned?
            if ($user->isBanned()) {
                $counters['user unbanned']++;
                $user->unban();
                profile_sync_log($sync_config->getGUID(), "User unbanned: {$user->name} ({$user->username})");
            }
            continue;
        }
        // start of profile sync
        $special_sync_fields = ['name', 'username', 'email', 'user_icon_relative_path', 'user_icon_full_path'];
        foreach ($sync_match as $datasource_col => $profile_config) {
            list($datasource_col) = explode(PROFILE_SYNC_DATASOURCE_COL_SEPERATOR, $datasource_col);
            $profile_field = elgg_extract('profile_field', $profile_config);
            $access = (int) elgg_extract('access', $profile_config, $default_access);
            $override = (bool) elgg_extract('always_override', $profile_config, true);
            if (!in_array($profile_field, $special_sync_fields) && !array_key_exists($profile_field, $profile_fields)) {
                $counters['invalid profile field']++;
                continue;
            }
            if (!isset($source_row[$datasource_col])) {
                $counters['invalid source field']++;
                continue;
            }
            $value = elgg_extract($datasource_col, $source_row);
            $value = profile_sync_filter_var($value);
            switch ($profile_field) {
                case 'email':
                    if (!is_email_address($value)) {
                        continue 2;
                    }
                case 'username':
                    if ($override && $user->username !== $value) {
                        // new username, check for availability
                        if (get_user_by_username($value)) {
                            // already taken
                            profile_sync_log($sync_config->getGUID(), "New username: {$value} for {$user->name} is already taken");
                            continue 2;
                        }
                    }
                case 'name':
                    if (empty($value)) {
                        $counters['empty attributes']++;
                        profile_sync_log($sync_config->getGUID(), "Empty user attribute: {$datasource_col} for user {$user->name}");
                        continue 2;
                    }
                    if (isset($user->{$profile_field}) && !$override) {
                        // don't override profile field
                        // 						profile_sync_log($sync_config->getGUID(), "Profile field already set: {$profile_field} for user {$user->name}");
                        continue 2;
                    }
                    // check for the same value
                    if ($user->{$profile_field} === $value) {
                        // same value, no need to update
                        continue 2;
                    }
                    // save user attribute
                    $user->{$profile_field} = $value;
                    $user->save();
                    break;
                case 'user_icon_relative_path':
                    // get a user icon based on a relative file path/url
                    // only works with file based datasources (eg. csv)
                    if (!$sync_source instanceof ProfileSyncCSV) {
                        profile_sync_log($sync_config->getGUID(), "Can't fetch relative user icon path in non CSV datasouces: trying user {$user->name}");
                        continue 2;
                    }
                    // make new icon path
                    if (!empty($value)) {
                        $value = sanitise_filepath($value, false);
                        // prevent abuse (like ../../......)
                        $value = ltrim($value, DIRECTORY_SEPARATOR);
                        // remove beginning /
                        $value = $base_location . DIRECTORY_SEPARATOR . $value;
                        // concat base location and rel path
                    }
                case 'user_icon_full_path':
                    // get a user icon based on a full file path/url
                    if (!empty($user->icontime) && !$override) {
                        // don't override icon
                        // 						profile_sync_log($sync_config->getGUID(), "User already has an icon: {$user->name}");
                        continue 2;
                    }
                    // upload new icon
                    $icon_sizes = elgg_get_config('icon_sizes');
                    $fh = new ElggFile();
                    $fh->owner_guid = $user->getGUID();
                    if (empty($value) && $user->icontime) {
                        // no icon, so unset current icon
                        profile_sync_log($sync_config->getGUID(), "Removing icon for user: {$user->name}");
                        foreach ($icon_sizes as $size => $icon_info) {
                            $fh->setFilename("profile/{$user->getGUID()}{$size}.jpg");
                            $fh->delete();
                        }
                        unset($user->icontime);
                        unset($fh);
                        // on to the next field
                        continue 2;
                    }
                    // try to get the user icon
                    $icon_contents = file_get_contents($value);
                    if (empty($icon_contents)) {
                        profile_sync_log($sync_config->getGUID(), "Unable to fetch user icon: {$value} for user {$user->name}");
                        continue 2;
                    }
                    // was csv image updated
                    $csv_icontime = @filemtime($value);
                    if ($csv_icontime !== false && isset($user->icontime)) {
                        $csv_icontime = sanitise_int($csv_icontime);
                        $icontime = sanitise_int($user->icontime);
                        if ($csv_icontime === $icontime) {
                            // base image has same modified time as user icontime, so skipp
                            // 							profile_sync_log($sync_config->getGUID(), "No need to update user icon for user: {$user->name}");
                            continue 2;
                        }
                    }
                    if ($csv_icontime === false) {
                        $csv_icontime = time();
                    }
                    // write icon to a temp location for further handling
                    $tmp_icon = tempnam(sys_get_temp_dir(), $user->getGUID());
                    file_put_contents($tmp_icon, $icon_contents);
                    // resize icon
                    $icon_updated = false;
                    foreach ($icon_sizes as $size => $icon_info) {
                        $icon_contents = get_resized_image_from_existing_file($tmp_icon, $icon_info['w'], $icon_info['h'], $icon_info['square'], 0, 0, 0, 0, $icon_info['upscale']);
                        if (empty($icon_contents)) {
                            continue;
                        }
                        $fh->setFilename("profile/{$user->getGUID()}{$size}.jpg");
                        $fh->open('write');
                        $fh->write($icon_contents);
                        $fh->close();
                        $icon_updated = true;
                    }
                    // did we have a successfull icon upload?
                    if ($icon_updated) {
                        $user->icontime = $csv_icontime;
                    }
                    // cleanup
                    unlink($tmp_icon);
                    unset($fh);
                    break;
                default:
                    // check overrides
                    if (isset($user->{$profile_field}) && !$override) {
                        // don't override profile field
                        // 						profile_sync_log($sync_config->getGUID(), "Profile field already set: {$profile_field} for user {$user->name}");
                        continue 2;
                    }
                    // convert tags
                    if ($profile_fields[$profile_field] === 'tags') {
                        $value = string_to_tag_array($value);
                    }
                    // remove existing value
                    if (empty($value)) {
                        if (isset($user->{$profile_field})) {
                            unset($user->{$profile_field});
                        }
                        continue 2;
                    }
                    // check for the same value
                    if ($user->{$profile_field} === $value) {
                        // same value, no need to update
                        continue 2;
                    }
                    // 					profile_sync_log($sync_config->getGUID(), "Updating {$profile_field} with value {$value} old value {$user->$profile_field}");
                    // get the access of existing profile data
                    $access = profile_sync_get_profile_field_access($user->getGUID(), $profile_field, $access);
                    // save new value
                    $user->setMetadata($profile_field, $value, '', false, $user->getGUID(), $access);
                    break;
            }
        }
        // let others know we updated the user
        $update_event_params = ['entity' => $user, 'source_row' => $source_row, 'sync_config' => $sync_config, 'datasource' => $datasource];
        elgg_trigger_event('update_user', 'profile_sync', $update_event_params);
        // cache cleanup
        _elgg_services()->entityCache->remove($user->getGUID());
        $metadata_cache->clear($user->getGUID());
    }
    profile_sync_log($sync_config->getGUID(), PHP_EOL . 'End processing: ' . date(elgg_echo('friendlytime:date_format')) . PHP_EOL);
    foreach ($counters as $name => $count) {
        profile_sync_log($sync_config->getGUID(), "{$name}: {$count}");
    }
    // close logfile
    profile_sync_log($sync_config->getGUID(), null, true);
    // save last run
    $sync_config->lastrun = time();
    // cleanup datasource cache
    $sync_source->cleanup();
    // re-enable db caching
    _elgg_services()->db->enableQueryCache();
    // restore access
    elgg_set_ignore_access($ia);
    if ($metadata_cache instanceof ElggVolatileMetadataCache) {
        // elgg 1.10
        $metadata_cache->unsetIgnoreAccess();
    } elseif ($metadata_cache instanceof \Elgg\Cache\MetadataCache) {
        // elgg 1.11+
        $metadata_cache->clearAll();
    }
}