Skip to content
Snippets Groups Projects
Select Git revision
  • 5d0a8269e33be98f270253013eda7b05d477edd5
  • main default protected
  • studip-rector
  • ci-opt
  • course-members-export-as-word
  • data-vue-app
  • pipeline-improvements
  • webpack-optimizations
  • rector
  • icon-renewal
  • http-client-and-factories
  • jsonapi-atomic-operations
  • vueify-messages
  • tic-2341
  • 135-translatable-study-areas
  • extensible-sorm-action-parameters
  • sorm-configuration-trait
  • jsonapi-mvv-routes
  • docblocks-for-magic-methods
19 results

oauth.php

Blame
  • Forked from Stud.IP / Stud.IP
    Source project has a limited visibility.
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    User.class.php 56.66 KiB
    <?php
    /**
     * User.class.php
     * model class for combined auth_user_md5/user_info record
     * this class represents one user, the attributes from tables
     * auth_user_md5 and user_info were merged.
     *
     * @code
     * $a_user = User::find($id);
     * $another_users_email = User::findByUsername($username)->email;
     * $a_user->email = $another_users_email;
     * $a_user->store();
     * @endcode
     *
     * 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.
     *
     * @author      André Noack <noack@data-quest.de>
     * @copyright   2011 Stud.IP Core-Group
     * @license     http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
     * @category    Stud.IP
     *
     * @property string user_id database column
     * @property string id alias column for user_id
     * @property string username database column
     * @property string password database column
     * @property string perms database column
     * @property string vorname database column
     * @property string nachname database column
     * @property string email database column
     * @property string validation_key database column
     * @property string auth_plugin database column
     * @property string locked database column
     * @property string lock_comment database column
     * @property string locked_by database column
     * @property string visible database column
     * @property string hobby computed column read/write
     * @property string lebenslauf computed column read/write
     * @property string publi computed column read/write
     * @property string schwerp computed column read/write
     * @property string home computed column read/write
     * @property string privatnr computed column read/write
     * @property string privatcell computed column read/write
     * @property string privadr computed column read/write
     * @property string score computed column read/write
     * @property string geschlecht computed column read/write
     * @property string mkdate computed column read/write
     * @property string chdate computed column read/write
     * @property string title_front computed column read/write
     * @property string title_rear computed column read/write
     * @property string preferred_language computed column read/write
     * @property string smsforward_copy computed column read/write
     * @property string smsforward_rec computed column read/write
     * @property string guestbook computed column read/write
     * @property string email_forward computed column read/write
     * @property string smiley_favorite computed column read/write
     * @property string motto computed column read/write
     * @property string lock_rule computed column read/write
     * @property SimpleORMapCollection course_memberships has_many CourseMember
     * @property SimpleORMapCollection institute_memberships has_many InstituteMember
     * @property SimpleORMapCollection admission_applications has_many AdmissionApplication
     * @property SimpleORMapCollection archived_course_memberships has_many ArchivedCourseMember
     * @property SimpleORMapCollection datafields has_many DatafieldEntryModel
     * @property SimpleORMapCollection studycourses has_many UserStudyCourse
     * @property SimpleORMapCollection contacts has_many Contact
     * @property UserInfo   info   has_one UserInfo
     * @property UserOnline online has_one UserOnline
     * @property Kategorie[]|SimpleORMapCollection $profile_categories has_many Kategorie
     *
     * @property UserConfig config
     */
    class User extends AuthUserMd5 implements Range, PrivacyObject
    {
        /**
         *
         */
        protected static function configure($config = [])
        {
            $config['has_many']['course_memberships'] = [
                'class_name' => CourseMember::class,
                'on_delete'  => 'delete',
                'on_store'   => 'store',
            ];
            $config['has_many']['institute_memberships'] = [
                'class_name' => InstituteMember::class,
                'order_by'   => 'ORDER BY priority ASC',
                'on_delete'  => 'delete',
                'on_store'   => 'store',
            ];
            $config['has_many']['admission_applications'] = [
                'class_name' => AdmissionApplication::class,
                'on_delete'  => 'delete',
                'on_store'   => 'store',
            ];
            $config['has_many']['archived_course_memberships'] = [
                'class_name' => ArchivedCourseMember::class,
                'on_delete'  => 'delete',
                'on_store'   => 'store',
            ];
            $config['has_many']['datafields'] = [
                'class_name'  => DatafieldEntryModel::class,
                'foreign_key' => function ($user) {
                    return [$user];
                },
                'assoc_foreign_key' => function ($model, $params) {
                    $model->setValue('range_id', $params[0]->id);
                },
                'assoc_func' => 'findByModel',
                'on_delete'  => 'delete',
                'on_store'   => 'store',
            ];
            $config['has_many']['studycourses'] = [
                'class_name' => UserStudyCourse::class,
                'assoc_func' => 'findByUser',
                'on_delete'  => 'delete',
                'on_store'   => 'store',
            ];
            $config['has_and_belongs_to_many']['contacts'] = [
                'class_name'     => User::class,
                'thru_table'     => 'contact',
                'thru_key'       => 'owner_id',
                'thru_assoc_key' => 'user_id',
                'order_by'       => 'ORDER BY Nachname, Vorname',
                'on_delete'      => 'delete',
                'on_store'       => 'store',
            ];
            $config['has_many']['contactgroups'] = [
                'class_name'        => Statusgruppen::class,
                'assoc_foreign_key' => 'range_id',
                'on_delete'         => 'delete',
                'on_store'          => 'store',
            ];
            $config['has_one']['info'] = [
                'class_name' => UserInfo::class,
                'on_delete'  => 'delete',
                'on_store'   => 'store',
            ];
            $config['has_one']['online'] = [
                'class_name' => UserOnline::class,
                'on_delete'  => 'delete',
                'on_store'   => 'store',
            ];
            $config['has_many']['resource_permissions'] = [
                'class_name' => ResourcePermission::class,
                'on_delete'  => 'delete',
                'on_store'   => 'store'
            ];
            $config['has_many']['resource_temporary_permissions'] = [
                'class_name' => ResourceTemporaryPermission::class,
                'on_delete'  => 'delete',
                'on_store'   => 'store'
            ];
            $config['has_many']['consultation_blocks'] = [
                'class_name'        => ConsultationBlock::class,
                'assoc_foreign_key' => 'range_id',
                'on_delete'         => 'delete',
            ];
            $config['has_many']['consultation_bookings'] = [
                'class_name' => ConsultationBooking::class,
                'on_delete'  => 'delete',
            ];
            $config['has_many']['profile_categories'] = [
                'class_name'        => Kategorie::class,
                'assoc_foreign_key' => 'range_id',
                'on_delete'         => 'delete',
            ];
    
    
            $config['has_many']['mvv_assignments'] = [
                'class_name'        => MvvContact::class,
                'assoc_foreign_key' => 'contact_id',
                'on_delete'         => 'delete'
            ];
    
            $config['has_and_belongs_to_many']['domains'] = [
                'class_name'        => UserDomain::class,
                'thru_table'        => 'user_userdomains',
                'on_delete'         => 'delete',
                'on_store'          => 'store',
                'order_by'          => 'ORDER BY name',
            ];
    
            $config['has_one']['courseware'] = [
                'class_name' => \Courseware\StructuralElement::class,
                'assoc_func' => 'getCoursewareUser'
            ];
    
            $config['has_many']['course_notifications'] = [
                'class_name'        => CourseMemberNotification::class,
                'on_delete'         => 'delete',
            ];
    
            $config['additional_fields']['config']['get'] = function ($user) {
                return UserConfig::get($user->id);
            };
    
            $config['registered_callbacks']['after_delete'][] = 'cbRemoveFeedback';
            $config['registered_callbacks']['before_store'][] = 'cbClearCaches';
    
            $info = new UserInfo();
            $info_meta = $info->getTableMetadata();
            foreach ($info_meta ['fields'] as $field => $meta) {
                if ($field !== $info_meta['pk'][0]) {
                    $config['additional_fields'][$field] = [
                        'get'            => '_getAdditionalValueFromRelation',
                        'set'            => '_setAdditionalValueFromRelation',
                        'relation'       => 'info',
                        'relation_field' => $field,
                    ];
                }
            }
    
            parent::configure($config);
        }
    
        /**
         * Returns the currently authenticated user.
         *
         * @return ?User User
         */
        public static function findCurrent()
        {
            if (is_object($GLOBALS['user'])) {
                return $GLOBALS['user']->getAuthenticatedUser();
            }
    
            return null;
        }
    
        /**
         * build new object with given data
         *
         * @param $data array assoc array of record
         * @return User
         */
        public static function build($data, $is_new = true)
        {
            $user = new User();
            $user->info = new UserInfo();
            $user->setData($data);
            $user->setNew($is_new);
            foreach (array_keys($user->db_fields()) as $field) {
                $user->content_db[$field] = $user->content[$field];
            }
            $user->info = UserInfo::build($data, $is_new);
            return $user;
        }
    
        /**
         * Returns user object including user_info
         *
         * @param string $id
         * @return ?User User
         */
        public static function findFull($id)
        {
            $sql = "SELECT *
                    FROM auth_user_md5
                    LEFT JOIN user_info USING (user_id)
                    WHERE user_id = ?";
            $data = DBManager::get()->fetchOne($sql, [$id]);
            if ($data) {
                return self::buildExisting($data);
            }
    
            return null;
        }
    
        /**
         * Returns user objects including user_info
         *
         * @param array $ids
         * @param string $order_by
         * @return User[] User
         */
        public static function findFullMany($ids, $order_by = '')
        {
            $sql = "SELECT *
                    FROM auth_user_md5
                    LEFT JOIN user_info USING (user_id)
                    WHERE user_id IN (?) " . $order_by;
            $data = DBManager::get()->fetchAll($sql, [$ids], 'User::buildExisting');
            return $data;
        }
    
        /**
         * return user object for given username
         *
         * @param string $username a username
         * @return User
         */
        public static function findByUsername($username)
        {
            return parent::findOneByUsername($username);
        }
    
        /**
         * returns an array of User-objects that have the given value in the
         * given datafield.
         * @param string $datafield_id
         * @param array of User
         */
        public static function findByDatafield($datafield_id, $value)
        {
            return User::findMany(
                array_column(
                    DatafieldEntryModel::findBySQL(
                        'datafield_id = :datafield_id AND content = :value',
                        compact('datafield_id', 'value')
                    ),
                    'range_id')
            );
        }
    
        /**
         * Wraps a search parameter in %..% if the parameter itself does not
         * contain % or _.
         *
         * @param String $needle Search parameter
         * @return String containing the wrapped needle if neccessary
         */
        private static function searchParam($needle)
        {
            if (preg_match('/[%_]/S', $needle)) {
                return $needle;
            }
    
            return '%' . $needle . '%';
        }
    
        /**
         * Temporary migrate to User.class.php
         *
         * @param $attributes
         * @return array
         */
        public static function search($attributes)
        {
            $params = [];
            $joins  = [];
            $where  = [];
    
            $query = "SELECT au.*, ui.*
                      FROM `auth_user_md5` au
                      LEFT JOIN `user_online` uo ON (au.`user_id` = uo.`user_id`)
                      LEFT JOIN `user_info` ui ON (au.`user_id` = ui.`user_id`)";
    
            if (!empty($attributes['username'])) {
                $where[] =  "au.`username` like :username";
                $params[':username'] = self::searchParam($attributes['username']);
            }
    
            if (!empty($attributes['vorname'])) {
                $where[] = "au.`Vorname` LIKE :vorname";
                $params[':vorname'] = self::searchParam($attributes['vorname']);
            }
    
            if (!empty($attributes['nachname'])) {
                $where[] = "au.`Nachname` LIKE :nachname";
                $params[':nachname'] = self::searchParam($attributes['nachname']);
            }
    
            if (!empty($attributes['email'])) {
                $where[] = "au.`Email` LIKE :email";
                $params[':email'] = self::searchParam($attributes['email']);
            }
    
            //permissions
            if (!is_null($attributes['perm']) && $attributes['perm'] != 'alle') {
                $where[] = "au.`perms` = :perms";
                $params[':perms'] = $attributes['perm'];
            }
    
            //locked user
            if (!empty($attributes['locked'])) {
                $where[] = "au.`locked` = 1";
            }
    
            // show only users who are not lecturers
            if (!empty($attributes['show_only_not_lectures'])) {
                $where[] = "au.`user_id` NOT IN (SELECT `user_id` FROM `seminar_user` WHERE `status` = 'dozent') ";
            }
    
            if (!empty($attributes['auth_plugins'])) {
                $where[] = "IFNULL(`auth_plugin`, 'preliminary') = :auth_plugins ";
                $params[':auth_plugins'] = $attributes['auth_plugins'];
            }
    
            //inactivity
            if (!is_null($attributes['inaktiv']) && $attributes['inaktiv'][0] != 'nie') {
                $comp = in_array(trim($attributes['inaktiv'][0]), ['=', '>', '<=']) ? $attributes['inaktiv'][0] : '=';
                $days = (int)$attributes['inaktiv'][1];
                $where[] = "uo.`last_lifesign` {$comp} UNIX_TIMESTAMP(TIMESTAMPADD(DAY, -{$days}, NOW())) ";
            } elseif (!is_null($attributes['inaktiv'])) {
                $where[] = "uo.`last_lifesign` IS NULL";
            }
    
            //datafields
            if (!is_null($attributes['datafields']) && count($attributes['datafields']) > 0) {
                $joins[] = "LEFT JOIN `datafields_entries` de ON (de.`range_id` = au.`user_id`)";
                foreach ($attributes['datafields'] as $id => $entry) {
                    $where[] = "de.`datafield_id` = :df_id_". $id;
                    $where[] = "de.`content` LIKE :df_content_". $id;
                    $params[':df_id_' . $id] = $id;
                    $params[':df_content_' . $id] = $entry;
                }
            }
    
            // roles
            if (!empty($attributes['roles'])) {
                $joins[] = "LEFT JOIN `roles_user` ON roles_user.`userid` = au.`user_id`";
                $where[] = "roles_user.`roleid` IN (:roles)";
                $params[':roles'] = $attributes['roles'];
            }
    
            // userdomains
            if (!empty($attributes['userdomains'])) {
                $joins[] = "LEFT JOIN `user_userdomains` uud ON (au.`user_id` = uud.`user_id`)";
                $joins[] = "LEFT JOIN `userdomains` uds USING (`userdomain_id`)";
                if ($attributes['userdomains'] === 'null-domain') {
                    $where[] = "`userdomain_id` IS NULL ";
                } else {
                    $where[] = "userdomain_id = :userdomains";
                    $params[':userdomains'] = $attributes['userdomains'];
                }
            }
    
            // degree or studycourse
            if (!empty($attributes['degree']) || !empty($attributes['studycourse']) || !empty($attributes['fachsem'])) {
                $joins[] = "LEFT JOIN `user_studiengang` us ON (us.`user_id` = au.`user_id`)";
                if (!empty($attributes['degree'])) {
                    $where[] = "us.`abschluss_id` IN (:degree)";
                    $params[':degree'] = $attributes['degree'];
                }
    
                if (!empty($attributes['studycourse'])) {
                    $where[] = "us.`fach_id` IN (:studycourse)";
                    $params[':studycourse'] = $attributes['studycourse'];
                }
    
                if(!empty($attributes['fachsem'])) {
                    $where[] = 'us.`semester` = :fachsem';
                    $params[':fachsem'] = $attributes['fachsem'];
                }
            }
    
            if ($attributes['institute']) {
                $joins[] = "LEFT JOIN `user_inst` uis ON uis.`user_id` = au.`user_id`";
                $where[] = "uis.`Institut_id` = :institute";
                $params[':institute'] = $attributes['institute'];
            }
    
            $query .= implode(' ', $joins);
            $query .= " WHERE 1 AND ";
            $query .= implode(' AND ', $where);
            $query .= " GROUP BY au.`user_id` ";
    
            if (!empty($attributes['sortby'])) {
                //sortieren
                switch ($attributes['sortby']) {
                    case "perms":
                        $query .= "ORDER BY au.`perms` {$attributes['order']}, au.`username`";
                        break;
                    case "Vorname":
                        $query .= "ORDER BY au.`Vorname` {$attributes['order']}, au.`Nachname`";
                        break;
                    case "Nachname":
                        $query .= "ORDER BY au.`Nachname` {$attributes['order']}, au.`Vorname`";
                        break;
                    case "Email":
                        $query .= "ORDER BY au.`Email` {$attributes['order']}, au.`username`";
                        break;
                    case "changed":
                        $query .= "ORDER BY uo.`last_lifesign` {$attributes['order']}, au.`username`";
                        break;
                    case "mkdate":
                        $query .= "ORDER BY ui.`mkdate` {$attributes['order']}, au.`username`";
                        break;
                    case "auth_plugin":
                        $query .= "ORDER BY `auth_plugin` {$attributes['order']}, au.`username`";
                        break;
                    default:
                        $query .= " ORDER BY au.`username` {$attributes['order']}";
                }
            }
    
            return DBManager::get()->fetchAll($query, $params, __CLASS__ . '::buildExisting');
        }
    
    
        /**
         * @see SimpleORMap::store()
         */
        public function store()
        {
            if ($this->isDirty() && !$this->info->isFieldDirty('chdate')) {
                $this->info->setValue('chdate', time());
            }
            return parent::store();
        }
    
        /**
         * @see SimpleORMap::triggerChdate()
         */
        public function triggerChdate()
        {
           return $this->info->triggerChdate();
        }
    
        /**
         * returns the name in specified format
         * (formats defined in $GLOBALS['_fullname_sql'])
         *
         * @param string one of full,full_rev,no_title,no_title_rev,no_title_short,no_title_motto,full_rev_username
         * @return string guess what - the fullname
         */
        public function getFullName($format = 'default')
        {
            static $concat,$left,$if,$quote;
    
            if ($format === 'default') {
                $format = 'full';
            }
    
            $sql = $GLOBALS['_fullname_sql'][$format] ?? null;
            if (!$sql || $format == 'no_title') {
                return $this->vorname . ' ' . $this->nachname;
            }
            if ($format == 'no_title_rev') {
                return $this->nachname . ', ' . $this->vorname;
            }
            if ($concat === null) {
                $concat = function() {return join('', func_get_args());};
                $left = function($str, $c = 0) {return mb_substr($str,0,$c);};
                $if = function($ok,$yes,$no) {return $ok ? $yes : $no;};
                $quote = function($str) {return "'" . addcslashes($str, "\\'\0") . "'";};
            }
    
            $data = array_map($quote, $this->toArray('vorname nachname username title_front title_rear motto perms'));
            $replace_func['CONCAT'] = '$concat';
            $replace_func['LEFT'] = '$left';
            $replace_func['UCASE'] = 'mb_strtoupper';
            $replace_func['IF'] = '$if';
            $eval = strtr($sql, $replace_func);
            $eval = strtr(mb_strtolower($eval), $data);
            return eval('return ' . $eval . ';');
        }
    
        public function toArrayRecursive($only_these_fields = null)
        {
            $ret = parent::toArrayRecursive($only_these_fields);
            unset($ret['info']);
            return  $ret;
        }
    
        /**
         * Returns whether the user was assigned a certain role.
         *
         * @param string $role         The role to check
         * @param string $institute_id An optional institute_id
         * @return bool True if the user was assigned this role, false otherwise
         */
        public function hasRole($role, $institute_id = '')
        {
            return RolePersistence::isAssignedRole($this->user_id, $role, $institute_id);
        }
    
        /**
         * Returns the roles that were assigned to the user.
         *
         * @param boolean $with_implicit
         * @return array
         */
        public function getRoles($with_implicit = false)
        {
            return RolePersistence::getAssignedRoles($this->user_id, $with_implicit);
        }
    
        /**
         * Returns whether the given user is stored in contacts.
         *
         * @param User $another_user
         * @return bool
         */
        public function isFriendOf($another_user)
        {
            return (bool) DBManager::get()->fetchColumn("SELECT 1 FROM contact WHERE owner_id=? AND user_id=?", [$this->user_id, $another_user->user_id]);
        }
    
        /**
         * checks if at least one field was modified since last restore
         *
         * @return boolean
         */
        public function isDirty()
        {
            return parent::isDirty() || $this->info->isDirty();
        }
    
        /**
         * checks if given field was modified since last restore
         *
         * @param string $field
         * @return boolean
         */
        public function isFieldDirty($field)
        {
            $field = mb_strtolower($field);
            return (array_key_exists($field, $this->content_db) ? parent::isFieldDirty($field) : $this->info->isFieldDirty($field));
        }
    
        /**
         * reverts value of given field to last restored value
         *
         * @param string $field
         * @return mixed the restored value
         */
        public function revertValue($field)
        {
            $field = mb_strtolower($field);
            return (array_key_exists($field, $this->content_db) ? parent::revertValue($field) : $this->info->revertValue($field));
        }
    
        /**
         * returns unmodified value of given field
         *
         * @param string $field
         * @throws InvalidArgumentException
         * @return mixed
         */
        public function getPristineValue($field)
        {
            $field = mb_strtolower($field);
            return (array_key_exists($field, $this->content_db) ? parent::getPristineValue($field) : $this->info->getPristineValue($field));
        }
    
        /**
         * Returns data of table row as assoc array with raw contents like
         * they are in the database.
         * Pass array of fieldnames or ws separated string to limit
         * fields.
         *
         * @param mixed $only_these_fields
         * @return array
         */
        public function toRawArray($only_these_fields = null)
        {
            return array_merge($this->info->toRawArray($only_these_fields), parent::toRawArray($only_these_fields));
        }
    
        /**
         * @param string $relation
         */
        public function initRelation($relation)
        {
            parent::initRelation($relation);
            if ($relation == 'info' && is_null($this->relations['info'])) {
                $options = $this->getRelationOptions($relation);
                $result = new $options['class_name'];
                $foreign_key_value = call_user_func($options['assoc_func_params_func'], $this);
                call_user_func($options['assoc_foreign_key_setter'], $result, $foreign_key_value);
                $this->relations[$relation] = $result;
            }
        }
    
        /**
         * This function returns the perms allowed for an institute for the current user
         *
         * @return array list of perms
         */
        public function getInstitutePerms()
        {
            if($this->perms === 'admin') {
                return ['admin'];
            }
            $allowed_status = [];
            $possible_status = ['autor', 'tutor', 'dozent'];
    
            $pos = array_search($this->perms, $possible_status);
    
            if ($pos !== false) {
                $allowed_status = array_slice($possible_status, 0, $pos + 1);
            }
            return $allowed_status;
        }
    
        /**
         * Get the decorated StudIP-Kings information
         * @return String
         */
        public function getStudipKingIcon()
        {
            $is_king = StudipKing::is_king($this->user_id, TRUE);
    
            $result = '';
            foreach ($is_king as $type => $text) {
                $type = str_replace('_', '-', $type);
                $result .= Assets::img('crowns/crown-' . $type . '.png', ['alt' => $text, 'title' => $text]);
            }
    
            return $result ?: null;
        }
    
        /**
         * Builds an array containing all available elements that are part of a
         * user's homepage together with their visibility. It isn't sufficient to
         * just load the visibility settings from database, because if the user
         * has added some data (e.g. CV) but not yet assigned a special visibility
         * to that field, it wouldn't show up.
         *
         * @return array An array containing all available homepage elements
         * together with their visibility settings in the form
         * $name => $visibility.
         */
        public function getHomepageElements()
        {
            $homepage_visibility = get_local_visibility_by_id($this->id, 'homepage');
            if (is_array(json_decode($homepage_visibility, true))) {
                $homepage_visibility = json_decode($homepage_visibility, true);
            } else {
                $homepage_visibility = [];
            }
    
            // News
            $news = StudipNews::GetNewsByRange($this->id, true);
    
            // Non-private dates.
            if (Config::get()->CALENDAR_ENABLE) {
                $dates = CalendarEvent::countBySql('range_id = ?', [$this->id]);
            } else {
                $dates = [];
            }
    
            // Votes
            if (Config::get()->VOTE_ENABLE) {
                $activeVotes  = Questionnaire::countBySQL("user_id = ? AND visible = '1'", [$this->id]);
                $stoppedVotes = Questionnaire::countBySQL("user_id = ? AND visible = '0'", [$this->id]);
            }
            // Evaluations
            $evalDB = new EvaluationDB();
            $activeEvals = $evalDB->getEvaluationIDs($this->id, EVAL_STATE_ACTIVE);
            // Free datafields
            $data_fields = DataFieldEntry::getDataFieldEntries($this->id, 'user');
    
            // Now join all available elements with visibility settings.
            $homepage_elements = [];
    
            if (Avatar::getAvatar($this->id)->is_customized() && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['picture'])) {
                $homepage_elements['picture'] = [
                    'name'        => _('Eigenes Bild'),
                    'visibility'  => $homepage_visibility['picture'] ?? get_default_homepage_visibility($this->id),
                    'extern'      => true,
                    'identifier'  => 'commondata'
                ];
            }
    
            if ($this->info->motto && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['motto'])) {
                $homepage_elements['motto'] = [
                    'name'       => _('Motto'),
                    'visibility' => $homepage_visibility['motto']?? get_default_homepage_visibility($this->id),
                    'identifier' => 'privatedata'
                ];
            }
            if (Config::get()->ENABLE_SKYPE_INFO) {
                if ($GLOBALS['user']->cfg->getValue('SKYPE_NAME') && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['skype_name'])) {
                    $homepage_elements['skype_name'] = [
                        'name'       => _('Skype Name'),
                        'visibility' => $homepage_visibility['skype_name']?? get_default_homepage_visibility($this->id),
                        'identifier' => 'privatedata'
                    ];
                }
            }
            if ($this->info->privatnr && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['Private Daten_phone'])) {
                $homepage_elements['private_phone'] = [
                    'name'       => _('Private Telefonnummer'),
                    'visibility' => $homepage_visibility['private_phone']?? get_default_homepage_visibility($this->id),
                    'identifier' => 'privatedata'
                ];
            }
            if ($this->info->privatcell && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['private_cell'])) {
                $homepage_elements['private_cell'] = [
                    'name'       => _('Private Handynummer'),
                    'visibility' => $homepage_visibility['private_cell']?? get_default_homepage_visibility($this->id),
                    'identifier' => 'privatedata'
                ];
            }
            if ($this->info->privadr && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['privadr'])) {
                $homepage_elements['privadr'] = [
                    'name'         => _('Private Adresse'),
                    'visibility'   => $homepage_visibility['privadr']?? get_default_homepage_visibility($this->id),
                    'identifier'   => 'privatedata'
                ];
            }
            if ($this->info->home && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['homepage'])) {
                $homepage_elements['homepage'] = [
                    'name'        => _('Homepage-Adresse'),
                    'visibility'  => $homepage_visibility['homepage']?? get_default_homepage_visibility($this->id),
                    'extern'      => true,
                    'identifier'  => 'privatedata'
                ];
            }
            if ($news && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['news'])) {
                $homepage_elements['news'] = [
                    'name'       => _('Ankündigungen'),
                    'visibility' => $homepage_visibility['news']?? get_default_homepage_visibility($this->id),
                    'extern'     => true,
                    'identifier' => 'commondata'
                ];
            }
            if (Config::get()->CALENDAR_ENABLE && $dates && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['dates'])) {
                $homepage_elements['termine'] = [
                    'name'       => _('Termine'),
                    'visibility' => $homepage_visibility['termine']?? get_default_homepage_visibility($this->id),
                    'extern'     => true,
                    'identifier' => 'commondata'
                ];
            }
            if (Config::get()->VOTE_ENABLE && ($activeVotes || $stoppedVotes || $activeEvals) && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['votes'])) {
                $homepage_elements['votes'] = [
                    'name'       => _('Fragebögen'),
                    'visibility' => $homepage_visibility['votes']?? get_default_homepage_visibility($this->id),
                    'identifier' => 'commondata'
                ];
            }
    
            $query = "SELECT 1
                      FROM user_inst
                      LEFT JOIN Institute USING (Institut_id)
                      WHERE user_id = ? AND inst_perms = 'user'";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$this->id]);
            if ($statement->fetchColumn() && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['studying'])) {
                $homepage_elements['studying'] = [
                    'name'       => _('Wo ich studiere'),
                    'visibility' => $homepage_visibility['studying'] ?: get_default_homepage_visibility($this->id),
                    'identifier' => 'studdata'
                ];
            }
            if ($this->info->lebenslauf && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['lebenslauf'])) {
                $homepage_elements['lebenslauf'] = [
                    'name'       => _('Lebenslauf'),
                    'visibility' => $homepage_visibility['lebenslauf'] ?: get_default_homepage_visibility($this->id),
                    'extern'     => true,
                    'identifier' => 'privatedata'
                ];
            }
            if ($this->info->hobby && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['hobby'])) {
                $homepage_elements['hobby'] = [
                    'name'       => _('Hobbys'),
                    'visibility' => $homepage_visibility['hobby'] ?: get_default_homepage_visibility($this->id),
                    'identifier' => 'privatedata'
                ];
            }
            if ($this->info->publi && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['publi'])) {
                $homepage_elements['publi'] = [
                    'name'       => _('Publikationen'),
                    'visibility' => $homepage_visibility['publi'] ?: get_default_homepage_visibility($this->id),
                    'extern'     => true,
                    'identifier' => 'privatedata'
                ];
            }
            if ($this->info->schwerp && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms]['schwerp'])) {
                $homepage_elements['schwerp'] = [
                    'name'       => _('Arbeitsschwerpunkte'),
                    'visibility' => $homepage_visibility['schwerp'] ?: get_default_homepage_visibility($this->id),
                    'extern'     => true,
                    'identifier' => 'privatedata'
                ];
            }
    
            if ($data_fields) {
                foreach ($data_fields as $key => $field) {
                    if ($field->getValue() && $field->isEditable($this->perms) && empty($GLOBALS['NOT_HIDEABLE_FIELDS'][$this->perms][$key])) {
                        $homepage_elements[$key] = [
                            'name'       => $field->getName(),
                            'visibility' => $homepage_visibility[$key] ?: get_default_homepage_visibility($this->id),
                            'extern'     => true,
                            'identifier' => 'additionaldata'
                        ];
                    }
                }
            }
    
            foreach ($this->profile_categories as $category) {
                $homepage_elements['kat_' . $category->id] = [
                    'name'       => $category->name,
                    'visibility' => $homepage_visibility['kat_' . $category->id] ?: get_default_homepage_visibility($this->id),
                    'extern'     => true,
                    'identifier' => 'owncategory'
                ];
            }
    
            return $homepage_elements;
        }
    
        /**
         * Changes a user's email adress.
         *
         * @param string $email New email
         * @param bool   $force Force update (even if nothing actually changed)
         * @return bool
         */
        public function changeEmail($email, $force = false)
        {
            // Email did not actually change and update is not forced
            if ($this->email === $email && !$force) {
                return true;
            }
    
            // Is changing of email globally allowed?
            if (!Config::get()->ALLOW_CHANGE_EMAIL) {
                return false;
            }
    
            // Is changing of email allowed by auth plugin?
            if (StudipAuthAbstract::CheckField('auth_user_md5.Email', $this->auth_plugin) || LockRules::check($this->user_id, 'email')) {
                return false;
            }
    
            $validator          = new email_validation_class; ## Klasse zum Ueberpruefen der Eingaben
            $validator->timeout = 10;
            $REMOTE_ADDR        = $_SERVER['REMOTE_ADDR'];
            $Zeit               = date('H:i:s, d.m.Y');
    
            // accept only registered domains if set
            $email_restriction = trim(Config::get()->EMAIL_DOMAIN_RESTRICTION);
            if (!$validator->ValidateEmailAddress($email, $email_restriction)) {
                if ($email_restriction) {
                    $email_restriction_msg_part = '';
                    $email_restriction_parts    = explode(',', $email_restriction);
                    for ($email_restriction_count = 0; $email_restriction_count < count($email_restriction_parts); $email_restriction_count++) {
                        if ($email_restriction_count == count($email_restriction_parts) - 1) {
                            $email_restriction_msg_part .= '@' . trim($email_restriction_parts[$email_restriction_count]) . '<br>';
                        } else if (($email_restriction_count + 1) % 3) {
                            $email_restriction_msg_part .= '@' . trim($email_restriction_parts[$email_restriction_count]) . ', ';
                        } else {
                            $email_restriction_msg_part .= '@' . trim($email_restriction_parts[$email_restriction_count]) . ',<br>';
                        }
                    }
                    PageLayout::postError(sprintf(_('Die E-Mail-Adresse fehlt, ist falsch geschrieben oder gehört nicht zu folgenden Domains:%s'),
                        '<br>' . htmlReady($email_restriction_msg_part)));
                } else {
                    PageLayout::postError(_('Die E-Mail-Adresse fehlt oder ist falsch geschrieben!'));
                }
                return false;
            }
    
            if (!$validator->ValidateEmailHost($email)) {     // Mailserver nicht erreichbar, ablehnen
                PageLayout::postError(_('Der Mailserver ist nicht erreichbar. Bitte überprüfen Sie, ob Sie E-Mails mit der angegebenen Adresse verschicken können!'));
                return false;
            } else {       // Server ereichbar
                if (!$validator->ValidateEmailBox($email)) {    // aber user unbekannt. Mail an abuse!
                    StudipMail::sendAbuseMessage("edit_about", "Emailbox unbekannt\n\nUser: " . $this->username . "\nEmail: ".$email ."\n\nIP: " . $REMOTE_ADDR ." \nZeit: " . $Zeit . "\n");
                    PageLayout::postError(_('Die angegebene E-Mail-Adresse ist nicht erreichbar. Bitte überprüfen Sie Ihre Angaben!'));
                    return false;
                }
            }
    
            if (self::countBySql('email = ? AND user_id != ?', [$email, $this->user_id])) {
                PageLayout::postError(sprintf(_('Die angegebene E-Mail-Adresse wird bereits von einem anderen Benutzer (%s) verwendet. Bitte geben Sie eine andere E-Mail-Adresse an.'),
                    htmlReady($this->getFullName())));
                return false;
            }
    
            if (StudipAuthAbstract::CheckField('auth_user_md5.validation_key', $this->auth_plugin)) {
                PageLayout::postSuccess(_('Ihre E-Mail-Adresse wurde geändert!'));
            } else {
                // auth_plugin does not map validation_key (what if...?)
    
                // generate 10 char activation key
                $key = '';
                mt_srand((double)microtime() * 1000000);
                for ($i = 1; $i <= 10; $i++) {
                    $temp = mt_rand() % 36;
                    if ($temp < 10)
                        $temp += 48;   // 0 = chr(48), 9 = chr(57)
                    else
                        $temp += 87;   // a = chr(97), z = chr(122)
                    $key .= chr($temp);
                }
                $this->validation_key = $key;
    
                $activatation_url = $GLOBALS['ABSOLUTE_URI_STUDIP'] . 'activate_email.php?uid=' . $this->user_id . '&key=' . $this->validation_key;
                // include language-specific subject and mailbody with fallback to german
                $lang = getUserLanguagePath($this->id);
                if($lang == '') {
                    $lang = 'de';
                }
    
                // TODO: This should be refactored so that the included file returns an array
                include "locale/$lang/LC_MAILS/change_self_mail.inc.php"; // Defines $subject and $mailbody
    
                $mail = StudipMail::sendMessage($email, $subject ?? '', $mailbody ?? '');
    
                if (!$mail) {
                    return true;
                }
    
                $this->store();
    
                PageLayout::postInfo(sprintf(_('An Ihre neue E-Mail-Adresse <b>%s</b> wurde ein Aktivierungslink geschickt, dem Sie folgen müssen bevor Sie sich das nächste mal einloggen können.'), htmlReady($email)));
                StudipLog::log('USER_NEWPWD', $this->user_id);
            }
            return true;
        }
    
        /**
         * Merge an user ($old_id) to another user ($new_id).  This is a part of the
         * old numit-plugin.
         *
         * @param string $old_user
         * @param string $new_user
         * @param boolean $identity merge identity (if true)
         *
         * @return array() messages to display after migration
         * @deprecated
         */
        public static function convert($old_id, $new_id, $identity = false)
        {
            NotificationCenter::postNotification('UserWillMigrate', $old_id, $new_id);
    
            $messages = [];
    
            //Identitätsrelevante Daten migrieren
            if ($identity) {
                // Veranstaltungseintragungen
                self::removeDoubles('seminar_user', 'Seminar_id', $new_id, $old_id);
                $query = "UPDATE IGNORE seminar_user SET user_id = ? WHERE user_id = ?";
                $statement = DBManager::get()->prepare($query);
                $statement->execute([$new_id, $old_id]);
    
                self::removeDoubles('admission_seminar_user', 'seminar_id', $new_id, $old_id);
                $query = "UPDATE IGNORE admission_seminar_user SET user_id = ? WHERE user_id = ?";
                $statement = DBManager::get()->prepare($query);
                $statement->execute([$new_id, $old_id]);
    
                self::removeDoubles('termin_related_persons', 'range_id', $new_id, $old_id);
                $query = "UPDATE IGNORE `termin_related_persons` SET `user_id` = ? WHERE `user_id` = ?";
                $statement = DBManager::get()->prepare($query);
                $statement->execute([$new_id, $old_id]);
    
                // Persönliche Infos
                $query = "DELETE FROM user_info WHERE user_id = ?";
                $statement = DBManager::get()->prepare($query);
                $statement->execute([$new_id]);
    
                $query = "UPDATE IGNORE user_info SET user_id = ? WHERE user_id = ?";
                $statement = DBManager::get()->prepare($query);
                $statement->execute([$new_id, $old_id]);
    
                // Migrate registration timestamp by creating a new empty user info
                // entry
                $query = "INSERT INTO `user_info` (`user_id`, `mkdate`, `chdate`)
                          SELECT ?, `mkdate`, `chdate`
                          FROM `user_info`
                          WHERE `user_id` = ?";
                DBManager::get()->execute($query, [$old_id, $new_id]);
    
                // Studiengänge
                self::removeDoubles('user_studiengang', 'fach_id', $new_id, $old_id);
                $query = "UPDATE IGNORE user_studiengang SET user_id = ? WHERE user_id = ?";
                $statement = DBManager::get()->prepare($query);
                $statement->execute([$new_id, $old_id]);
    
                // Eigene Kategorien
                $query = "UPDATE IGNORE kategorien SET range_id = ? WHERE range_id = ?";
                $statement = DBManager::get()->prepare($query);
                $statement->execute([$new_id, $old_id]);
    
                // Institute
                self::removeDoubles('user_inst', 'Institut_id', $new_id, $old_id);
                $query = "UPDATE IGNORE user_inst SET user_id = ? WHERE user_id = ?";
                $statement = DBManager::get()->prepare($query);
                $statement->execute([$new_id, $old_id]);
    
                // Generische Datenfelder zusammenführen (bestehende Einträge des
                // "neuen" Nutzers werden dabei nicht überschrieben)
                $old_user = User::find($old_id);
                $old_user->datafields->each(function ($field) use ($new_id) {
                    if (!$field->isNew() && $field->content !== null) {
                        $entry = new DatafieldEntryModel([$field->datafield_id, $new_id, $field->sec_range_id, $field->lang]);
    
                        if ($entry->content === null || $entry->content === '' || $entry->content === 'default_value') {
                            $entry->content = $field->content;
                            $entry->store();
                        }
                    }
                });
    
                # Datenfelder des alten Nutzers leeren
                $old_user->datafields = [];
                $old_user->store();
    
                //
    
                //Buddys
                $query = "UPDATE IGNORE contact SET owner_id = ? WHERE owner_id = ?";
                $statement = DBManager::get()->prepare($query);
                $statement->execute([$new_id, $old_id]);
    
                // Avatar
                $old_avatar = Avatar::getAvatar($old_id);
                $new_avatar = Avatar::getAvatar($new_id);
                if ($old_avatar->is_customized()) {
                    if (!$new_avatar->is_customized()) {
                        $avatar_file = $old_avatar->getFilename(Avatar::ORIGINAL);
                        if (!file_exists($avatar_file)) {
                            $avatar_file = $old_avatar->getFilename(Avatar::NORMAL);
                        }
                        $new_avatar->createFrom($avatar_file);
                    }
                    $old_avatar->reset();
                }
    
                $messages[] = _('Identitätsrelevante Daten wurden migriert.');
            }
    
            // Restliche Daten übertragen
    
            // ForumsModule migrieren
            foreach (PluginEngine::getPlugins('ForumModule') as $plugin) {
                $plugin->migrateUser($old_id, $new_id);
            }
    
            // Dateieintragungen und Ordner
            // TODO (mlunzena) should post a notification
            $query = "UPDATE IGNORE file_refs SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            $query = "UPDATE IGNORE files SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            $query = "UPDATE IGNORE folders SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            //Kalender
            $query = "UPDATE IGNORE calendar_event SET range_id = ? WHERE range_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            $query = "UPDATE IGNORE calendar_user SET owner_id = ? WHERE owner_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            $query = "UPDATE IGNORE calendar_user SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            $query = "UPDATE IGNORE event_data SET author_id = ? WHERE author_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            $query = "UPDATE IGNORE event_data SET editor_id = ? WHERE editor_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            //Archiv
            self::removeDoubles('archiv_user', 'seminar_id', $new_id, $old_id);
            $query = "UPDATE IGNORE archiv_user SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            // Evaluationen
            $query = "UPDATE IGNORE eval SET author_id = ? WHERE author_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            self::removeDoubles('eval_user', 'eval_id', $new_id, $old_id);
            $query = "UPDATE IGNORE eval_user SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            $query = "UPDATE IGNORE evalanswer_user SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            // Kategorien
            $query = "UPDATE IGNORE kategorien SET range_id = ? WHERE range_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            // Nachrichten (Interne)
            $query = "UPDATE IGNORE message SET autor_id = ? WHERE autor_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            self::removeDoubles('message_user', 'message_id', $new_id, $old_id);
            $query = "UPDATE IGNORE message_user SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            // News
            $query = "UPDATE IGNORE news SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            $query = "UPDATE IGNORE news_range SET range_id = ? WHERE range_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            // Informationsseiten
            $query = "UPDATE IGNORE scm SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            // Statusgruppeneinträge
            self::removeDoubles('statusgruppe_user', 'statusgruppe_id', $new_id, $old_id);
            $query = "UPDATE IGNORE statusgruppe_user SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            // Termine
            $query = "UPDATE IGNORE termine SET autor_id = ? WHERE autor_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            //Votings
            $query = "UPDATE IGNORE questionnaires SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            $query = "UPDATE IGNORE questionnaire_assignments SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            $query = "UPDATE IGNORE questionnaire_assignments SET range_id = ? WHERE range_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            self::removeDoubles('questionnaire_anonymous_answers', 'questionnaire_id', $new_id, $old_id);
            $query = "UPDATE IGNORE questionnaire_anonymous_answers SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            self::removeDoubles('questionnaire_answers', 'question_id', $new_id, $old_id);
            $query = "UPDATE IGNORE questionnaire_answers SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            //Wiki
            $query = "UPDATE IGNORE wiki SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            $query = "UPDATE IGNORE wiki_locks SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            //Adressbucheinträge
            $query = "UPDATE IGNORE contact SET owner_id = ? WHERE owner_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            //Blubber
            $query = "UPDATE IGNORE blubber_comments SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
            $query = "UPDATE IGNORE blubber_mentions SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
            $query = "UPDATE IGNORE blubber_threads SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
            $query = "UPDATE IGNORE blubber_threads_followstates SET user_id = ? WHERE user_id = ?";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
    
            // Consultations
            $query = "UPDATE IGNORE consultation_blocks SET range_id = ? WHERE range_id = ? AND range_type = 'user'";
            DBManager::get()->execute($query, [$new_id, $old_id]);
            $query = "UPDATE IGNORE consultation_bookings SET user_id = ? WHERE user_id = ?";
            DBManager::get()->execute($query, [$new_id, $old_id]);
            $query = "UPDATE IGNORE consultation_events SET user_id = ? WHERE user_id = ?";
            DBManager::get()->execute($query, [$new_id, $old_id]);
            $query = "UPDATE IGNORE consultation_responsibilities SET range_id = ? WHERE range_id = ?
                                                                   AND range_type = 'user'";
            DBManager::get()->execute($query, [$new_id, $old_id]);
    
            NotificationCenter::postNotification('UserDidMigrate', $old_id, $new_id);
    
            $messages[] = _('Dateien, Termine, Adressbuch, Nachrichten und weitere Daten wurden migriert.');
            return $messages;
        }
    
        /**
         * Delete double entries of the old and new user. This is a part of the old
         * numit-plugin.
         *
         * @param string $table
         * @param string $field
         * @param md5 $new_id
         * @param md5 $old_id
         * @deprecated
         */
        private static function removeDoubles($table, $field, $new_id, $old_id)
        {
            $items = [];
    
            $query = "SELECT a.{$field} AS field_item
                      FROM {$table} AS a, {$table} AS b
                      WHERE a.user_id = ? AND b.user_id = ? AND a.{$field} = b.{$field}";
            $statement = DBManager::get()->prepare($query);
            $statement->execute([$new_id, $old_id]);
            $results = $statement->fetchAll(PDO::FETCH_ASSOC);
    
            foreach ($results as $value) {
                array_push($items, $value['field_item']);
            }
    
            if (!empty($items)) {
                $query = "DELETE FROM `{$table}`
                          WHERE user_id = :user_id AND `{$field}` IN (:items)";
    
                $statement = DBManager::get()->prepare($query);
                $statement->bindValue(':user_id', $new_id);
                $statement->bindValue(':items', $items, StudipPDO::PARAM_ARRAY);
                $statement->execute();
            }
        }
    
        /**
         * Returns a descriptive text for the range type.
         *
         * @return string
         */
        public function describeRange()
        {
            return _('NutzerIn');
        }
    
        /**
         * Returns a unique identificator for the range type.
         *
         * @return string
         */
        public function getRangeType()
        {
            return 'user';
        }
    
        /**
         * Returns the id of the current range
         *
         * @return mixed (string|int)
         */
        public function getRangeId()
        {
            return $this->id;
        }
    
        /**
         * {@inheritdoc}
         */
        public function getConfiguration()
        {
            return UserConfig::get($this);
        }
    
        /**
         * Decides whether the user may access the range.
         *
         * @param string|null $user_id Optional id of a user, defaults to current user
         * @return bool
         */
        public function isAccessibleToUser($user_id = null)
        {
            // TODO: Visibility checks
            if ($user_id === null) {
                $user_id = $GLOBALS['user']->id;
            }
            return $user_id === $this->user_id
                || self::find($user_id)->perms === 'root'
                || !in_array(self::find($this->user_id)->visible, ['no', 'never']);
        }
    
        /**
         * Decides whether the user may edit/alter the range.
         *
         * @param string|null $user_id Optional id of a user, defaults to current user
         * @return bool
         */
        public function isEditableByUser($user_id = null)
        {
            if ($user_id === null) {
                $user_id = $GLOBALS['user']->id;
            }
            return $user_id === $this->user_id
                || $GLOBALS['perm']->have_profile_perm('admin', $this->user_id)
                || Deputy::isDeputy($user_id, $this->user_id, true)
                || self::find($user_id)->perms === 'root';
        }
    
        /**
         * Export available data of a given user into a storage object
         * (an instance of the StoredUserData class) for that user.
         *
         * @param StoredUserData $storage object to store data into
         */
        public static function exportUserData(StoredUserData $storage)
        {
            $sorm = User::findBySQL("user_id = ?", [$storage->user_id]);
    
            if ($sorm) {
                $limit ='user_id username password perms vorname nachname email validation_key auth_plugin locked lock_comment locked_by visible';
                $field_data = [];
                foreach ($sorm as $row) {
                    $field_data[] = $row->toRawArray($limit);
                }
                if ($field_data) {
                    $storage->addTabularData(_('Kerndaten'), 'auth_user_md5', $field_data);
                }
    
                $limit = 'user_id hobby lebenslauf publi schwerp home privatnr privatcell privadr score geschlecht mkdate chdate title_front title_rear preferred_language smsforward_copy smsforward_rec email_forward smiley_favorite motto lock_rule';
                $field_data = [];
                foreach ($sorm as $row) {
                    $field_data[] = $row->toRawArray($limit);
                }
                if ($field_data) {
                    $storage->addTabularData(_('Benutzer Informationen'), 'user_info', $field_data);
                }
            }
    
            $data = DBManager::get()->fetchAll('SELECT * FROM object_user_visits WHERE user_id = ?', [$storage->user_id]);
            $storage->addTabularData(_('Objekt Aufrufe'), 'object_user_visits', $data);
        }
    
        /**
         * This callback is called after deleting a User.
         * It removes feedback entries that are associated with the User.
         */
        public function cbRemoveFeedback()
        {
            FeedbackElement::deleteBySQL('user_id = ?', [$this->id]);
            FeedbackEntry::deleteBySQL('user_id = ?', [$this->id]);
        }
    
        public function cbClearCaches()
        {
            if ($this->isFieldDirty('perms')) {
                RolePersistence::expireUserCache($this->user_id);
            }
        }
    
    
        /**
         * @see Range::__toString()
         */
        public function __toString() : string
        {
            return $this->getFullName();
        }
    }