Skip to content
Snippets Groups Projects
user_visible.inc.php 17.4 KiB
Newer Older
<?php
# Lifter002: TODO
# Lifter007: TODO
# Lifter003: TEST
# Lifter010: TODO
/*
user_visible.inc.php - Functions for determining a users visibility
Copyright (C) 2004 Till Glöggler <virtuos@snowysoft.de>

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

// Define constants for visibility states.
define('VISIBILITY_ME', 1);
define('VISIBILITY_BUDDIES', 2);
define('VISIBILITY_DOMAIN', 3);
define('VISIBILITY_STUDIP', 4);
define('VISIBILITY_EXTERN', 5);

/*
 * A function to determine a users visibility
 *
 * @param   $user_id    user-id
 * @returns boolean true: user is visible, false: user is not visible
 */
function get_visibility_by_id ($user_id)
{
    if ($GLOBALS['perm']->have_perm('root')) {
        return true;
    }

    $query = "SELECT visible FROM auth_user_md5 WHERE user_id = ?";
    $statement = DBManager::get()->prepare($query);
    $statement->execute([$user_id]);
    $visible = $statement->fetchColumn();

    return get_visibility_by_state($visible, $user_id);
}

/*
 * A function to determine a users visibility
 *
 * @param   $username   username
 * @returns boolean true: user is visible, false: user is not visible
 */
function get_visibility_by_username($username)
{
    if ($GLOBALS['perm']->have_perm('root')) {
        return true;
    }

    $query = "SELECT visible, user_id FROM auth_user_md5 WHERE username = ?";
    $statement = DBManager::get()->prepare($query);
    $statement->execute([$username]);
    $temp = $statement->fetch(PDO::FETCH_ASSOC);

    return get_visibility_by_state($temp['visible'], $temp['user_id']);
}

/*
 * A function to determine, whether a given state means 'visible' or 'invisible'
 *
 * @param   $stat   ['global', 'always', 'yes', 'unknown', 'no', 'never']
 * @param   $user_id        id of user that should be checked
 * @returns boolean true: state means 'visible', false: state means 'invisible'
 */
function get_visibility_by_state ($state, $user_id) {
    // Globally visible, no need for futher checks.
    if ($state === 'global') {
        return true;
    }

    $user = User::findCurrent();
    $other_user = User::find($user_id);
    if (!$user || !$other_user) {
    $same_domain = UserDomain::checkUserVisibility(
        $other_user->domains,
    );

    switch ($state) {
        case 'yes':
        case 'always':
            return $same_domain;
        case 'unknown':
            return $same_domain && Config::get()->USER_VISIBILITY_UNKNOWN;
    }

    return false;
}

/*
 * This function returns a query-snip for selecting with current visibility rights
 * @returns string  returns a query string
 */
function get_vis_query($table_alias = 'auth_user_md5', $context = '') {
    global $auth, $perm;

    if ($GLOBALS['perm']->have_perm('root')) {
        return '1';
    }

    $query = "{$table_alias}.visible = 'global'";

    /*
     *  Check if the user has set own visibilities or if the system default
     *  should be used.
     */
    if ($context) {
        $context_default = (int) Config::get()->getValue(mb_strtoupper($context) . '_VISIBILITY_DEFAULT');
        $contextQuery = " AND (IFNULL(user_visibility.{$context}, {$context_default}) = 1
                               OR {$table_alias}.visible = 'always')";
    } else {
        $contextQuery = '';
    }

    $my_domains = UserDomain::getUserDomainsForUser($GLOBALS['user']->id);
    $restricted = count($my_domains) > 0;

    $my_domain_ids = [];
    foreach ($my_domains as $domain) {
        if (!$domain->restricted_access) {
            $restricted = false;
        } else {
            $my_domain_ids[] = $domain->id;
        }
    }

    if (!$restricted) {
        $query .= " OR (
                    (NOT EXISTS (
                     SELECT *
                     FROM user_userdomains
                     JOIN userdomains USING (userdomain_id)
                     WHERE user_id = {$table_alias}.user_id
                  ) OR EXISTS (
                      SELECT *
                      FROM user_userdomains
                      JOIN userdomains USING (userdomain_id)
                      WHERE user_id = {$table_alias}.user_id
                      AND restricted_access = 0
                  )
                  ";
    }
    if (count($my_domain_ids) > 0) {
        if ($restricted) {
            $query .= " OR ( ( ";
        } else {
            $query .= " OR  ";
        }
        $query .= " EXISTS (SELECT *
                     FROM user_userdomains
                     WHERE user_id = {$table_alias}.user_id
                       AND userdomain_id IN (" . DBManager::get()->quote($my_domain_ids) . ")
                   )
                   )";
    } else {
        $query .= " ) ";
    }


    $allowed = ['always', 'yes'];
    if (Config::get()->USER_VISIBILITY_UNKNOWN) {
        // users with visibility "unknown" are treated as visible
        $allowed[] = 'unknown';
    }
    $quoted = DBManager::get()->quote($allowed);
    $query .= " AND {$table_alias}.visible IN ({$quoted}) )";

    return "($query) $contextQuery";
}

function get_ext_vis_query($table_alias = 'aum') {
    $allowed = ['global', 'always', 'yes'];
    if (Config::get()->USER_VISIBILITY_UNKNOWN) {
        $allowed[] = 'unknown';
    }

    $quoted = DBManager::get()->quote($allowed);
    return "({$table_alias}.visible IN ({$quoted}))";
}

/*
 * A function to create a chooser for a users visibility
 *
 * @param   $vis    visibility-state
 * @returns string  gives back a string with the chooser
 */
function vis_chooser($vis, $new = false, $id = false) {
    if ($vis == '') {
        $vis = 'unknown';
    }
    $txt = [];
    $txt[] = sprintf('<select name="visible"%s>', $id ? 'id="' . htmlReady($id) . '"' : '');
    $txt[] = '<option value="unknown"'.(($new || $vis === "unknown") ? ' selected="selected"':'').'>'._("Standardeinstellung").'</option>';
    $txt[] = '<option value="global"'.($vis === "global" ? " selected" : "").'>'._("sichtbar für alle Nutzenden").'</option>';
    $txt[] = '<option value="yes"'.($vis === "yes" ? " selected" : "").'>'._("sichtbar für eigene Nutzerdomäne").'</option>';
    $txt[] = '<option value="no"'.($vis === "no" ? " selected" : "").'>'._("unsichtbar").'</option>';
    $txt[] = '<option value="always"'.($vis === "always" ? " selected" : "").'>'._("Sichtbarkeit erzwingen").'</option>';
    $txt[] = '<option value="never"'.($vis === "never" ? " selected" : "").'>'._("Unsichtbarkeit erzwingen").'</option>';
    $txt[] = '</select>';
    return implode("\n", $txt);
}

// Ask user with unknown visibility state directly after login
// whether they want to be visible or invisible
//
// ATTENTION: NOT USED IN STANDARD DISTRIBUTION.
// see header.php for further info on enabling this feature.
//
// DON'T USE UNMODIFIED TEXTS!
//
function first_decision($userid) {
    $vis_cmd = Request::option('vis_cmd');
    $vis_state = Request::option('vis_state');
    $user_language = getUserLanguagePath($userid);

    if ($vis_cmd == "apply" && ($vis_state == "global" || $vis_state == "yes" || $vis_state == "no")) {
        $query = "UPDATE auth_user_md5 SET visible = ? WHERE user_id = ?";
        $statement = DBManager::get()->prepare($query);
        $statement->execute([$vis_state, $userid]);
        return;
    }

    $query = "SELECT visible FROM auth_user_md5 WHERE user_id = ?";
    $statement = DBManager::get()->prepare($query);
    $statement->execute([$userid]);
    $visiblity = $statement->fetchColumn();

    if ($visiblity != 'unknown') {
        return;
    }

    PageLayout::setTitle(_('Bitte wählen Sie Ihren Sichtbarkeitsstatus aus!'));
    PageLayout::setTabNavigation(NULL);

    // avoid recursion when loading the header
    Config::get()->USER_VISIBILITY_CHECK = false;

    $template = $GLOBALS['template_factory']->open("../locale/$user_language/LC_HELP/visibility_decision.php");
    $template->set_layout('layouts/base.php');

    echo $template->render();
    page_close();
    die;
}


/**
 * Gets a user's visibility settings for special context. Valid contexts are
 * at the moment:
 * <ul>
 * <li><b>online</b>: Visibility in "Who is online" list</li>
 * <li><b>search</b>: Can the user be found via person search?</li>
 * <li><b>email</b>: Is user's email address shown?</li>
 * <li><b>homepage</b>: Visibility of all user homepage elements, stored as
 * JSON-serialized array</li>
 * </ul>
 *
 * @param string $user_id user ID to check
 * @param string $context local visibility in which context?
 * @param boolean $return_user_perm return not only visibility, but also
 * the user's global permission level
 * @return mixed Visibility flag or array with visibility and user permission
 * level.
 */
function get_local_visibility_by_id($user_id, $context, $return_user_perm=false) {
    global $NOT_HIDEABLE_FIELDS;

    $user = User::find($user_id);

    if (Visibility::allowExtendedSettings($user)) {
        $query = "SELECT u.`{$context}`
                  FROM auth_user_md5 AS a
                  LEFT JOIN user_visibility AS u USING (user_id)
                  WHERE user_id = ?";
        $statement = DBManager::get()->prepare($query);
        $statement->execute([$user_id]);
        $data = $statement->fetch(PDO::FETCH_ASSOC);
    } else {
        $data = [];
    }

    if ($context === 'homepage') {
        $settings = User_Visibility_Settings::findByUser_id($user_id);
        foreach ($settings as $setting) {
            if ($setting['category'] == 1) {
                $homepage_settings[$setting['identifier']] = $setting['state'];
            }
        }

        if ($homepage_settings) {
            $data[$context] = json_encode($homepage_settings);
        }
    }

    if (!isset($data[$context])) {
        $data[$context] = Config::get()->getValue(mb_strtoupper($context) . '_VISIBILITY_DEFAULT');
    }

    if (!isset($data[$context])) {
        // No valid context given.
        $result = false;
    } elseif (!Visibility::isFieldHideableForUser($context, $user)) {
        // Context may not be hidden per global config setting.
        $result = true;
    } elseif ($return_user_perm) {
        // Give also user's permission level.
        $result = [
            'perms' => $user->perms,
            $context => $data[$context]
        ];
    return $result;
}


/**
 * Checks whether an element of a user homepage is visible for another user.
 * We do not give an element name and look up its visibility setting in the
 * database, because that would generate many database requests for a single
 * user homepage. Instead, the homepage itself loads all element visibilities
 * and we only need to check if the given element visibility allows showing it
 * to the visiting user. We need not check for not hideable fields here,
 * because that is already done when loading the element visibilities.
 *
 * @param string $user_id ID of the user who wants to see the element
 * @param string $owner_id ID of the homepage owner
 * @param int $element_visibility visibility level of the element, one of
 * the constants VISIBILITY_ME, VISIBILITY_BUDDIES, VISIBILITY_DOMAIN,
 * VISIBILITY_STUDIP, VISIBILITY_EXTERN
 * @return boolean Is the element visible?
 */
function is_element_visible_for_user($user_id, $owner_id, $element_visibility) {
    $is_visible = false;
    if ($user_id == $owner_id) {
        $is_visible = true;
    // Deputies with homepage editing rights see the same as the owner
    } else if (Config::get()->DEPUTIES_ENABLE && Config::get()->DEPUTIES_DEFAULTENTRY_ENABLE && Config::get()->DEPUTIES_EDIT_ABOUT_ENABLE && Deputy::isDeputy($user_id, $owner_id, true)) {
        $is_visible = true;
    } else {
        // No element visibility given (user has not configured this element yet)
        // Set default visibility as element visibility
        if (!$element_visibility) {
            $element_visibility = get_default_homepage_visibility($owner_id);
        }
        // Check if the given element is visible according to its visibility.
        switch ($element_visibility) {
            case VISIBILITY_EXTERN:
                $is_visible = true;
                break;
            case VISIBILITY_STUDIP:
                if ($user_id != "nobody") {
                    $is_visible = true;
                }
                break;
            case VISIBILITY_DOMAIN:
                $user_domains = UserDomain::getUserDomainsForUser($user_id);
                $owner_domains = UserDomain::getUserDomainsForUser($owner_id);
                if ((count($user_domains) === 0 && count($owner_domains) === 0)
                    || array_intersect($user_domains, $owner_domains)) {
                    $is_visible = true;
                }
                break;
            case VISIBILITY_BUDDIES:
                if (Contact::CountBySQL("user_id=? AND owner_id=?", [$user_id, $owner_id])) {
                    $is_visible = true;
                }
                break;
            case VISIBILITY_ME:
                if ($owner_id == $user_id) {
                    $is_visible = true;
                }
                break;
        }
    }
    return $is_visible;
}

/**
 * Checks whether a homepage element is visible on external pages.
 * We do not give an element name and look up its visibility setting in the
 * database, because that would generate many database requests for a single
 * user homepage. Instead, the homepage itself loads all element visibilities
 * and we only need to check if the given element visibility allows showing it.
 *
 * @param string $owner_id user ID of the homepage owner
 * @param string $owner_perm permission level of the homepage owner, needed
 * because every permission level can have its own not hideable fields.
 * @param string $field_name Name of the homepage field to check, needed for
 * checking if the element is not hideable
 * @param int $element_visibility visibility level of the element, one of
 * the constants VISIBILITY_ME, VISIBILITY_BUDDIES, VISIBILITY_DOMAIN,
 * VISIBILITY_STUDIP, VISIBILITY_EXTERN
 * @return boolean May the element be shown on external pages?
 */
function is_element_visible_externally($owner_id, $owner_perm, $field_name, $element_visibility) {
    global $NOT_HIDEABLE_FIELDS;
    $is_visible = false;
    if (!isset($element_visibility)) {
        $element_visibility = get_default_homepage_visibility($owner_id);
    }
    if ($element_visibility == VISIBILITY_EXTERN || $NOT_HIDEABLE_FIELDS[$owner_perm][$field_name])
        $is_visible = true;
    return $is_visible;
}

/**
 * Retrieves the standard visibility level for a homepage element if the user
 * hasn't specified anything explicitly. This default can be set via the global
 * configuration (variable "HOMEPAGE_VISIBILITY_DEFAULT").
 *
 * @return int Default visibility level.
 */
function get_default_homepage_visibility($user_id)
{
    $query = "SELECT default_homepage_visibility FROM user_visibility WHERE user_id = ?";
    $statement = DBManager::get()->prepare($query);
    $statement->execute([$user_id]);
    $visibility = $statement->fetchColumn();

    if (intval($visibility) != 0) {
        $result = $visibility;
    } else {
        $result = @constant(Config::get()->HOMEPAGE_VISIBILITY_DEFAULT);
        if (!$result) {
            $result = VISIBILITY_STUDIP;
        }
    }
    return $result;
}

/**
 * Gets a user's email address. If the address should not be shown according
 * to the user's privacy settings, we try to get the email address of the
 * default institute (this can be one of the institutes the user is assigned
 * to). If no default institute is found, the email address of the first found
 * institute is given. If the user isn't assigned to any institute, an empty
 * string is returned.
 *
 * @param string $user_id which user's email address is required?
 * @return string User email address or email address of the user's default
 * institute or empty string.
 */
function get_visible_email($user_id) {
    $result = '';
    // Email address is visible -> just show user's address.
    if (get_local_visibility_by_id($user_id, 'email')) {
        $query = "SELECT Email FROM auth_user_md5 WHERE user_id = ?";
        $statement = DBManager::get()->prepare($query);
        $statement->execute([$user_id]);
        $result = $statement->fetchColumn();
    // User's email is not visible
    } else if ($GLOBALS['perm']->get_perm($user_id) == 'dozent') {
        // bei Lehrenden eine Institutsadresse verwenden
        $query = "SELECT i.email, u.externdefault
                  FROM user_inst AS u
                  JOIN Institute AS i USING (Institut_id)
                  WHERE u.user_id = ? AND u.inst_perms != 'user'
                  ORDER BY u.priority";
        $statement = DBManager::get()->prepare($query);
        $statement->execute([$user_id]);

        while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
            if (!$result || $row['externdefault']) {
                $result = $row['email'];
            }
        }
    }
    return $result;
}