Skip to content
Snippets Groups Projects
Seminar.class.php 89.2 KiB
Newer Older
                    $user->username,
                    '____%system%____',
                    false,
                    false,
                    '1',
                    false,
                    sprintf('%s %s', _('Systemnachricht:'), _('nicht zugelassen in Veranstaltung')),
                    true
                );
                StudipLog::log('SEM_USER_DEL', $this->getId(), $user->id, 'Wurde aus der Veranstaltung entfernt');
                NotificationCenter::postNotification('UserDidLeaveCourse', $this->getId(), $user->id);

                $msgs[] = $user->getFullName();
            }
        }
        return $msgs;
    }

    /**
     * Cancels a subscription to a course
     * @param array $users
     * @return array
     * @throws Exception
     */
    public function cancelSubscription(array $users): array
    {
        $msgs = [];
        $messaging = new messaging;
        $users = User::findMany($users);
        foreach ($users as $user) {
            // delete member from seminar
            if ($this->deleteMember($user->id)) {
                setTempLanguage($user->id);
                $message = sprintf(
                    _('Ihre Anmeldung zur Veranstaltung **%s** wurde aufgehoben.'),
                    $this->getFullName()
                );
                restoreLanguage();
                $messaging->insert_message(
                    $message,
                    $user->username,
                    '____%system%____',
                    false,
                    false,
                    '1',
                    false,
                    sprintf('%s %s', _('Systemnachricht:'), _("Anmeldung aufgehoben")),
                    true
                );
                $msgs[] = $user->getFullName();
            }
        }

        return $msgs;
    }

    /**
     * deletes a user from the seminar by respecting the rule that at least one
     * user with status "dozent" must stay there
     * @param string $user_id  user_id of the user to delete
     * @return boolean
    public function deleteMember($user_id): bool
        $dozenten = $this->getMembers();
        if (count($dozenten) >= 2 || !$dozenten[$user_id]) {
            $result = CourseMember::deleteBySQL('Seminar_id = ? AND user_id = ?', [$this->id, $user_id]);
            if ($result === 0) {
                return true;
            }
            // If this course is a child of another course...
            if ($this->parent_course) {
                // ... check if user is member in another sibling ...
                $other = CourseMember::countBySQL(
                    "`user_id` = :user AND `Seminar_id` IN (:courses) AND `Seminar_id` != :this",
                    ['user' => $user_id, 'courses' => $this->parent->children->pluck('seminar_id'), 'this' => $this->id]
                );

                // ... and delete from parent course if this was the only
                // course membership in this family.
                if ($other === 0) {
                    $s = new Seminar($this->parent);
                    $s->deleteMember($user_id);
                }
            }

            if ($this->children != null) {
                foreach ($this->children as $child) {
                    $s = new Seminar($child);
                    $s->deleteMember($user_id);
                }
            }

            if ($dozenten[$user_id]) {
                $query = "SELECT termin_id FROM termine WHERE range_id = ?";
                $statement = DBManager::get()->prepare($query);
                $statement->execute([$this->id]);
                $termine = $statement->fetchAll(PDO::FETCH_COLUMN);

                $query = "DELETE FROM termin_related_persons WHERE range_id = ? AND user_id = ?";
                $statement = DBManager::get()->prepare($query);

                foreach ($termine as $termin_id) {
                    $statement->execute([$termin_id, $user_id]);
                }
                if (Deputy::isActivated()) {
                    $other_dozenten = array_diff(array_keys($dozenten), [$user_id]);
                    foreach (Deputy::findByRange_id($user_id) as $default_deputy) {
                        if ($default_deputy->user_id != $GLOBALS['user']->id &&
                                !Deputy::countBySql("range_id IN (?)", [$other_dozenten])) {
                            Deputy::deleteBySQL("range_id = ? AND user_id = ?", [$this->id, $default_deputy->user_id]);
                        }
                    }
                }
            }

            // Delete course related datafield entries
            DatafieldEntryModel::deleteBySQL('range_id = ? AND sec_range_id = ?', [$user_id, $this->id]);

            // Remove from associated status groups
            foreach (Statusgruppen::findBySeminar_id($this->id) as $group) {
                $group->removeUser($user_id, true);
            }

            $this->createMessage(sprintf(
                _('Nutzer %s wurde aus der Veranstaltung entfernt.'),
                '<i>' . htmlReady(get_fullname($user_id)) . '</i>'
            ));
            NotificationCenter::postNotification('CourseDidChangeMember', $this, $user_id);
            NotificationCenter::postNotification('UserDidLeaveCourse', $this->id, $user_id);
            StudipLog::log('SEM_USER_DEL', $this->id, $user_id, 'Wurde aus der Veranstaltung entfernt');
            $this->course->resetRelation('members');
        } else {
            $this->createError(
                sprintf(
                    _('Die Veranstaltung muss wenigstens <b>einen/eine</b> VeranstaltungsleiterIn (%s) eingetragen haben!'),
                    get_title_for_status('dozent', 1, $this->status)
                )
                . ' ' . _('Tragen Sie zunächst einen anderen ein, um diesen zu löschen.')
            );
            return false;
        }
    }

    /**
     * sets the almost never used column position in the table seminar_user
     * @param array $members members array: array of user_id's - wrong IDs will be ignored
     * @return Seminar
    public function setMemberPriority($members): Seminar
    {
        $counter = 0;
        CourseMember::findEachBySQL(
            function (CourseMember $membership) use (&$counter) {
                $membership->position = $counter++;
                $membership->store();
            },
Jan-Hendrik Willms's avatar
Jan-Hendrik Willms committed
            "Seminar_id = ? AND user_id IN (?)",
David Siegfried's avatar
David Siegfried committed
            [$this->id, $members]
        return $this;
    }

    /**
     * returns array with information about enrolment to this course for given user_id
     * ['enrolment_allowed'] : true or false
     * ['cause']: keyword to describe the cause
     * ['description'] : readable description of the cause
     *
     * @param string $user_id
     * @return array
     */
    public function getEnrolmentInfo($user_id)
    {
        $info = [];
        $user = User::find($user_id);
        if ($this->getSemClass()->isGroup()) {
            $info['enrolment_allowed'] = false;
            $info['cause'] = 'grouped';
            $info['description'] = _("Dies ist eine Veranstaltungsgruppe. Sie können sich nur in deren Unterveranstaltungen eintragen.");
            return $info;
        }
        if ($this->read_level == 0 && Config::get()->ENABLE_FREE_ACCESS && !$GLOBALS['perm']->get_studip_perm($this->getId(), $user_id)) {
            $info['enrolment_allowed'] = true;
            $info['cause'] = 'free_access';
            $info['description'] = _("Für die Veranstaltung ist keine Anmeldung erforderlich.");
            return $info;
        }
        if (!$user) {
            $info['enrolment_allowed'] = false;
            $info['cause'] = 'nobody';
            $info['description'] = _("Sie sind nicht in Stud.IP angemeldet.");
            return $info;
        }
        if ($GLOBALS['perm']->have_perm('root', $user_id)) {
            $info['enrolment_allowed'] = true;
            $info['cause'] = 'root';
            $info['description'] = _("Sie dürfen ALLES.");
            return $info;
        }
        if ($GLOBALS['perm']->have_studip_perm('admin', $this->getId(), $user_id)) {
            $info['enrolment_allowed'] = true;
            $info['cause'] = 'courseadmin';
            $info['description'] = _("Sie sind Administrator_in der Veranstaltung.");
            return $info;
        }
        if ($GLOBALS['perm']->have_perm('admin', $user_id)) {
            $info['enrolment_allowed'] = false;
            $info['cause'] = 'admin';
            $info['description'] = _("Als Administrator_in können Sie sich nicht für eine Veranstaltung anmelden.");
            return $info;
        }
        //Ist bereits Teilnehmer
        if ($GLOBALS['perm']->have_studip_perm('user', $this->getId(), $user_id)) {
            $info['enrolment_allowed'] = true;
            $info['cause'] = 'member';
            $info['description'] = _("Sie sind für die Veranstaltung angemeldet.");
            return $info;
        }
        $admission_status = $user->admission_applications->findBy('seminar_id', $this->getId())->val('status');
        if ($admission_status == 'accepted') {
            $info['enrolment_allowed'] = false;
            $info['cause'] = 'accepted';
            $info['description'] = _("Sie wurden für diese Veranstaltung vorläufig akzeptiert.");
            return $info;
        }
        if ($admission_status == 'awaiting') {
            $info['enrolment_allowed'] = false;
            $info['cause'] = 'awaiting';
            $info['description'] = _("Sie stehen auf der Warteliste für diese Veranstaltung.");
            return $info;
        }
        if ($GLOBALS['perm']->get_perm($user_id) == 'user') {
            $info['enrolment_allowed'] = false;
            $info['cause'] = 'user';
            $info['description'] = _("Sie haben nicht die erforderliche Berechtigung sich für eine Veranstaltung anzumelden.");
            return $info;
        }
        //falsche Nutzerdomäne
        $same_domain = true;
        $user_domains = UserDomain::getUserDomainsForUser($user_id);
        if (count($user_domains) > 0) {
            $seminar_domains = UserDomain::getUserDomainsForSeminar($this->getId());
            $same_domain = UserDomain::checkUserVisibility($seminar_domains, $user_domains);;
        }
        if (!$same_domain && !$this->isStudygroup()) {
            $info['enrolment_allowed'] = false;
            $info['cause'] = 'domain';
            $info['description'] = _("Sie sind nicht in einer zugelassenenen Nutzerdomäne, Sie können sich nicht eintragen!");
            return $info;
        }
        //Teilnehmerverwaltung mit Sperregel belegt
        if (LockRules::Check($this->getId(), 'participants')) {
            $info['enrolment_allowed'] = false;
            $info['cause'] = 'locked';
            $lockdata = LockRules::getObjectRule($this->getId());
            $info['description'] = _("In diese Veranstaltung können Sie sich nicht eintragen!") . ($lockdata['description'] ? '<br>' . formatLinks($lockdata['description']) : '');
            return $info;
        }
        //Veranstaltung unsichtbar für aktuellen Nutzer
        if (!$this->visible && !$this->isStudygroup() && !$GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM, $user_id)) {
            $info['enrolment_allowed'] = false;
            $info['cause'] = 'invisible';
            $info['description'] = _("Die Veranstaltung ist gesperrt, Sie können sich nicht eintragen!");
            return $info;
        }
        if ($courseset = $this->getCourseSet()) {
            $info['enrolment_allowed'] = true;
            $info['cause'] = 'courseset';
            $info['description'] = _("Die Anmeldung zu dieser Veranstaltung folgt speziellen Regeln. Lesen Sie den Hinweistext.");
            $user_prio = AdmissionPriority::getPrioritiesByUser($courseset->getId(), $user_id);
            if (isset($user_prio[$this->getId()])) {
                if ($courseset->hasAdmissionRule('LimitedAdmission')) {
                    $info['description'] .= ' ' . sprintf(_("(Sie stehen auf der Anmeldeliste für die automatische Platzverteilung mit der Priorität %s.)"), $user_prio[$this->getId()]);
                } else {
                    $info['description'] .= ' ' . _("(Sie stehen auf der Anmeldeliste für die automatische Platzverteilung.)");
                }
            }
            return $info;
        }
        $info['enrolment_allowed'] = true;
        $info['cause'] = 'normal';
        $info['description'] = '';
        return $info;
    }

    /**
     * adds user with given id as preliminary member to course
     *
     * @param string $user_id
     * @return integer 1 if successfull
     */
    public function addPreliminaryMember($user_id, $comment = '')
    {
        $new_admission_member = new AdmissionApplication();
        $new_admission_member->user_id = $user_id;
        $new_admission_member->position = 0;
        $new_admission_member->status = 'accepted';
        $new_admission_member->comment = $comment;
        $this->course->admission_applicants[] = $new_admission_member;
        $ok = $new_admission_member->store();
        if ($ok && $this->isStudygroup()) {
            StudygroupModel::applicationNotice($this->getId(), $user_id);
        }
        $cs = $this->getCourseSet();
        if ($cs) {
            $prio_delete = AdmissionPriority::unsetPriority($cs->getId(), $user_id, $this->getId());
        }
        // LOGGING
        StudipLog::log('SEM_USER_ADD', $this->getId(), $user_id, 'accepted', 'Vorläufig akzeptiert');
        return $ok;
    }

    /**
     * returns courseset object for this  course
     *
     * @return CourseSet courseset object or null
     */
    public function getCourseSet()
    {
        if ($this->course_set === null) {
            $this->course_set = CourseSet::getSetForCourse($this->id);
            if ($this->course_set === null) {
                $this->course_set = false;
            }
        }
        return $this->course_set ?: null;
    }

    /**
     * returns true if the number of participants of this course is limited
     *
     * @return boolean
     */
    public function isAdmissionEnabled()
    {
        $cs = $this->getCourseSet();
        return ($cs && $cs->isSeatDistributionEnabled());
    }

    /**
     * returns the number of free seats in the course or true if not limited
     *
     * @return integer
     */
    public function getFreeAdmissionSeats()
    {
        if ($this->isAdmissionEnabled()) {
            return $this->course->getFreeSeats();
        } else {
            return true;
        }
    }

    /**
     * returns true if the course is locked
     *
     * @return boolean
     */
    public function isAdmissionLocked()
    {
        $cs = $this->getCourseSet();
        return ($cs && $cs->hasAdmissionRule('LockedAdmission'));
    }

    /**
     * returns true if the course is password protected
     *
     * @return boolean
     */
    public function isPasswordProtected()
    {
        $cs = $this->getCourseSet();
        return ($cs && $cs->hasAdmissionRule('PasswordAdmission'));
    }

    /**
     * returns array with start and endtime of course enrolment timeframe
     * return null if there is no timeframe
     *
     * @return array assoc array with start_time end_time as keys timestamps as values
     */
    public function getAdmissionTimeFrame()
    {
        $cs = $this->getCourseSet();
        return ($cs && $cs->hasAdmissionRule('TimedAdmission')) ?
            ['start_time' => $cs->getAdmissionRule('TimedAdmission')->getStartTime(),
                  'end_time' => $cs->getAdmissionRule('TimedAdmission')->getEndTime()] : [];
    }

    /**
     * returns StudipModule object for given slot, null when deactivated or not available
     *
     * @param string $slot
    public function getSlotModule($slot): ?StudipModule
    {
        $module = 'Core' . ucfirst($slot);
        if ($this->course->isToolActive($module)) {
            return PluginEngine::getPlugin($module);
        }
    }

    /**
     * adds user with given id on waitinglist
     *
     * @param string $user_id
     * @param string $which_end 'last' or 'first'
     * @return integer|bool number on waitlist or false if not successful
     */
    public function addToWaitlist($user_id, $which_end = 'last')
    {
        if (AdmissionApplication::exists([$user_id, $this->id]) || CourseMember::find([$this->id, $user_id])) {
            return false;
        }
        switch ($which_end) {
            // Append users to waitlist end.
            case 'last':
                $maxpos = DBManager::get()->fetchColumn("SELECT MAX(`position`)
                    FROM `admission_seminar_user`
                    WHERE `seminar_id`=?
                        AND `status`='awaiting'", [$this->id]);
                $waitpos = $maxpos+1;
                break;
            // Prepend users to waitlist start.
            case 'first':
            default:
                // Move all others on the waitlist up by the number of people to add.
                AdmissionApplication::renumberAdmission($this->id);
                $waitpos = 1;
        }
        $new_admission_member = new AdmissionApplication();
        $new_admission_member->user_id = $user_id;
        $new_admission_member->position = $waitpos;
        $new_admission_member->status = 'awaiting';
        $new_admission_member->seminar_id = $this->id;
        if ($new_admission_member->store()) {
            StudipLog::log('SEM_USER_ADD', $this->id, $user_id, 'awaiting', 'Auf Warteliste gesetzt, Position: ' . $waitpos);
            $this->course->resetRelation('admission_applicants');
            return $waitpos;
        }
        return false;
    }
}