Skip to content
Snippets Groups Projects
Select Git revision
  • 3eb1d6ae774098ff5119afccf0e1d66132673a90
  • main default protected
  • step-01354-5.5
  • biest-504
  • issue-3215
  • step-03209-bald-rapunzel
  • tic-3123
  • tic-2720-remove-less-compilation-in-plugins
  • step-1800
  • tic-2532
  • biest-561
  • tic-3225
  • 5.3
  • 5.4
  • step-2472
  • step-2660
  • step-1559
  • tic-3094
  • biest-3206
  • biest-3207
  • 5.0
  • v5.3.1
  • v5.2.3
  • v5.1.4
  • v5.0.6
  • v5.3
  • v5.2.2
  • v5.1.3
  • v5.0.5
  • v5.2.1
  • v5.1.2
  • v5.0.4
  • v5.2
  • v5.1.1
  • v5.0.3
  • v5.1
  • v5.0.2
  • v5.0.1
  • v5.0
39 results

export.js

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.
    wizard.php 17.14 KiB
    <?php
    /**
     * wizard.php
     * Controller for course creation wizard.
     *
     * 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      Thomas Hackl <thomas.hackl@uni-passau.de>
     * @copyright   2015 Stud.IP Core-Group
     * @license     http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
     * @category    Stud.IP
     * @since       3.3
     */
    
    class Course_WizardController extends AuthenticatedController
    {
        /**
         * @var Array steps the wizard has to execute in order to create a new course.
         */
        public $steps = [];
    
        public function before_filter (&$action, &$args)
        {
            parent::before_filter($action, $args);
    
            $this->dialog = Request::isXhr();
            $this->studygroup = Request::bool('studygroup', $this->flash['studygroup'] ?? false);
    
            if (!$this->studygroup) {
                PageLayout::setTitle(_('Neue Veranstaltung anlegen'));
    
                $navigation = new Navigation(_('Neue Veranstaltung anlegen'), 'dispatch.php/course/wizard');
                Navigation::addItem('/browse/my_courses/new_course', $navigation);
                Navigation::activateItem('/browse/my_courses/new_course');
            } else {
                $this->flash['studygroup'] = true;
    
                PageLayout::setTitle(_('Neue Studiengruppe anlegen'));
    
                $navigation = new Navigation(_('Neue Studiengruppe anlegen'), 'dispatch.php/course/wizard?studygroup=1');
                Navigation::addItem('/browse/my_courses/new_course', $navigation);
                Navigation::activateItem('/browse/my_courses/new_course');
            }
    
            $this->steps = CourseWizardStepRegistry::findBySQL("`enabled`=1 ORDER BY `number`");
    
            if ($GLOBALS['user']->perms === 'user') {
                throw new AccessDeniedException();
            }
        }
    
        /**
         * Just some sort of placeholder for initial calling without a step number.
         */
        public function index_action()
        {
            $this->redirect('course/wizard/step/0' . ($this->studygroup ? '?studygroup=1' : ''));
        }
    
        /**
         * Fetches the wizard step with the given number and gets the
         * corresponding template.
         *
         * @param int $number step number to show
         * @param String $temp_id temporary ID for the course to create
         */
        public function step_action($number=0, $temp_id='')
        {
            $step = $this->getStep($number);
            if (!$temp_id) {
                $this->initialize();
                if (Request::getArray('batchcreate')) {
                    $_SESSION['coursewizard'][$this->temp_id]['batchcreate'] = Request::getArray('batchcreate');
                }
            } else {
                $this->temp_id = $temp_id;
            }
            if ($number == 0) {
                $this->first_step = true;
            }
    
            if ($this->studygroup) {
                // Add special studygroup flag to set values.
                $this->setStepValues(
                    get_class($step),
                    array_merge($this->getValues(get_class($step)), ['studygroup' => 1])
                );
            }
            $this->values = $this->getValues();
            $this->content = $step->getStepTemplate($this->values, $number, $this->temp_id);
            $this->stepnumber = $number;
    
        }
    
        /**
         * Processes a finished wizard step by saving the gathered values to
         * session.
         * @param int $step_number the step we are at.
         * @param String $temp_id temporary ID for the course to create
         */
        public function process_action($step_number, $temp_id)
        {
            $stop = false;
            $next_step = 0;
            $this->temp_id = $temp_id;
            // Get request data and store it in session.
            $iterator = Request::getInstance()->getIterator();
            $values = [];
            while ($iterator->valid()) {
                $values[$iterator->key()] = $iterator->current();
                $iterator->next();
            }
            if (!empty($this->steps[$step_number]['classname'])) {
                $this->setStepValues($this->steps[$step_number]['classname'], $values);
            }
            // Back or forward button clicked -> set next step accordingly.
            if (Request::submitted('back')) {
                $next_step = $this->getNextRequiredStep($step_number, 'down');
            } else if (Request::submitted('next')) {
                // Validate given data.
                if ($this->getStep($step_number)->validate($this->getValues())) {
                    $next_step = $this->getNextRequiredStep($step_number, 'up');
                /*
                 * Validation failed -> stay on current step. Error messages are
                 * provided via the called step class validation method.
                 */
                } else {
                    $next_step = $step_number;
                }
            // The "create" button was clicked -> create course.
            } else if (Request::submitted('create')) {
                $_SESSION['coursewizard'][$this->temp_id]['copy_basic_data'] = Request::submitted('copy_basic_data');
                if ($this->getValues()) {
                    // Batch creation of several courses at once.
                    if ($batch = Request::getArray('batchcreate')) {
                        $numbering = ($batch['numbering'] == 'number' ? 1 : 'A');
                        $success = 0;
                        $failed = 0;
                        // Create given number of courses.
                        for ($i = 1 ; $i <= $batch['number'] ; $i++) {
                            if ($newcourse = $this->createCourse($i == $batch['number'] ? true : false)) {
                                // Add corresponding number/letter to name or number of newly created course.
                                if ($batch['add_number_to'] == 'name') {
                                    $newcourse->name .= ' ' . $numbering;
                                } else if ($batch['add_number_to'] == 'number') {
                                    $newcourse->veranstaltungsnummer = $batch['numbering'] == 'number' ?
                                        $numbering : $newcourse->veranstaltungsnummer . ' ' . $numbering;
                                }
                                $newcourse->parent_course = $batch['parent'];
                                if ($newcourse->store()) {
                                    $numbering++;
                                    $success++;
                                } else {
                                    $failed++;
                                }
                            } else {
                                $failed++;
                            }
                        }
    
                        // Show message for successfully created courses.
                        if ($success > 0) {
                            PageLayout::postSuccess(sprintf(_('%u Veranstaltungen wurden angelegt.'), $success));
                        }
    
                        // Show message for courses that couldn't be created.
                        if ($failed > 0) {
                            PageLayout::postError(sprintf(_('%u Veranstaltungen konnten nicht angelegt werden.'), $failed));
                        }
    
                        $this->redirect(URLHelper::getURL('dispatch.php/course/grouping/children',
                            ['cid' => $batch['parent']]));
                    } else {
                        $this->course = $this->createCourse();
                        if ($this->course) {
                            if (!$GLOBALS['perm']->have_perm('root')) {
                                $dest_url = 'course/contentmodules';
                            } else {
                                $dest_url = 'course/basicdata/view';
                            }
                            // A studygroup has been created.
                            if (in_array($this->course->status, studygroup_sem_types())) {
                                $message = MessageBox::success(sprintf(
                                    _('Die Studien-/Arbeitsgruppe "%s" wurde angelegt. '
                                    . 'Sie können sie direkt hier weiter verwalten.'),
                                    htmlReady($this->course->name)
                                ));
                                $target = $this->url_for('course/studygroup/edit', ['cid' => $this->course->id]);
    
                                // "Normal" course.
                            } elseif (Request::int('dialog') && $GLOBALS['perm']->have_perm('admin')) {
    
                                $message = MessageBox::success(sprintf(
                                    _('Die Veranstaltung <a class="link-intern" href="%s">"%s"</a> wurde angelegt.'),
                                    $this->link_for($dest_url, ['cid' => $this->course->id]),
                                    htmlReady($this->course->getFullname())
                                ));
                                $target = $this->url_for('admin/courses');
                            } else {
                                $message = MessageBox::success(sprintf(
                                    _('Die Veranstaltung "%s" wurde angelegt. Sie können sie direkt hier weiter verwalten.'),
                                    htmlReady($this->course->getFullname())
                                ));
                                $target = $this->url_for($dest_url, ['cid' => $this->course->id]);
                            }
    
                            PageLayout::postMessage($message);
                            $this->redirect($target);
                        } else {
                            PageLayout::postError(_('Die Veranstaltung konnte nicht angelegt werden.'));
                            $this->redirect('course/wizard');
                        }
                    }
                } else {
                    PageLayout::postMessage(MessageBox::error(_('Die angegebene Veranstaltung wurde bereits angelegt.')));
                    $this->redirect('course/wizard');
                }
                $stop = true;
            /*
             * Something other than "back", "next" or "create" was clicked,
             * e.g. QuickSearch
             * -> stay on current step and process given values.
             */
            } else {
                $stepclass = $this->steps[$step_number]['classname'];
                $result = $this->getStep($step_number)
                    ->alterValues($this->getValues());
                $_SESSION['coursewizard'][$temp_id][$stepclass] = $result;
                $next_step = $step_number;
            }
            if (!$stop) {
                // We are after the last step -> all done, show summary.
                if ($next_step >= count($this->steps)) {
                    $this->redirect($this->url_for('course/wizard/summary', $next_step, $temp_id));
                // Redirect to next step.
                } else {
                    $this->redirect($this->url_for('course/wizard/step', $next_step, $this->temp_id));
                }
            }
        }
    
        /**
         * We are after last step: all set and ready to create a new course.
         */
        public function summary_action($stepnumber, $temp_id)
        {
            $this->stepnumber = $stepnumber;
            $this->temp_id = $temp_id;
            $this->source_course = null;
            if (!$this->getValues()) {
                PageLayout::postError(_('Ihre Session ist abgelaufen, bitte erneut anfangen.'));
                $this->redirect('course/wizard');
            }
            if (isset($_SESSION['coursewizard'][$this->temp_id]['source_id'])) {
                $this->source_course = Course::find($_SESSION['coursewizard'][$this->temp_id]['source_id']);
            }
        }
    
        /**
         * Wrapper for ajax calls to step classes. Three things must be given
         * via Request:
         * - step number
         * - method to call in target step
         * - parameters for the target method (will be passed in given order)
         */
        public function ajax_action()
        {
            $stepNumber = Request::int('step');
            $method = Request::get('method');
            $parameters = Request::getArray('parameter');
            $result = call_user_func_array([$this->getStep($stepNumber), $method], $parameters);
            if (is_array($result) || is_object($result)) {
                $this->render_json($result);
            } else {
                $this->render_text($result);
            }
    
        }
    
        public function forward_action($step_number, $temp_id)
        {
            $this->temp_id = $temp_id;
            $stepclass = $this->steps[$step_number]['classname'];
            $result = $this->getStep($step_number)->alterValues($this->getValues() ?: []);
            $this->setStepValues($stepclass, $result);
            $this->redirect($this->url_for('course/wizard/step', $step_number, $this->temp_id));
        }
    
        /**
         * Copy an existing course.
         */
        public function copy_action($id) {
            if (!$GLOBALS['perm']->have_studip_perm('dozent', $id)
                || LockRules::Check($id, 'seminar_copy')) {
                throw new AccessDeniedException(_("Sie dürfen diese Veranstaltung nicht kopieren"));
            }
            $course = Course::find($id);
            $values = [];
            for ($i = 0 ; $i < sizeof($this->steps) ; $i++) {
                $step = $this->getStep($i);
                $values = $step->copy($course, $values);
            }
            $values['source_id'] = $course->id;
            $this->initialize();
            $_SESSION['coursewizard'][$this->temp_id] = $values;
            $this->redirect($this->url_for('course/wizard/step/0/' . $this->temp_id, ['cid' => '']));
        }
    
        /**
         * Creates a temporary ID for storing the wizard values in session.
         */
        private function initialize()
        {
            $temp_id = md5(uniqid(microtime()));
            $_SESSION['coursewizard'][$temp_id] = [];
            $this->temp_id = $temp_id;
        }
    
        /**
         * Wizard finished: we can create the course now. First store an empty,
         * invisible course for getting an ID. Then, iterate through steps and
         * set values from each step.
         * @param bool $cleanup cleanup session after course creation?
         * @return Course
         * @throws Exception
         */
        private function createCourse($cleanup = true)
        {
    
            foreach (array_keys($this->steps) as $n) {
                $step = $this->getStep($n);
                if ($step->isRequired($this->getValues())) {
                    if (!$step->validate($this->getValues())) {
                        unset($_SESSION['coursewizard'][$this->temp_id]);
                        return false;
                    }
                }
            }
            // Create a new (empty) course so that we get an ID.
            $course = new Course();
            $course->visible = 0;
            $course->setId($course->getNewId());
            $course_id = $course->id;
            // Each (required) step stores its own values at the course object.
            for ($i = 0; $i < sizeof($this->steps) ; $i++) {
                $step = $this->getStep($i);
                if ($step->isRequired($this->getValues())) {
                    if ($stored = $step->storeValues($course, $this->getValues())) {
                        $course = $stored;
                    } else {
                        $course = false;
                        unset($_SESSION['coursewizard'][$this->temp_id]);
                        break;
                        //throw new Exception(_('Die Daten aus Schritt ' . $i . ' konnten nicht gespeichert werden, breche ab.'));
                    }
                }
            }
            // Cleanup session data if necessary.
            if ($cleanup) {
                unset($_SESSION['coursewizard'][$this->temp_id]);
            }
            return $course;
        }
    
        /**
         * Fetches the class belonging to the wizard step at the given index.
         * @param $number
         * @return mixed
         */
        private function getStep($number)
        {
            $classname = $this->steps[$number]['classname'];
            return new $classname();
        }
    
        /**
         * Not all steps are required for each course type, some sem_classes must
         * not have study areas, for example. So we need to check which step is
         * required next, starting from an index and going up or down, according
         * to navigation through the wizard.
         * @param $number
         * @param string $direction
         * @return mixed
         */
        private function getNextRequiredStep($number, $direction='up')
        {
            $found = false;
            switch ($direction) {
                case 'up':
                    $i = $number + 1;
                    while (!$found && $i < sizeof($this->steps)) {
                        $step = $this->getStep($i);
                        if ($step->isRequired($this->getValues())) {
                            $found = true;
                        } else {
                            $i++;
                        }
                    }
                    break;
                case 'down':
                    $i = $number - 1;
                    while (!$found && $i >= 0) {
                        $step = $this->getStep($i);
                        if ($step->isRequired($this->getValues())) {
                            $found = true;
                        } else {
                            $i--;
                        }
                    }
                    break;
            }
            return $i;
        }
    
        /**
         * Gets values stored in session for a given step, or all
         * @param string $classname the step to get values for, or all
         * @return Array
         */
        private function getValues($classname='')
        {
            if ($classname) {
                return $_SESSION['coursewizard'][$this->temp_id][$classname] ?? [];
            } else {
                return $_SESSION['coursewizard'][$this->temp_id] ?? [];
            }
        }
    
        /**
         * @param string $stepclass name of the current step.
         * @param mixed $values
         */
        private function setStepValues($stepclass, $values)
        {
            $_SESSION['coursewizard'][$this->temp_id][$stepclass] = $values;
        }
    
    }