Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • alexander.vorwerk/studip
  • hochschule-wismar/stud-ip
  • tleilax/studip
  • marcus/studip
  • manschwa/studip
  • eberhardt/studip
  • uol/studip
  • pluta/studip
  • thienel/extern-uni-b
  • studip/studip
  • strohm/studip
  • uni-osnabrueck/studip
  • FloB/studip
  • universit-t-rostock/studip
  • Robinyyy/studip
  • jakob.diel/studip
  • HyperSpeeed/studip
  • ann/studip
  • nod3zer0/stud-ip-siple-saml-php-plugin
19 results
Show changes
Commits on Source (533)
Showing
with 4076 additions and 182 deletions
{
"parserOptions": {
"parser": "@babel/eslint-parser",
"parser": "@typescript-eslint/parser",
"sourceType": "module"
},
"env": {
......@@ -9,7 +9,8 @@
},
"extends": [
"eslint:recommended",
"plugin:vue/essential"
"plugin:vue/essential",
"@vue/eslint-config-typescript"
],
"globals": {
"STUDIP": "writable",
......@@ -23,13 +24,15 @@
],
"rules": {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "off",
"no-async-promise-executor": "error",
"no-await-in-loop": "error",
"no-promise-executor-return": "error",
"require-atomic-updates": "error",
"max-nested-callbacks": ["error", 4],
"no-return-await": "error",
"prefer-promise-reject-errors": "error"
"prefer-promise-reject-errors": "error",
"vue/multi-word-component-names": "off"
}
}
......@@ -31,10 +31,6 @@ public/pictures/banner/*.jpg
public/pictures/banner/*.png
public/pictures/course/[0-9a-f]*.png
public/pictures/institute/[0-9a-f]*.png
public/pictures/smile/*.gif
public/pictures/smile/*.jpeg
public/pictures/smile/*.jpg
public/pictures/smile/*.png
public/pictures/user/[0-9a-f]*.png
public/plugins_packages/*
......
image: studip/studip:tests
image: studip/studip:tests-php7.2
variables:
GIT_DEPTH: 1
MYSQL_RANDOM_ROOT_PASSWORD: "true"
MYSQL_DATABASE: studip_db
MYSQL_USER: studip_user
......@@ -12,150 +13,177 @@ variables:
# Optimize caching
FF_USE_FASTZIP: "true"
CACHE_COMPRESSION_LEVEL: "fast"
# User faster docker driver
# Use faster docker driver
DOCKER_DRIVER: overlay2
# Images
NODE_IMAGE: node:14-slim
# Directories
CACHE_DIR: .caches
REPORT_DIR: .reports
stages:
- checks
- analyse
- tests
- test
- packaging
- release
- build
.scripts:
install-composer:
mkdir-caches: &mkdir-caches
- mkdir -p $CACHE_DIR
mkdir-reports: &mkdir-reports
- mkdir -p $REPORT_DIR
install-composer: &install-composer
- make composer-dev
configure-studip:
- !reference [.scripts, install-composer]
configure-studip: &configure-studip
- *install-composer
- cp docker/studip/config_local.php config/config_local.inc.php
- cp config/config.inc.php.dist config/config.inc.php
initialize-studip-database:
- !reference [.scripts, configure-studip]
initialize-studip-database: &initialize-studip-database
- *configure-studip
- chmod +x .gitlab/scripts/install_db.sh
- .gitlab/scripts/install_db.sh
- cli/studip migrate
remove-absolute-path-in-report:
- sed -i "s%$PWD/%%" tests/_output/report.xml
.artifacts:
common: &common-artifacts
when: always
expire_in: 1 week
tests: &test-artifacts
<<: *common-artifacts
paths:
- tests/_output
reports:
junit: tests/_output/report.xml
.caches:
php: &composer-cache
key: "php-$CI_COMMIT_REF_SLUG"
paths:
- composer/
- .caches/phplint-cache
- .caches/resultCache.php
- .caches/cache/*
- .caches/resultCaches/*
- $CACHE_DIR/phplint-cache
- $CACHE_DIR/resultCache.php
- $CACHE_DIR/cache/*
- $CACHE_DIR/resultCaches/*
js: &npm-cache
key: "js-$CI_COMMIT_REF_SLUG"
paths:
- node_modules/
- .caches/eslint-cache
- .caches/stylelint-cache
- $CACHE_DIR/eslint-cache
- $CACHE_DIR/stylelint-cache
lint-php:
stage: checks
needs: []
cache: *composer-cache
allow_failure: false
variables:
PHPLINT_JSON_REPORT: $REPORT_DIR/phplint-report.json
PHPLINT_CODE_QUALITY_REPORT: $REPORT_DIR/phplint-codequality.json
interruptible: true
before_script:
- !reference [.scripts, install-composer]
- mkdir -p .reports
- *mkdir-caches
- *mkdir-reports
- *install-composer
script:
- php -d memory_limit=-1 composer/bin/phplint --xml .reports/phplint-report.xml --cache=.caches/phplint-cache
- php -d memory_limit=-1
composer/bin/phplint
--json $PHPLINT_JSON_REPORT
--cache=$CACHE_DIR/phplint-cache
after_script:
- ./.gitlab/scripts/convert-phplint-report $PHPLINT_JSON_REPORT > $PHPLINT_CODE_QUALITY_REPORT
artifacts:
<<: *common-artifacts
paths:
- .reports/phplint-report.xml
reports:
junit: .reports/phplint-report.xml
codequality: $PHPLINT_CODE_QUALITY_REPORT
lint-js:
stage: checks
needs: []
cache: *npm-cache
allow_failure: false
image: $NODE_IMAGE
variables:
ESLINT_CODE_QUALITY_REPORT: $REPORT_DIR/eslint-codequality.json
interruptible: true
before_script:
- make npm
- *mkdir-reports
- npm install
--no-save --no-audit --no-fund
--loglevel=error
eslint eslint-formatter-gitlab
script:
- npm run lint -- --cache --cache-location .caches/eslint-cache --format ./node_modules/eslint-junit/index.js
- npx eslint
--ext .js,.vue
--format gitlab
resources/assets/javascripts resources/vue
artifacts:
<<: *common-artifacts
paths:
- .reports/eslint-report.xml
reports:
junit: .reports/eslint-report.xml
codequality: $ESLINT_CODE_QUALITY_REPORT
lint-css:
stage: checks
needs: []
cache: *npm-cache
allow_failure: false
image: $NODE_IMAGE
variables:
STYLELINT_CODE_QUALITY_REPORT: $REPORT_DIR/stylelint-codequality.json
interruptible: true
before_script:
- make npm
- *mkdir-reports
- npm install
--no-save --no-audit --no-fund
--loglevel=error
stylelint@^14.9.1
stylelint-config-standard@^26.0.0
stylelint-formatter-gitlab
script:
- npm run css-lint -s -- --cache --cache-location .caches/stylelint-cache --custom-formatter node_modules/stylelint-junit-formatter --output-file .reports/stylelint-report.xml
- npx
stylelint
--custom-formatter=node_modules/stylelint-formatter-gitlab
resources/assets/stylesheets
artifacts:
<<: *common-artifacts
paths:
- .reports/stylelint-report.xml
reports:
junit: .reports/stylelint-report.xml
codequality: $STYLELINT_CODE_QUALITY_REPORT
phpstan:
stage: analyse
needs: [lint-php]
variables:
PHPSTAN_CODE_QUALITY_REPORT: $REPORT_DIR/phpstan-codequality.json
allow_failure: true
interruptible: true
when: manual
cache: *composer-cache
before_script:
- make composer-dev
- mkdir .reports -p
- *mkdir-reports
- *install-composer
script:
- php composer/bin/phpstan analyse --memory-limit=1G --no-progress --level=$PHPSTAN_LEVEL --error-format=gitlab > .reports/report-phpstan.json
- php
composer/bin/phpstan analyse
--memory-limit=1G
--no-progress
--level=$PHPSTAN_LEVEL
--error-format=gitlab > $PHPSTAN_CODE_QUALITY_REPORT
artifacts:
paths:
- .reports/report-phpstan.json
expire_in: 14 days
when: always
reports:
codequality: .reports/report-phpstan.json
codequality: $PHPSTAN_CODE_QUALITY_REPORT
test-unit:
stage: tests
stage: test
needs: [lint-php]
variables:
PHPUNIT_XML_REPORT: $REPORT_DIR/phpunit-report.xml
cache:
<<: *composer-cache
policy: pull
allow_failure: false
interruptible: true
before_script:
- !reference [.scripts, configure-studip]
- *mkdir-reports
- *configure-studip
script:
- composer/bin/codecept run unit --xml
- !reference [.scripts, remove-absolute-path-in-report]
- 'composer/bin/codecept
run unit
--xml=$PHPUNIT_XML_REPORT
-o "paths: output: ."'
after_script:
- sed -i "s%$PWD/%%" $PHPUNIT_XML_REPORT
artifacts:
<<: *test-artifacts
reports:
junit: $PHPUNIT_XML_REPORT
test-functional:
stage: tests
stage: test
needs: [lint-php]
variables:
FUNCTIONAL_XML_REPORT: $REPORT_DIR/functional-report.xml
FUNCTIONAL_CODE_QUALITY_REPORT: $REPORT_DIR/functional-codequality.json
cache:
<<: *composer-cache
policy: pull
......@@ -164,47 +192,54 @@ test-functional:
allow_failure: false
interruptible: true
before_script:
- !reference [.scripts, initialize-studip-database]
- *mkdir-reports
- *initialize-studip-database
script:
- composer/bin/codecept run functional --xml
- !reference [.scripts, remove-absolute-path-in-report]
- 'composer/bin/codecept
run functional
--xml=$FUNCTIONAL_XML_REPORT
-o "paths: output: ."'
after_script:
- sed -i "s%$PWD/%%" $FUNCTIONAL_XML_REPORT
artifacts:
<<: *test-artifacts
reports:
junit: $FUNCTIONAL_XML_REPORT
test-jsonapi:
stage: tests
stage: test
needs: [lint-php]
cache:
<<: *composer-cache
policy: pull
services:
- mariadb
allow_failure: false
variables:
JSONAPI_XML_REPORT: $REPORT_DIR/jsonapi-report.xml
interruptible: true
before_script:
- !reference [.scripts, initialize-studip-database]
- *mkdir-reports
- *initialize-studip-database
script:
- composer/bin/codecept run jsonapi --xml
- !reference [.scripts, remove-absolute-path-in-report]
- 'composer/bin/codecept
run jsonapi
--xml=$JSONAPI_XML_REPORT
-o "paths: output: ."'
after_script:
- sed -i "s%$PWD/%%" $JSONAPI_XML_REPORT
artifacts:
<<: *test-artifacts
when: always
expire_in: 1 week
paths:
- tests/_output
reports:
junit: tests/_output/report.xml
junit: $JSONAPI_XML_REPORT
test-assets:
stage: tests
stage: test
needs: []
image: $NODE_IMAGE
cache: *npm-cache
allow_failure: false
interruptible: true
before_script:
- make npm
- npm install
script:
- make webpack-dev
- npm run webpack-dev
packaging:
stage: packaging
......
## Barrierefreiheits-Review
### Prüfung auf ausreichenden Kontrast und Kenntlichmachung bei GUI-Elementen
- [ ] Vordergrund- und Hintergrundfarbe haben einen ausreichenden Kontrast.
- Mindestens 4,5:1 bei Text und 3:1 bei Icons, idealerweise 7:1.
- [ ] Links werden passend hervorgehoben.
- Kontrast mindestens 3:1 und mit einer weiteren Hervorhebung.
- Wegen GUI-Richtlinien nur im Fließtext umsetzbar.
- [ ] Die angezeigten Informationen sind auch ohne Farbsehen erkennbar.
### Prüfung auf Tastaturbedienbarkeit von Seitenelementen
- [ ] Interaktive Elemente (Link, Button) sind per TAB erreichbar.
- [ ] Elemente verwenden übliche Tasten zur Bedienung
- Eingabetaste für Links und Buttons.
- Pfeiltasten für Select-Felder und Radio-Buttons.
- Leertaste zum Aktivieren von Checkboxen, Radio-Buttons und zum Öffnen von Select-Feldern.
- [ ] Fokusfallen sind nicht vorhanden
- [ ] Die „natürliche“ Reihenfolge der Fokussierung bleibt erhalten.
- tabindex > 0 wird nicht verwendet.
- [ ] Die Fokussierung wird beim Aufruf von Aktionen nicht zurückgesetzt.
### Prüfung auf Nutzbarkeit von Seitenelementen mit Screenreadern
- [ ] Elemente werden korrekt vorgelesen.
- Button: „Schalter“
- Link: „Link“
- Select-Feld: „Auswahlfeld“/„Auswahlschalter“
- [ ] Icons, die nur Schmuckelemente sind, sind für Screenreader unsichtbar.
- [ ] Icons und Bilder, die eine Information liefern, haben einen Alternativtext, der vorgelesen wird.
- [ ] Vorgelesene Texte referenzieren andere Elemente der Seite ohne Positionsangaben.
- [ ] Anhand des vorgelesenen Textes ist die Struktur der Seite erkennbar.
- [ ] Dopplungen von Text (durch ein Icon neben einem Text) tauchen nicht auf.
## Mängel
- (Hier Mängel auflisten)
/label ~BIEST ~Accessibility ~"Version::5.4"
#!/usr/bin/env php
<?php
function error(string $error, int $status = 1): void
{
echo trim($error) . "\n";
exit($status);
}
$self = basename($argv[0]);
if ($argc !== 2) {
error("Missing report file, use {$self} <filename>");
}
$report_file = $argv[1];
if (!file_exists($report_file)) {
error("Report file {$report_file} does not exist");
}
if (!is_readable($report_file)) {
error("Report file {$report_file} is not readable");
}
$json = json_decode(file_get_contents($report_file), true);
if ($json === false) {
error("Could not read json contents of {$report_file}");
}
$errors = [];
foreach ($json['errors'] as $error) {
$errors[] = [
'description' => $error['error'],
'fingerprint' => md5("{$error['file_name']}:{$error['line']}"),
'severity' => 'major',
'location' => [
'path' => $error['file_name'],
'lines' => [
'begin' => $error['line'],
],
],
];
}
echo json_encode($errors);
This diff is collapsed.
......@@ -38,7 +38,7 @@ PROJECT_NAME = Stud.IP
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 4.0
PROJECT_NUMBER = 5.4
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
......
......@@ -2,7 +2,7 @@ Die Installation von Stud.IP ist halb so schlimm:
es müssen lediglich ein paar Dateien kopiert werden und ein paar
Programme laufen ;-)
Vorausgesetzt wird ein Webserver wie Apache2 oder nginx mit PHP-7.0 Modulen und
Vorausgesetzt wird ein Webserver wie Apache2 oder nginx mit PHP-7.2 Modulen und
eine MySQL 5.7.6 Datenbank.
Was genau zu tun ist, steht in
......@@ -16,4 +16,4 @@ können.
Also reinsehen und ausprobieren... Viel Spass damit!
You get in an try out. Have a lot of fun!
The StudIP Core Group <[info@studip.de](mailto:info@studip.de)> 2022
\ No newline at end of file
The StudIP Core Group <[info@studip.de](mailto:info@studip.de)> 2022
CODECEPT = composer/bin/codecept
CATALOGS = locale/en/LC_MESSAGES/studip.mo locale/en/LC_MESSAGES/js-resources.json
NPM_BIN = $(shell npm bin)
RESOURCES = $(shell find resources -type f)
PHP_SOURCES = $(shell find app config lib public templates -name '*.php' \( ! -path 'public/plugins_packages/*' -o -path 'public/plugins_packages/core/*' \))
......@@ -79,17 +78,17 @@ test-unit: $(CODECEPT)
catalogs: npm $(CATALOGS)
optimize-icons: npm
find public/assets/images/icons -type f | xargs -P0 $(NPM_BIN)/svgo -q --config=config/svgo.config.js
find public/assets/images/icons -type f | xargs -P0 npx svgo -q --config=config/svgo.config.js
# default rules for gettext handling
js-%.pot: $(VUE_SOURCES)
$(NPM_BIN)/gettext-extract --attribute v-translate --output $@ $(VUE_SOURCES)
npx gettext-extract --attribute v-translate --output $@ $(VUE_SOURCES)
js-%.po: js-%.pot
msgmerge -qU -C $(dir $@)studip.po $@ $<
js-%.json: js-%.po
$(NPM_BIN)/gettext-compile --output $@ $<
npx gettext-compile --output $@ $<
sed -i~ 's/^{[^{]*//;s/}$$//' $@
%.pot: $(PHP_SOURCES)
......
# Stud.IP v5.4
**<Datum>**
## Neue Features
-
## Breaking changes
-
## Security related issues
-
## Deprecated Features
-
RELEASE 5.2.alpha-svn
RELEASE 5.4.alpha
<?php
class Accessibility_FormsController extends StudipController
{
protected $with_session = true;
public function report_barrier_action()
{
PageLayout::setTitle(_('Barriere melden'));
$this->page = Request::get('page');
$user = User::findCurrent();
$user_salutation = '';
if (!empty($user)) {
if ($user->geschlecht == 1) {
$user_salutation = _('Herr');
} elseif ($user->geschlecht == 2) {
$user_salutation = _('Frau');
} elseif ($user->geschlecht == 3) {
$user_salutation = _('divers');
}
}
$this->form = \Studip\Forms\Form::create();
$this->form->addInput(
new \Studip\Forms\HiddenInput(
'page',
'',
$this->page
)
);
$details_part = new \Studip\Forms\Fieldset(_('Angaben zur gefundenen Barriere'));
$details_part->addInput(
new \Studip\Forms\SelectInput(
'barrier_type',
_('Um welche Art von Barriere handelt es sich?'),
'',
[
'options' => [
_('Inhalte auf dieser Seite (z.B. PDF, Bilder oder Lernmodule)') => _('Inhalte auf dieser Seite (z.B. PDF, Bilder oder Lernmodule)'),
_('Ein Problem mit der Seite selbst oder der Navigation') => _('Ein Problem mit der Seite selbst oder der Navigation'),
_('Sonstiges') => _('Sonstiges')
]
]
)
)->setRequired();
$details_part->addInput(
new \Studip\Forms\TextareaInput(
'barrier_details',
_('Beschreiben Sie die Barriere'),
''
)
)->setRequired();
$this->form->addPart($details_part);
$personal_data_part = new \Studip\Forms\Fieldset(_('Ihre persönlichen Daten'));
$personal_data_part->addText(sprintf('<p>%s</p>', _('Freiwillige Angaben Ihrer Kontaktdaten für etwaige Rückfragen.')));
$personal_data_part->addInput(
new \Studip\Forms\SelectInput(
'salutation',
_('Anrede'),
$user_salutation,
[
'options' => [
_('Keine Angabe') => _('Keine Angabe'),
_('Frau') => _('Frau'),
_('Herr') => _('Herr'),
_('divers') => _('divers')
]
]
)
);
$personal_data_part->addInput(
new \Studip\Forms\TextInput(
'name',
_('Vorname und Nachname'),
$user ? sprintf('%s %s', $user->vorname, $user->nachname) : ''
)
);
$personal_data_part->addInput(
new \Studip\Forms\TextInput(
'phone_number',
_('Telefonnummer'),
$user ? ($user->privatcell ?: $user->privatnr) : ''
)
);
$personal_data_part->addInput(
new \Studip\Forms\TextInput(
'email_address',
_('E-Mail-Adresse'),
$user ? $user->email : ''
)
);
$personal_data_part->addText(sprintf('<p>%s</p>',
_('Informationen zum Datenschutz dieses Formulars finden Sie in der Datenschutzerklärung.')));
$privacy_url = Config::get()->PRIVACY_URL;
if (is_internal_url($privacy_url)) {
$personal_data_part->addLink(
_('Datenschutzerklärung lesen'),
URLHelper::getURL($privacy_url, ['cancel_login' => '1']),
Icon::create('link-intern'),
['data-dialog' => 'size=big']
);
} else {
$personal_data_part->addLink(
_('Datenschutzerklärung lesen'),
URLHelper::getURL($privacy_url),
Icon::create('link-extern'),
['target' => '_blank']
);
}
$this->form->addPart($personal_data_part);
$this->form->setSaveButtonText(_('Barriere melden'));
$this->form->setSaveButtonName('report');
$this->form->setURL($this->report_barrierURL());
$this->form->addStoreCallback(
function ($form, $form_values) {
$recipients = Config::get()->ACCESSIBILITY_RECEIVER_EMAIL;
if (empty($recipients)) {
//Fallback: Use the UNI_CONTACT mail address:
$recipients = [$GLOBALS['UNI_CONTACT']];
}
//Get the sender and their language:
$sender = User::findCurrent();
//Default to the system default language:
$lang = explode('_', $GLOBALS['DEFAULT_LANGUAGE'])[0];
if ($sender) {
//Use the senders language since the choices in the form
//are in their language as well.
$lang = explode('_', getUserLanguage($sender->id))[0];
}
//Format the senders name according to the salutation.
$formatted_name = '';
if ($form_values['salutation'] === _('Keine Angabe')) {
$formatted_name = $form_values['name'];
} elseif ($form_values['salutation'] === _('divers')) {
$formatted_name = sprintf('%s (%s)', $form_values['name'], $form_values['salutation']);
} else {
$formatted_name = sprintf('%s %s', $form_values['salutation'], $form_values['name']);
}
//Build the mail text:
$template = $GLOBALS['template_factory']->open("../locale/{$lang}/LC_MAILS/report_barrier.php");
$template->set_attributes([
'sender' => $sender,
'page' => $form_values['page'],
'barrier_type' => $form_values['barrier_type'],
'barrier_details' => $form_values['barrier_details'],
'formatted_name' => $formatted_name,
'phone_number' => $form_values['phone_number'],
'email_address' => $form_values['email_address']
]);
$mail_text = $template->render();
foreach ($recipients as $mail_address) {
//Send the mail:
$mail = new StudipMail();
$mail->addRecipient($mail_address)
->setReplyToEmail($form_values['email_address'])
->setSubject(_('Meldung einer Barriere in Stud.IP'))
->setBodyText($mail_text)
->send();
}
$form->setSuccessMessage(
_('Ihre Meldung einer Barriere wurde weitergeleitet.') . ' ' .
sprintf(
'<a href="%1$s">%2$s %3$s</a>',
URLHelper::getLink($this->page),
Icon::create('link-intern', ['class' => 'text-bottom']),
_('Zurück')
)
);
return 1;
}
);
$this->form->autoStore();
}
}
......@@ -26,7 +26,12 @@ class Admin_AccessibilityInfoTextController extends AuthenticatedController
public function edit_action()
{
CSRFProtection::verifyUnsafeRequest();
Config::get()->store('ACCESSIBILITY_INFO_TEXT', Request::i18n('accessbility_info_text'));
Config::get()->store(
'ACCESSIBILITY_INFO_TEXT',
Studip\Markup::purifyHtml(Request::i18n('accessbility_info_text'))
);
PageLayout::postSuccess(_('Die Einstellungen wurden gespeichert.'));
$this->relocate('admin/accessibility_info_text/index');
}
......
......@@ -149,15 +149,17 @@ class Admin_AutoinsertController extends AuthenticatedController
$this->seminar_search = [];
PageLayout::setTitle(_('Manuelles Eintragen von Nutzergruppen in Veranstaltungen'));
if (Request::submitted('submit')) {
if (Request::submittedSome('submit', 'force')) {
$filters = array_filter(Request::getArray('filter'));
if (!Request::get('sem_id') || Request::get('sem_id') == 'false') {
$force = Request::bool('force', false);
$seminar_id = Request::option('sem_id');
if (!$seminar_id || $seminar_id === 'false') {
PageLayout::postError(_('Ungültiger Aufruf'));
} elseif (!count($filters)) {
PageLayout::postError(_('Keine Filterkriterien gewählt'));
} else {
$seminar = Seminar::GetInstance(Request::option('sem_id'));
$group = select_group($seminar->getSemesterStartTime());
$seminar = Seminar::GetInstance($seminar_id);
$userlookup = new UserLookup();
foreach ($filters as $type => $values) {
......@@ -167,9 +169,9 @@ class Admin_AutoinsertController extends AuthenticatedController
$real_users = 0;
foreach ($user_ids as $user_id) {
if (!AutoInsert::checkAutoInsertUser(Request::option('sem_id'), $user_id)) {
$seminar->addMember($user_id);
$real_users += AutoInsert::saveAutoInsertUser(Request::option('sem_id'), $user_id);
if ($force || !AutoInsert::checkAutoInsertUser($seminar_id, $user_id)) {
$real_users += $seminar->addMember($user_id) ? 1 : 0;
AutoInsert::saveAutoInsertUser($seminar_id, $user_id);
}
}
......@@ -193,6 +195,7 @@ class Admin_AutoinsertController extends AuthenticatedController
}
$this->redirect('admin/autoinsert/manual');
return;
}
}
......@@ -231,7 +234,8 @@ class Admin_AutoinsertController extends AuthenticatedController
'fachsemester' => _('Studienfachsemester'),
'institut' => _('Einrichtung'),
'status' => _('Statusgruppe'),
'domain' => _('Domäne')
'domain' => _('Domäne'),
'role' => _('Rolle'),
];
$links = new ActionsWidget();
......
......@@ -48,7 +48,11 @@ class Admin_CourseplanningController extends AuthenticatedController
$stgteil = StudiengangTeil::find($GLOBALS['user']->cfg->MY_COURSES_SELECTED_STGTEIL);
$plan_title .= ' - ' . $stgteil->getDisplayName();
}
if ($GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE && $GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE != 'all') {
if (
isset($this->semester)
&& $GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE
&& $GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE !== 'all'
) {
$plan_title .= ' - ' . $this->semester->name;
}
return $plan_title;
......@@ -838,45 +842,43 @@ class Admin_CourseplanningController extends AuthenticatedController
$sem_types = SemType::getTypes();
}
$seminars = array_map('reset', $courses);
if (!empty($seminars)) {
foreach ($seminars as $seminar_id => $seminar) {
$seminars[$seminar_id]['seminar_id'] = $seminar_id;
$seminars[$seminar_id]['obj_type'] = 'sem';
$dozenten = $this->getTeacher($seminar_id);
$seminars[$seminar_id]['dozenten'] = $dozenten;
if (in_array('contents', $params['view_filter'])) {
$tools = new SimpleCollection(ToolActivation::findbyRange_id($seminar_id, "ORDER BY position"));
$visit_data = get_objects_visits([$seminar_id], 0, null, null, $tools->pluck('plugin_id'));
$seminars[$seminar_id]['tools'] = $tools;
$seminars[$seminar_id]['visitdate'] = $visit_data[$seminar_id][0]['visitdate'];
$seminars[$seminar_id]['last_visitdate'] = $visit_data[$seminar_id][0]['last_visitdate'];
$seminars[$seminar_id]['sem_class'] = $sem_types[$seminar['status']]->getClass();
$seminars[$seminar_id]['navigation'] = MyRealmModel::getAdditionalNavigations(
$seminar_id,
$seminars[$seminar_id],
$seminars[$seminar_id]['sem_class'],
$GLOBALS['user']->id,
$visit_data[$seminar_id]
);
}
//add last activity column:
if (in_array('last_activity', $params['view_filter'])) {
$seminars[$seminar_id]['last_activity'] = lastActivity($seminar_id);
}
if ($this->selected_action == 17) {
$seminars[$seminar_id]['admission_locked'] = false;
if ($seminar['course_set']) {
$set = new CourseSet($seminar['course_set']);
if (!is_null($set) && $set->hasAdmissionRule('LockedAdmission')) {
$seminars[$seminar_id]['admission_locked'] = 'locked';
} else {
$seminars[$seminar_id]['admission_locked'] = 'disable';
}
unset($set);
$seminars = array_map('current', $courses);
foreach ($seminars as $seminar_id => $seminar) {
$seminars[$seminar_id]['seminar_id'] = $seminar_id;
$seminars[$seminar_id]['obj_type'] = 'sem';
$dozenten = $this->getTeacher($seminar_id);
$seminars[$seminar_id]['dozenten'] = $dozenten;
if (in_array('contents', $params['view_filter'])) {
$tools = new SimpleCollection(ToolActivation::findbyRange_id($seminar_id, "ORDER BY position"));
$visit_data = get_objects_visits([$seminar_id], 0, null, null, $tools->pluck('plugin_id'));
$seminars[$seminar_id]['tools'] = $tools;
$seminars[$seminar_id]['visitdate'] = $visit_data[$seminar_id][0]['visitdate'];
$seminars[$seminar_id]['last_visitdate'] = $visit_data[$seminar_id][0]['last_visitdate'];
$seminars[$seminar_id]['sem_class'] = $sem_types[$seminar['status']]->getClass();
$seminars[$seminar_id]['navigation'] = MyRealmModel::getAdditionalNavigations(
$seminar_id,
$seminars[$seminar_id],
$seminars[$seminar_id]['sem_class'],
$GLOBALS['user']->id,
$visit_data[$seminar_id]
);
}
//add last activity column:
if (in_array('last_activity', $params['view_filter'])) {
$seminars[$seminar_id]['last_activity'] = lastActivity($seminar_id);
}
if ($this->selected_action == 17) {
$seminars[$seminar_id]['admission_locked'] = false;
if ($seminar['course_set']) {
$set = new CourseSet($seminar['course_set']);
if (!is_null($set) && $set->hasAdmissionRule('LockedAdmission')) {
$seminars[$seminar_id]['admission_locked'] = 'locked';
} else {
$seminars[$seminar_id]['admission_locked'] = 'disable';
}
unset($set);
}
}
}
......
......@@ -169,22 +169,22 @@ class Admin_CoursesController extends AuthenticatedController
Now draw the configurable elements according
to the values inside the visibleElements array.
*/
if ($visibleElements['search']) {
if (!empty($visibleElements['search'])) {
$this->setSearchWiget();
}
if ($visibleElements['institute']) {
if (!empty($visibleElements['institute'])) {
$this->setInstSelector();
}
if ($visibleElements['semester']) {
if (!empty($visibleElements['semester'])) {
$this->setSemesterSelector();
}
if ($visibleElements['stgteil']) {
if (!empty($visibleElements['stgteil'])) {
$this->setStgteilSelector();
}
if ($visibleElements['courseType']) {
if (!empty($visibleElements['courseType'])) {
$this->setCourseTypeWidget($courseTypeFilterConfig);
}
if ($visibleElements['teacher']) {
if (!empty($visibleElements['teacher'])) {
$this->setTeacherWidget();
}
......@@ -536,7 +536,7 @@ class Admin_CoursesController extends AuthenticatedController
}
if (in_array('institute', $filter_config)) {
$row['institute'] = $course->home_institut ? $course->home_institut['name'] : $course['institute'];
$row['institute'] = $course_model->home_institut ? (string) $course_model->home_institut['name'] : $course_model['institut_id'];
}
foreach (PluginManager::getInstance()->getPlugins('AdminCourseContents') as $plugin) {
......@@ -592,7 +592,7 @@ class Admin_CoursesController extends AuthenticatedController
$inst = explode('_', Request::option('institute'));
$GLOBALS['user']->cfg->store('MY_INSTITUTES_DEFAULT', $inst[0]);
if ($inst[1] == 'withinst') {
if (isset($inst[1]) && $inst[1] === 'withinst') {
$GLOBALS['user']->cfg->store('MY_INSTITUTES_INCLUDE_CHILDREN', 1);
} else {
$GLOBALS['user']->cfg->store('MY_INSTITUTES_INCLUDE_CHILDREN', 0);
......@@ -648,11 +648,11 @@ class Admin_CoursesController extends AuthenticatedController
}
$course = Course::find($course_id);
if ($value == 'none') {
if ($value === 'none') {
$value = null;
}
if ($course->lock_rule == $value) {
if ($course->lock_rule === $value) {
continue;
}
......@@ -689,7 +689,7 @@ class Admin_CoursesController extends AuthenticatedController
$all_courses = Request::getArray('all_sem');
$course_set_id = CourseSet::getGlobalLockedAdmissionSetId();
$log_msg = '';
foreach ($all_courses as $course_id) {
if ($GLOBALS['perm']->have_studip_perm('dozent', $course_id)) {
$set = CourseSet::getSetForCourse($course_id);
......@@ -713,7 +713,7 @@ class Admin_CoursesController extends AuthenticatedController
}
if ($log_msg) {
StudipLog::log('SEM_CHANGED_ACCESS', $course_id, NULL, $log_msg);
StudipLog::log('SEM_CHANGED_ACCESS', $course_id, null, $log_msg);
}
}
}
......@@ -880,11 +880,14 @@ class Admin_CoursesController extends AuthenticatedController
throw new AccessDeniedException();
}
$course = Course::find($course_id);
$course->completion = ($course->completion + 1) % 3;
$course->completion = ((int)$course->completion + 1) % 3;
$course->store();
if (Request::isXhr()) {
$this->render_json((int)$course->completion);
$this->render_json([
'state' => (int)$course->completion,
'label' => $course->getCompetionLabel(),
]);
} else {
$this->redirect('admin/courses/index#course-' . $course_id);
}
......@@ -1193,7 +1196,9 @@ class Admin_CoursesController extends AuthenticatedController
$filter->filterBySemester($this->semester->getId());
}
if ($active_elements['courseType'] && $params['typeFilter'] && $params['typeFilter'] !== "all") {
list($class_filter,$type_filter) = explode('_', $params['typeFilter']);
$parts = explode('_', $params['typeFilter']);
$class_filter = $parts[0];
$type_filter = $parts[1] ?? null;
if (!$type_filter && !empty($GLOBALS['SEM_CLASS'][$class_filter])) {
$type_filter = array_keys($GLOBALS['SEM_CLASS'][$class_filter]->getSemTypes());
}
......@@ -1350,7 +1355,7 @@ class Admin_CoursesController extends AuthenticatedController
//from that faculty and all its institutes.
//$institut is an array, we can't use the method isFaculty() here!
if ($institut['fakultaets_id'] == $institut['Institut_id']) {
if ($institut['fakultaets_id'] === $institut['Institut_id']) {
$list->addElement(
new SelectElement(
$institut['Institut_id'] . '_withinst', //_withinst = with institutes
......
......@@ -29,7 +29,7 @@ class Admin_Cronjobs_LogsController extends AuthenticatedController
if (empty($_SESSION['cronlog-filter'])) {
$_SESSION['cronlog-filter'] = [
'where' => '1',
'values' => [],
'values' => array_fill_keys(['status', 'schedule_id', 'task_id'], null),
];
}
......
......@@ -29,7 +29,7 @@ class Admin_Cronjobs_SchedulesController extends AuthenticatedController
if (empty($_SESSION['cronjob-filter'])) {
$_SESSION['cronjob-filter'] = [
'where' => '1',
'values' => [],
'values' => array_fill_keys(['type', 'status', 'task_id'], null),
];
}
......
......@@ -66,20 +66,20 @@ class Admin_IliasInterfaceController extends AuthenticatedController
{
Navigation::activateItem('admin/config/ilias_interface');
PageLayout::setTitle(_("Verwaltung der ILIAS-Schnittstelle"));
PageLayout::setTitle(_('Verwaltung der ILIAS-Schnittstelle'));
$widget = new ActionsWidget();
$widget->addLink(
_('Schnittstelle konfigurieren'),
$this->url_for('admin/ilias_interface/edit_interface_settings'),
Icon::create('admin', 'clickable'),
Icon::create('admin'),
['data-dialog' => 'size=auto']
);
$widget->addLink(
_('ILIAS-Installation hinzufügen'),
$this->url_for('admin/ilias_interface/edit_server/new'),
Icon::create('add', 'clickable'),
Icon::create('add'),
['data-dialog' => 'size=auto']
);
$this->sidebar->addWidget($widget);
......@@ -125,7 +125,7 @@ class Admin_IliasInterfaceController extends AuthenticatedController
$this->ilias_version = '';
$this->ilias_version_date = '';
$this->clients = [];
if ($index == 'new') {
if ($index === 'new') {
// default values
$this->ilias_config = [
'is_active' => false,
......@@ -178,7 +178,7 @@ class Admin_IliasInterfaceController extends AuthenticatedController
} else {
$this->ilias_version = '';
}
if (Request::get('ilias_index') != 'new') {
if (Request::get('ilias_index') !== 'new') {
// use data from previously connected ILIAS
$index = Request::get('ilias_index');
} else {
......@@ -189,9 +189,9 @@ class Admin_IliasInterfaceController extends AuthenticatedController
}
// find new unique index
$index = 'ilias'.ConnectedIlias::getIntVersion($this->ilias_version);
if (is_array($this->ilias_configs[$index]) OR is_array($this->existing_indices[$index])) {
if (is_array($this->ilias_configs[$index]) || is_array($this->existing_indices[$index])) {
$i = 1;
while (is_array($this->ilias_configs[$index.'-'.$i]) OR is_array($this->existing_indices[$index.'-'.$i])) {
while (is_array($this->ilias_configs[$index.'-'.$i]) || is_array($this->existing_indices[$index.'-'.$i])) {
$i++;
}
$index = $index.'-'.$i;
......@@ -247,7 +247,7 @@ class Admin_IliasInterfaceController extends AuthenticatedController
/**
* edit connected ILIAS permissions settings
* @param $index Index of ILIAS settings
* @param string $index Index of ILIAS settings
*/
public function edit_permissions_action($index)
{
......@@ -257,7 +257,7 @@ class Admin_IliasInterfaceController extends AuthenticatedController
/**
* Deletes given ILIAS settings from configuration
* @param $index Index of ILIAS settings
* @param string $index Index of ILIAS settings
*/
public function delete_action($index)
{
......@@ -272,7 +272,7 @@ class Admin_IliasInterfaceController extends AuthenticatedController
/**
* Save connected ILIAS installation settings
* @param $index Index of ILIAS settings
* @param string $index Index of ILIAS settings
*/
public function save_action($index)
{
......@@ -359,9 +359,10 @@ class Admin_IliasInterfaceController extends AuthenticatedController
}
}
}
// show error messages
foreach ($connected_ilias->getError() as $error) {
PageLayout::postError($error);
if (isset($connected_ilias)) { // show error messages
foreach ($connected_ilias->getError() as $error) {
PageLayout::postError($error);
}
}
$this->redirect($this->url_for('admin/ilias_interface'));
}
......@@ -376,7 +377,7 @@ class Admin_IliasInterfaceController extends AuthenticatedController
//check stored configuration
$connected_ilias = new ConnectedIlias($index);
if ($connected_ilias->getConnectionSettingsStatus() AND $connected_ilias->getContentSettingsStatus() AND $connected_ilias->getPermissionsSettingsStatus()) {
if ($connected_ilias->getConnectionSettingsStatus() && $connected_ilias->getContentSettingsStatus() && $connected_ilias->getPermissionsSettingsStatus()) {
//store config entry
Config::get()->store('ILIAS_INTERFACE_SETTINGS', $this->ilias_configs);
PageLayout::postSuccess(_('ILIAS-Installation aktiviert.'));
......@@ -427,6 +428,7 @@ class Admin_IliasInterfaceController extends AuthenticatedController
}
}
} elseif (Request::get('ilias_call')) {
$params = [];
foreach ($this->soap_methods[Request::get('ilias_call')] as $param) {
$params[$param] = Request::get('ilias_soap_param_'.$param);
}
......
......@@ -403,11 +403,12 @@ class Admin_InstallController extends Trails_Controller
public function migrate_action()
{
URLHelper::setBaseURL($_SESSION['STUDIP_INSTALLATION']['system']['ABSOLUTE_URI_STUDIP']);
unset($_SESSION['STUDIP_INSTALLATION']);
session_destroy();
header('Location: ' . dirname($_SERVER['SCRIPT_NAME']) . '/web_migrate.php');
die;
$this->redirect(URLHelper::getURL('web_migrate.php'));
}
public function session_error_action()
......