Compare commits

...

43 Commits

Author SHA1 Message Date
Luca c9fa7131bd Redirect to home site if user is already logged in 3 years ago
Luca 52e8c895cb Only show login link in navbar if visitor is guest 3 years ago
Luca 8dfabec920 Move registration button above login form, remove angeltype button from login page 3 years ago
Luca f8d7c080d9 Use permissions to hide menu items instead of commenting them out 3 years ago
Luca 5a8d94e21e Add bottom margin to even more things 3 years ago
Luca 89d903d360 Hide most user information from 'normal' users 3 years ago
Luca 4291107050 Re-enable translation for 'Answer questions' 3 years ago
Luca 6ffcaf3f8b Update translations 3 years ago
Luca 099d8371b3 Only show DECT number if DECT is enabled 3 years ago
Luca 9def5d689e Also check if required fields are empty 3 years ago
Luca 1ba5cd9fe8 Add more spacing to registration form 3 years ago
Luca aacd2ae83c Add info about minimum password length to registration form 3 years ago
Luca 4c1396398c Update localization 3 years ago
Luca 91f40167e2 Replace favicon with empty image (using angel.svg does not work due to filename mangling) 3 years ago
Luca 82076f2003 Add favicon 3 years ago
Luca c585115e2a Add bottom margin to consent checkbox, mark mobile number as required 3 years ago
Luca 673aa60bcd Fix missing comma 3 years ago
Luca 08d6f8e3e5 Update registration form 3 years ago
Luca 633e36b5f3 Enlarge shift signup submission button 3 years ago
Luca 1d586e0ee6 Hide comment field on shift self-signup 3 years ago
Luca a50e415d24 Remove 'News', 'Meetings', 'Angeltypes' and 'Ask the Heaven' from navbar 3 years ago
Luca 64b281c4c8 Change default home site to 'user_shifts' 3 years ago
Luca 0f4f90cfa3 Disable pronoun field 3 years ago
Luca 9d7fbd56fa Fix migration 3 years ago
Luca c0f19eb2ff Rename groups 3 years ago
Luca 0419e7b217 Comment out note about cookies 3 years ago
Luca a562914339 Hide shifts export in shifts overview 3 years ago
Luca 1c10c21ad2 Pass crontab path to supercronic 3 years ago
Luca ba2cc09dc0 Add container for running tasks 3 years ago
Luca d84a336310 Replace 'database' with 'db' in $app->get() call 3 years ago
Luca 915b35c7b0 Fix import script some more 3 years ago
Luca 2870d84a0a Fix missing ')' 3 years ago
Luca b1cb122b86 Add script for importing schedules 3 years ago
Luca a788bc9cde Do not append language to title from schedule 3 years ago
Luca c8706d527e Add option to hide iCal/JSON export 3 years ago
Luca 15c677a28c Set 'oauth.openid.hidden' to true 3 years ago
Luca b2356afb79 Re-add excluded translations 3 years ago
Luca 9b4dda44b0 s/Engel/Helfer\*in/ 3 years ago
Luca 2e71130a4c Change default theme to 'Engelsystem light' and replace angel icon 3 years ago
Luca 11c8aa2536 Disable planned arrival/departure date fields 3 years ago
Luca efe62792e1 Set 'max_freeloadable_shifts' to 1 instead of 0 3 years ago
Luca 7f5c2da582 Change default config to better fit our needs 3 years ago
Luca d5640c4c69 Use 'unix_socket' instead of 'host' in database config 3 years ago

@ -1,5 +1,6 @@
# Docker config
docker/
!docker/crontab
!docker/nginx/entrypoint.sh
!docker/nginx/nginx.conf

@ -0,0 +1,31 @@
#!/usr/bin/env php
<?php
require_once __DIR__ . '/../includes/application.php';
require_once __DIR__ . '/../includes/pages/schedule/ImportSchedule.php';
use Engelsystem\Controllers\Admin\Schedule\ImportSchedule;
$script = array_shift($argv);
if (count($argv) === 0) {
echo "usage: $script '*'|SCHEDULE_ID [SCHEDULE_ID...]" . PHP_EOL;
exit;
}
$app = app();
$scheduleIds = $argv;
if ($argv[0] === '*') {
$db = $app->get('db');
$scheduleIds = array_map(fn(stdClass $schedule) => $schedule->id, $db->select('SELECT id FROM schedules'));
}
$importer = $app->get(ImportSchedule::class);
foreach ($scheduleIds as $id) {
try {
$importer->doImport($id);
} catch (ErrorException $e) {
echo "import '$id' failed:" . PHP_EOL . $e->getMessage() . PHP_EOL;
}
}

@ -2,13 +2,15 @@
// To change settings create a config.php
$default_app_name = 'Helfer*innen';
return [
// MySQL-Connection Settings
'database' => [
'host' => env('MYSQL_HOST', (env('CI', false) ? 'mariadb' : 'localhost')),
'database' => env('MYSQL_DATABASE', 'engelsystem'),
'username' => env('MYSQL_USER', 'root'),
'password' => env('MYSQL_PASSWORD', ''),
'unix_socket' => env('MYSQL_SOCKET', '/var/run/mysqld/mysqld.sock'),
],
// For accessing stats
@ -18,7 +20,7 @@ return [
'maintenance' => (bool)env('MAINTENANCE', false),
// Application name (not the event name!)
'app_name' => env('APP_NAME', 'Engelsystem'),
'app_name' => env('APP_NAME', $default_app_name),
// Set to development to enable debugging messages
'environment' => env('ENVIRONMENT', 'production'),
@ -35,10 +37,10 @@ return [
// Footer links
'footer_items' => [
// URL to the angel faq and job description
'FAQ' => env('FAQ_URL', '/faq'),
'FAQ' => env('FAQ_URL', 'https://kontakt-bamberg.de/mithelfen-2'),
// Contact email address, linked on every page
'Contact' => env('CONTACT_EMAIL', 'mailto:ticket@c3heaven.de'),
'Contact' => env('CONTACT_EMAIL', 'mailto:helfen@kontakt-bamberg.de'),
],
// Text displayed on the FAQ page, rendered as markdown
@ -54,7 +56,7 @@ return [
'from' => [
// From address of all emails
'address' => env('MAIL_FROM_ADDRESS', 'noreply@example.com'),
'name' => env('MAIL_FROM_NAME', env('APP_NAME', 'Engelsystem')),
'name' => env('MAIL_FROM_NAME', env('APP_NAME', $default_app_name)),
],
'host' => env('MAIL_HOST', 'localhost'),
@ -73,59 +75,56 @@ return [
'setup_admin_password' => env('SETUP_ADMIN_PASSWORD', null),
'oauth' => [
// '[name]' => [config]
/*
'[name]' => [
'openid' => [
// Name shown to the user (optional)
'name' => 'Some Provider',
'name' => env('OAUTH_DISPLAY_NAME', 'Team-Login'),
// Auth client ID
'client_id' => 'engelsystem',
'client_id' => env('OAUTH_CLIENT_ID', 'engelsystem'),
// Auth client secret
'client_secret' => '[generated by provider]',
'client_secret' => env('OAUTH_CLIENT_SECRET', null),
// Authentication URL
'url_auth' => '[generated by provider]',
'url_auth' => env('OAUTH_AUTH_URL', null),
// Token URL
'url_token' => '[generated by provider]',
'url_token' => env('OAUTH_TOKEN_URL', null),
// User info URL which provides userdata
'url_info' => '[generated by provider]',
'url_info' => env('OAUTH_USERINFO_URL', null),
// Info unique user id field
'id' => 'uuid',
'id' => env('OAUTH_ID_CLAIM', 'sub'),
// The following fields are used for registration
// Info username field (optional)
'username' => 'nickname',
'username' => env('OAUTH_USERNAME_CLAIM', 'preferred_username'),
// Info email field (optional)
'email' => 'email',
'email' => env('OAUTH_EMAIL_CLAIM', 'email'),
// Info first name field (optional)
'first_name' => 'first-name',
'first_name' => env('OAUTH_FIRST_NAME_CLAIM', 'given_name'),
// Info last name field (optional)
'last_name' => 'last-name',
'last_name' => env('OAUTH_LAST_NAME_CLAIM', 'family_name'),
// User URL to provider, linked on provider settings page (optional)
'url' => '[provider page]',
'url' => env('OAUTH_ACCOUNT_URL', null),
// Whether info attributes are nested arrays (optional)
// For example {"user":{"name":"foo"}} can be accessed using user.name
'nested_info' => false,
// Only show after clicking the page title (optional)
'hidden' => false,
'hidden' => true,
// Mark user as arrived when using this provider (optional)
'mark_arrived' => false,
'mark_arrived' => true,
// If the password field should be enabled on registration (optional)
'enable_password' => false,
// Allow registration even if disabled in config (optional)
'allow_registration' => null,
// Auto join teams
// Info groups field (optional)
'groups' => 'groups',
//'groups' => 'groups',
// Groups to team (angeltype) mapping (optional)
'teams' => [
/*'teams' => [
'/Lorem' => 4, // 4 being the ID of the angeltype
'/Foo Mod' => ['id' => 5, 'supporter' => true], // 5 being the ID of the angeltype
],*/
],
],
*/
],
// Default theme, 1=style1.css
'theme' => env('THEME', 1),
'theme' => env('THEME', 0),
'themes' => [
15 => [
@ -212,7 +211,7 @@ return [
// Redirect to this site after logging in or when pressing the top-left button
// Must be one of news, meetings, user_shifts, angeltypes, questions
'home_site' => env('HOME_SITE', 'news'),
'home_site' => env('HOME_SITE', 'user_shifts'),
// Number of News shown on one site
'display_news' => env('DISPLAY_NEWS', 10),
@ -221,7 +220,7 @@ return [
'registration_enabled' => (bool)env('REGISTRATION_ENABLED', true),
// Only arrived angels can sign up for shifts
'signup_requires_arrival' => (bool)env('SIGNUP_REQUIRES_ARRIVAL', false),
'signup_requires_arrival' => (bool)env('SIGNUP_REQUIRES_ARRIVAL', true),
// Whether newly-registered user should automatically be marked as arrived
'autoarrive' => (bool)env('ANGEL_AUTOARRIVE', false),
@ -257,32 +256,32 @@ return [
'enable_password' => (bool)env('ENABLE_PASSWORD', true),
// Whether the DECT field should be enabled
'enable_dect' => (bool)env('ENABLE_DECT', true),
// Enables prename and lastname
'enable_user_name' => (bool)env('ENABLE_USER_NAME', false),
'enable_dect' => (bool)env('ENABLE_DECT', false),
// Enable displaying the pronoun fields
'enable_pronoun' => (bool)env('ENABLE_PRONOUN', false),
// Enables the planned arrival/leave date
'enable_planned_arrival' => (bool)env('ENABLE_PLANNED_ARRIVAL', true),
'enable_planned_arrival' => (bool)env('ENABLE_PLANNED_ARRIVAL', false),
// Enables the T-Shirt configuration on signup and profile
'enable_tshirt_size' => (bool)env('ENABLE_TSHIRT_SIZE', true),
'enable_tshirt_size' => (bool)env('ENABLE_TSHIRT_SIZE', false),
// Enables shifts export as iCal/JSON (if disabled, buttons/links will not be shown, but endpoints will still work)
'enable_shifts_export' => (bool)env('ENABLE_SHIFTS_EXPORT', false),
// Enables the goody/voucher configuration on signup and profile
'enable_goody' => (bool)env('ENABLE_GOODY', false),
// Enables joining angel types on registration
'enable_angeltype_signup' => (bool)env('ENABLE_ANGELTYPE_SIGNUP', false),
// Number of shifts to freeload until angel is locked for shift signup.
'max_freeloadable_shifts' => env('MAX_FREELOADABLE_SHIFTS', 2),
'max_freeloadable_shifts' => env('MAX_FREELOADABLE_SHIFTS', 1),
// Local timezone
'timezone' => env('TIMEZONE', ini_get('date.timezone') ?: 'Europe/Berlin'),
// Multiply 'night shifts' and freeloaded shifts (start or end between 2 and 6 exclusive) by 2
'night_shifts' => [
'enabled' => (bool)env('NIGHT_SHIFTS', true), // Disable to weigh every shift the same
'enabled' => (bool)env('NIGHT_SHIFTS', false),
'start' => env('NIGHT_SHIFTS_START', 2),
'end' => env('NIGHT_SHIFTS_END', 6),
'multiplier' => env('NIGHT_SHIFTS_MULTIPLIER', 2),
@ -299,12 +298,11 @@ return [
// Available locales in /resources/lang/
'locales' => [
'de_DE' => 'Deutsch',
'en_US' => 'English',
'de_DE.UTF-8@kontakt' => 'Deutsch',
],
// The default locale to use
'default_locale' => env('DEFAULT_LOCALE', 'en_US'),
'default_locale' => env('DEFAULT_LOCALE', 'de_DE.UTF-8@kontakt'),
// Available T-Shirt sizes, set value to null if not available
'tshirt_sizes' => [
@ -359,9 +357,9 @@ return [
// A list of credits
'credits' => [
'Contribution' => 'Please visit [engelsystem/engelsystem](https://github.com/engelsystem/engelsystem) if '
. 'you want to to contribute, have found any [bugs](https://github.com/engelsystem/engelsystem/issues) '
. 'or need help.'
// 'Contribution' => 'Please visit [engelsystem/engelsystem](https://github.com/engelsystem/engelsystem) if '
// . 'you want to to contribute, have found any [bugs](https://github.com/engelsystem/engelsystem/issues) '
// . 'or need help.'
],
// var dump server

@ -0,0 +1,47 @@
<?php
namespace Engelsystem\Migrations;
use Engelsystem\Database\Migration\Migration;
class RenameGroups extends Migration
{
const GROUPS = [
[-10, '1-Gast', '1-Besucher*in'],
[-20, '2-Engel', '2-Helfer*in'],
[-40, '3-Shift Coordinator', '3-Schicht-Koordinator*in'],
[-50, '4-Team Coordinator', '4-Team-Koordinator*in'],
[-60, '5-Bürokrat', '5-Bürokrat*in'],
[-70, '6-Developer', '6-Entwickler*in'],
];
/**
* Run the migration
*/
public function up()
{
$connection = $this->schema->getConnection();
foreach (self::GROUPS as [$id, $old, $new]) {
$connection->update(
'UPDATE `Groups` SET `Name` = ? WHERE `UID` = ?',
[$new, $id]
);
}
}
/**
* Reverse the migration
*/
public function down()
{
$connection = $this->schema->getConnection();
foreach (self::GROUPS as [$id, $old, $new]) {
$connection->update(
'UPDATE `Groups` SET `Name` = ? WHERE `UID` = ?',
[$old, $id]
);
}
}
}

@ -27,6 +27,32 @@ COPY --from=composer /app/composer.lock /app/
RUN find /app/storage/ -type f -not -name VERSION -exec rm {} \;
# Fetch supercronic
FROM alpine as supercronic
ENV SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.1.12/supercronic-linux-amd64 \
SUPERCRONIC=supercronic-linux-amd64 \
SUPERCRONIC_SHA1SUM=048b95b48b708983effb2e5c935a1ef8483d9e3e
RUN apk add --no-cache curl \
&& curl -fsSLO "$SUPERCRONIC_URL" \
&& echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - \
&& chmod +x "$SUPERCRONIC" \
&& mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}"
# Build a container for running tasks
FROM php:8-cli-alpine as cron
RUN apk add --no-cache icu-dev && \
docker-php-ext-install intl pdo_mysql
COPY --from=data /app/ /app
COPY --from=supercronic /usr/local/bin/supercronic-linux-amd64 /usr/local/bin/supercronic
COPY docker/crontab /etc/crontab
ENTRYPOINT ["/usr/local/bin/supercronic"]
CMD ["/etc/crontab"]
# Build the PHP container
FROM php:8-fpm-alpine
WORKDIR /var/www

@ -0,0 +1,2 @@
# Run schedule import every minute
*/1 * * * * /app/bin/import '*'

@ -75,7 +75,7 @@ function ShiftEntry_create($shift_entry)
$shift_entry['SID'],
$shift_entry['TID'],
$shift_entry['UID'],
$shift_entry['Comment'],
$shift_entry['Comment'] ?? '',
$shift_entry['freeload_comment'],
(int)$shift_entry['freeloaded'],
]

@ -28,29 +28,24 @@ function guest_register()
$authUser = auth()->user();
$tshirt_sizes = config('tshirt_sizes');
$enable_tshirt_size = config('enable_tshirt_size');
$enable_user_name = config('enable_user_name');
$enable_dect = config('enable_dect');
$enable_planned_arrival = config('enable_planned_arrival');
$min_password_length = config('min_password_length');
$enable_password = config('enable_password');
$enable_pronoun = config('enable_pronoun');
$enable_angeltype_signup = config('enable_angeltype_signup');
$config = config();
$request = request();
$session = session();
$is_oauth = $session->has('oauth2_connect_provider');
$msg = '';
$nick = '';
$lastName = '';
$preName = '';
$dect = '';
$mobile = '';
$email = '';
$pronoun = '';
$email_shiftinfo = false;
$email_by_human_allowed = false;
$email_news = false;
$email_goody = false;
$mobile_consent = false;
$tshirt_size = '';
$password_hash = '';
$selected_angel_types = [];
@ -97,53 +92,29 @@ function guest_register()
if ($request->hasPostData('submit')) {
$valid = true;
if ($request->has('username')) {
$nickValidation = User_validate_Nick($request->input('username'));
$nick = $nickValidation->getValue();
if (!$nickValidation->isValid()) {
$valid = false;
$msg .= error(sprintf(__('Please enter a valid nick.') . ' ' . __('Use up to 24 letters, numbers, connecting punctuations or spaces for your nickname.'),
$nick), true);
}
if (User::whereName($nick)->count() > 0) {
if (!$request->has('prename') || empty($preName = strip_request_item('prename'))) {
$valid = false;
$msg .= error(sprintf(__('Your nick &quot;%s&quot; already exists.'), $nick), true);
$msg .= error(__('Please enter your first name.'), true);
}
} else {
if (!$request->has('lastname') || empty($lastName = strip_request_item('lastname'))) {
$valid = false;
$msg .= error(__('Please enter a nickname.'), true);
$msg .= error(__('Please enter your last name.'), true);
}
if ($request->has('email') && strlen(strip_request_item('email')) > 0) {
$email = strip_request_item('email');
if (!check_email($email)) {
if (!$request->has('mobile') || empty($mobile = strip_request_item('mobile'))) {
$valid = false;
$msg .= error(__('E-mail address is not correct.'), true);
}
if (User::whereEmail($email)->first()) {
$msg .= error(__('Please enter your mobile number.'), true);
} else if (User::whereName($mobile)->count() > 0) {
$valid = false;
$msg .= error(__('E-mail address is already used by another user.'), true);
$msg .= error(__('This mobile number is already in use.'), true);
}
if ($request->has('mobile_consent')) {
$mobile_consent = true;
} else {
$valid = false;
$msg .= error(__('Please enter your e-mail.'), true);
}
if ($request->has('email_shiftinfo')) {
$email_shiftinfo = true;
}
if ($request->has('email_by_human_allowed')) {
$email_by_human_allowed = true;
}
if ($request->has('email_news')) {
$email_news = true;
}
if ($request->has('email_goody')) {
$email_goody = true;
$msg .= error(__('Please consent to receiving notifications via SMS.'), true);
}
if ($enable_tshirt_size) {
@ -189,12 +160,6 @@ function guest_register()
}
// Trivia
if ($enable_user_name && $request->has('lastname')) {
$lastName = strip_request_item('lastname');
}
if ($enable_user_name && $request->has('prename')) {
$preName = strip_request_item('prename');
}
if ($enable_pronoun && $request->has('pronoun')) {
$pronoun = strip_request_item('pronoun');
}
@ -206,15 +171,12 @@ function guest_register()
error(__('For dect numbers are only 40 digits allowed.'));
}
}
if ($request->has('mobile')) {
$mobile = strip_request_item('mobile');
}
if ($valid) {
$user = new User([
'name' => $nick,
'name' => $mobile,
'password' => $password_hash,
'email' => $email,
'email' => $mobile,
'api_key' => '',
'last_login_at' => null,
]);
@ -242,10 +204,10 @@ function guest_register()
$settings = new Settings([
'language' => $session->get('locale'),
'theme' => config('theme'),
'email_human' => $email_by_human_allowed,
'email_goody' => $email_goody,
'email_shiftinfo' => $email_shiftinfo,
'email_news' => $email_news,
'email_human' => $mobile_consent,
'email_goody' => $mobile_consent,
'email_shiftinfo' => $mobile_consent,
'email_news' => $mobile_consent,
]);
$settings->user()
->associate($user)
@ -336,14 +298,6 @@ function guest_register()
$form_data = $session->get('form_data');
$session->remove('form_data');
if (!$nick && !empty($form_data['name'])) {
$nick = $form_data['name'];
}
if (!$email && !empty($form_data['email'])) {
$email = $form_data['email'];
}
if (!$preName && !empty($form_data['first_name'])) {
$preName = $form_data['first_name'];
}
@ -352,89 +306,54 @@ function guest_register()
$lastName = $form_data['last_name'];
}
if (!$mobile && !empty($form_data['phone_number'])) {
$mobile = $form_data['phone_number'];
}
return page_with_title(register_title(), [
__('By completing this form you\'re registering as a Chaos-Angel. This script will create you an account in the angel task scheduler.'),
form_info(entry_required() . ' = ' . __('Entry required!')),
form_element('', __('By completing this form you\'re registering as a Chaos-Angel. This script will create you an account in the angel task scheduler.')),
form_element('', entry_required() . ' = ' . __('Entry required!')),
$msg,
msg(),
form([
div('row', [
div('col', [
form_text(
'username',
__('Nick') . ' ' . entry_required(),
$nick,
false,
24,
'nickname'
),
form_info('',
__('Use up to 24 letters, numbers, connecting punctuations or spaces for your nickname.'))
form_text('prename', __('First name') . ' ' . entry_required(), $preName, false, 64, 'given-name')
]),
div('col', [
form_text('lastname', __('Last name') . ' ' . entry_required(), $lastName, false, 64, 'family-name')
]),
$enable_pronoun ? div('col', [
form_text('pronoun', __('Pronoun'), $pronoun, false, 15)
]) : '',
]),
$enable_user_name ? div('row', [
div('col', [
form_text('prename', __('First name'), $preName, false, 64, 'given-name')
]),
div('col', [
form_text('lastname', __('Last name'), $lastName, false, 64, 'family-name')
])
]) : '',
div('row', [
div('col', [
form_email(
'email',
__('E-Mail') . ' ' . entry_required(),
$email,
form_text(
'mobile',
__('Mobile') . ' ' . entry_required(),
$mobile,
false,
'email',
254
40,
'tel-national'
),
form_checkbox(
'email_shiftinfo',
__(
'The %s is allowed to send me an email (e.g. when my shifts change)',
[config('app_name')]
),
$email_shiftinfo
'mobile_consent',
__('I consent to receive notifications via SMS.') . ' ' . entry_required(),
$mobile_consent
),
form_checkbox(
'email_news',
__('Notify me of new news'),
$email_news
),
form_checkbox(
'email_by_human_allowed',
__('Allow heaven angels to contact you by e-mail.'),
$email_by_human_allowed
),
config('enable_goody') ?
form_checkbox(
'email_goody',
__('To receive vouchers, give consent that nick, email address, worked hours and shirt size will be stored until the next similar event.')
. (config('privacy_email') ? ' ' . __('To withdraw your approval, send an email to <a href="mailto:%s">%1$s</a>.', [config('privacy_email')]) : ''),
$email_goody
) : '',
]),
$enable_dect ? div('col', [
form_text('dect', __('DECT'), $dect, false, 40, 'tel-local')
]) : '',
div('col', [
form_text('mobile', __('Mobile'), $mobile, false, 40, 'tel-national')
])
]),
div('row', [
$enable_password || $enable_planned_arrival ? div('row', [
$enable_password ? div('col', [
form_password('password', __('Password') . ' ' . entry_required())
form_password('password', __('Password') . ' ' . entry_required()),
form_element('', '<span class="help-block">' . icon('info-circle') . sprintf(__('Please use at least %s characters.'), $min_password_length) . '</span>'),
]) : '',
$enable_planned_arrival ? div('col', [
@ -444,21 +363,22 @@ function guest_register()
$planned_arrival_date, $buildup_start_date, $teardown_end_date
)
]) : '',
]),
]) : '',
div('row', [
$enable_password || $enable_tshirt_size ? div('row', [
$enable_password ? div('col', [
form_password('password2', __('Confirm password') . ' ' . entry_required())
]) : '',
div('col', [
$enable_tshirt_size ? form_select('tshirt_size',
$enable_tshirt_size ? div('col', [
form_select('tshirt_size',
__('Shirt size') . ' ' . entry_required(),
$tshirt_sizes, $tshirt_size, __('Please select...')) : ''
]),
]),
$tshirt_sizes, $tshirt_size, __('Please select...')
)
]) : '',
]) : '',
div('row', [
$enable_angeltype_signup ? div('row', [
div('col', [
form_checkboxes(
'angel_types',
@ -475,7 +395,7 @@ function guest_register()
__('Some angel types have to be confirmed later by a supporter at an introduction meeting. You can change your selection in the options section.')
)
])
]),
]) : '',
form_submit('submit', __('Register'))
])

@ -169,6 +169,8 @@ class ImportSchedule extends BaseController
public function loadSchedule(Request $request): Response
{
try {
$id = $request->getAttribute('id');
/**
* @var Event[] $newEvents
* @var Event[] $changeEvents
@ -188,7 +190,7 @@ class ImportSchedule extends BaseController
,
$scheduleUrl,
$schedule
) = $this->getScheduleData($request);
) = $this->getScheduleData($id);
} catch (ErrorException $e) {
$this->addNotification($e->getMessage(), 'errors');
return back();
@ -219,6 +221,24 @@ class ImportSchedule extends BaseController
public function importSchedule(Request $request): Response
{
try {
$id = $request->getAttribute('id');
$this->doImport($id);
} catch (ErrorException $e) {
$this->addNotification($e->getMessage(), 'errors');
return back();
}
return redirect($this->url, 303)
->with('messages', ['schedule.import.success']);
}
/**
* @param string $id
*
* @throws ErrorException
*/
public function doImport(string $id): void
{
/**
* @var Event[] $newEvents
* @var Event[] $changeEvents
@ -234,11 +254,7 @@ class ImportSchedule extends BaseController
$newRooms,
$shiftType,
$scheduleUrl
) = $this->getScheduleData($request);
} catch (ErrorException $e) {
$this->addNotification($e->getMessage(), 'errors');
return back();
}
) = $this->getScheduleData($id);
$this->log('Started schedule "{name}" import', ['name' => $scheduleUrl->name]);
@ -274,9 +290,6 @@ class ImportSchedule extends BaseController
$scheduleUrl->touch();
$this->log('Ended schedule "{name}" import', ['name' => $scheduleUrl->name]);
return redirect($this->url, 303)
->with('messages', ['schedule.import.success']);
}
/**
@ -311,7 +324,7 @@ class ImportSchedule extends BaseController
'end' => $shift->getEndDate()->unix(),
'RID' => $room->id,
'URL' => $shift->getUrl(),
'created_by_user_id' => $user->id,
'created_by_user_id' => $user ? $user->id : null,
'created_at_timestamp' => time(),
'edited_by_user_id' => null,
'edited_at_timestamp' => 0,
@ -357,7 +370,7 @@ class ImportSchedule extends BaseController
'end' => $shift->getEndDate()->unix(),
'RID' => $room->id,
'URL' => $shift->getUrl(),
'edited_by_user_id' => $user->id,
'edited_by_user_id' => $user ? $user->id : null,
'edited_at_timestamp' => time(),
]
);
@ -397,13 +410,12 @@ class ImportSchedule extends BaseController
}
/**
* @param Request $request
* @param string $id
* @return Event[]|Room[]|RoomModel[]|ScheduleUrl|Schedule|string
* @throws ErrorException
*/
protected function getScheduleData(Request $request)
protected function getScheduleData(string $id)
{
$id = $request->getAttribute('id');
/** @var ScheduleUrl $scheduleUrl */
$scheduleUrl = ScheduleUrl::findOrFail($id);
@ -480,7 +492,7 @@ class ImportSchedule extends BaseController
$event->getDate()->subMinutes($minutesBefore);
$event->getEndDate()->addMinutes($minutesAfter);
$event->setTitle(sprintf('%s [%s]', $event->getTitle(), $event->getLanguage()));
//$event->setTitle(sprintf('%s [%s]', $event->getTitle(), $event->getLanguage()));
}
}
}

@ -311,7 +311,7 @@ function view_user_shifts()
function ical_hint()
{
$user = auth()->user();
if(!auth()->can('ical')) {
if(!config('enable_shifts_export') || !auth()->can('ical')) {
return '';
}

@ -177,7 +177,7 @@ function form_checkbox($name, $label, $selected, $value = 'checked', $html_id =
$html_id = $name;
}
return '<div class="checkbox"><label>'
return '<div class="checkbox mb-3"><label>'
. '<input type="checkbox" id="' . $html_id . '" name="' . $name . '" value="' . htmlspecialchars((string)$value) . '" '
. ($selected ? ' checked="checked"' : '') . ' /> '
. $label

@ -138,8 +138,8 @@ function ShiftEntry_create_view_user($shift, Room $room, $angeltype, $comment)
Shift_view_header($shift, $room),
info(sprintf(__('Do you want to sign up for this shift as %s?'), AngelType_name_render($angeltype)), true),
form([
form_textarea('comment', __('Comment (for your eyes only):'), $comment),
form_submit('submit', icon('check-lg') . __('Save'))
//form_textarea('comment', __('Comment (for your eyes only):'), $comment),
form_element(null, form_submit('submit', icon('check-lg') . __('Save'), 'btn-lg', false), '', 'd-grid'),
])
]);
}

@ -609,6 +609,7 @@ function User_view(
}
}
$enable_export = config('enable_shifts_export');
return page_with_title(
'<span class="icon-icon_angel"></span> '
. (
@ -656,15 +657,15 @@ function User_view(
page_link_to('user_settings'),
icon('gear') . __('Settings')
) : '',
($its_me && $auth->can('ical')) ? button(
($its_me && $enable_export && $auth->can('ical')) ? button(
page_link_to('ical', ['key' => $user_source->api_key]),
icon('calendar3') . __('iCal Export')
) : '',
($its_me && $auth->can('shifts_json_export')) ? button(
($its_me && $enable_export && $auth->can('shifts_json_export')) ? button(
page_link_to('shifts_json_export', ['key' => $user_source->api_key]),
icon('box-arrow-up-right') . __('JSON Export')
) : '',
($its_me && (
($its_me && $enable_export && (
$auth->can('shifts_json_export')
|| $auth->can('ical')
|| $auth->can('atom')
@ -675,18 +676,18 @@ function User_view(
])
])
]),
div('row user-info', [
div('col-md-2', [
($its_me || $admin_user_privilege) ? div('row user-info', [
config('enable_dect') ? div('col-md-2 mb-3', [
heading(icon('phone')
. '<a href="tel:' . $user_source->contact->dect . '">'
. $user_source->contact->dect, 1)
. '</a>'
]),
]) : '',
User_view_state($admin_user_privilege, $freeloader, $user_source),
User_angeltypes_render($user_angeltypes),
User_groups_render($user_groups),
$admin_user_privilege ? User_angeltypes_render($user_angeltypes) : '',
$admin_user_privilege ? User_groups_render($user_groups) : '',
$admin_user_privilege ? User_oauth_render($user_source) : '',
]),
]) : '',
($its_me || $admin_user_privilege) ? '<h2>' . __('Shifts') . '</h2>' : '',
$myshifts_table,
($its_me && $nightShiftsConfig['enabled']) ? info(
@ -703,7 +704,7 @@ function User_view(
page_link_to('user_shifts')
), true)
: '',
$its_me ? ical_hint() : ''
$its_me && $enable_export ? ical_hint() : ''
]
);
}
@ -724,7 +725,7 @@ function User_view_state($admin_user_privilege, $freeloader, $user_source)
$state = User_view_state_user($user_source);
}
return div('col-md-2', [
return div('col-md-2 mb-3', [
heading(__('User state'), 4),
join('<br>', $state)
]);
@ -829,7 +830,7 @@ function User_angeltypes_render($user_angeltypes)
. ($angeltype['supporter'] ? icon('patch-check') : '') . $angeltype['name']
. '</a>';
}
return div('col-md-2', [
return div('col-md-2 mb-3', [
heading(__('Angeltypes'), 4),
join('<br>', $output)
]);
@ -847,7 +848,7 @@ function User_groups_render($user_groups)
$output[] = __($groupName);
}
return div('col-md-2', [
return div('col-md-2 mb-3', [
'<h4>' . __('Rights') . '</h4>',
join('<br>', $output)
]);
@ -874,7 +875,7 @@ function User_oauth_render(User $user)
return '';
}
return div('col-md-2', [
return div('col-md-2 mb-3', [
heading(__('OAuth'), 4),
join('<br>', $output),
]);

@ -1,5 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="full" width="135mm" height="135mm">
<g transform="rotate(180 255.7 239.5)">
<path d="m262.16 408.63c-70.507 0-127.66-66.46-127.66-148.44 0-45.996 17.956-87.059 46.202-114.29v-34.156l-179.95-52.779v-100.51l510.58-0.01416 0.0743 96.124-165.36 59.377h-2.432v31.957c28.247 27.228 46.202 68.291 46.202 114.29 0 81.983-57.157 148.44-127.66 148.44zm0 70.373c-124.23 0-224.93-40.861-224.93-91.265s100.71-91.265 224.93-91.265 224.93 40.861 224.93 91.265-100.71 91.265-224.93 91.265zm0-46.182c102.74 0 186.02-28.553 186.02-63.775s-83.286-63.776-186.02-63.776c-102.74 0-186.02 28.553-186.02 63.776s83.286 63.775 186.02 63.775z"/>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="28.00242mm" width="28.00242mm"><path style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none" d="M 25.83203,27.114244 C 11.6334,27.114244 0,38.747274 0,52.946274 c 0,14.19863 11.6334,25.775401 25.83203,25.775401 14.19875,0 25.77539,-11.576771 25.77539,-25.775401 0,-14.199 -11.57664,-25.83203 -25.77539,-25.83203 z m 54.22656,0 c -14.19863,0 -25.83008,11.63303 -25.83008,25.83203 0,14.19863 11.63145,25.775401 25.83008,25.775401 14.19875,0 25.77734,-11.576771 25.77734,-25.775401 0,-14.199 -11.57859,-25.83203 -25.77734,-25.83203 z m -62.14453,7.75391 h 6.16992 l 18.07617,18.07812 -18.02148,18.01953 h -6.28125 l 18.07617,-18.01953 z m 64.00195,0.0547 h 6.28125 l -18.07617,18.07618 18.07617,18.02148 H 81.9707 L 63.94921,52.999034 Z"/></svg>

Before

Width:  |  Height:  |  Size: 714 B

After

Width:  |  Height:  |  Size: 869 B

@ -0,0 +1,135 @@
msgid ""
msgstr ""
"Project-Id-Version: Engelsystem 2.0\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Last-Translator: \n"
"Language: de_DE\n"
msgid "auth.not-found"
msgstr ""
"Es wurde kein Benutzer gefunden oder das Passwort ist falsch. Probiere es bitte noch einmal. Wenn das Problem "
"weiterhin besteht, melde dich beim Infopoint."
msgid "validation.password.required"
msgstr "Bitte gib ein Passwort an."
msgid "validation.login.required"
msgstr "Bitte gib einen Benutzernamen an."
msgid "validation.email.required"
msgstr "Bitte gib eine E-Mail-Adresse an."
msgid "validation.email.email"
msgstr "Die E-Mail-Adresse ist nicht gültig."
msgid "validation.password.min"
msgstr "Dein neues Passwort ist zu kurz."
msgid "validation.new_password.min"
msgstr "Dein neues Passwort ist zu kurz."
msgid "validation.password.confirmed"
msgstr "Deine Passwörter stimmen nicht überein."
msgid "validation.password_confirmation.required"
msgstr "Du musst dein Passwort bestätigen."
msgid "schedule.edit.success"
msgstr "Das Programm wurde erfolgreich konfiguriert."
msgid "schedule.import"
msgstr "Programm importieren"
msgid "schedule.import.request-error"
msgstr "Das Programm konnte nicht abgerufen werden."
msgid "schedule.import.read-error"
msgstr "Das Programm konnte nicht gelesen werden."
msgid "schedule.import.invalid-shift-type"
msgstr "Der Schichttyp konnte nicht gefunden werden."
msgid "schedule.import.success"
msgstr "Das Programm wurde erfolgreich importiert."
msgid "validation.schedule-url.required"
msgstr "Bitte gib eine Programm-URL an."
msgid "validation.schedule-url.url"
msgstr "Die Programm-URL muss eine URL sein."
msgid "validation.shift-type.required"
msgstr "Der Schichttyp ist erforderlich."
msgid "validation.shift-type.int"
msgstr "Der Schichttyp muss eine Zahl sein."
msgid "validation.minutes-before.int"
msgstr "Die Minuten vor dem Programmpunkt müssen eine Zahl sein."
msgid "validation.minutes-after.int"
msgstr "Die Minuten nach dem Programmpunkt müssen eine Zahl sein."
msgid "news.comment.success"
msgstr "Kommentar gespeichert"
msgid "news.comment-delete.success"
msgstr "Kommentar erfolgreich gelöscht"
msgid "news.edit.success"
msgstr "News erfolgreich aktualisiert"
msgid "news.delete.success"
msgstr "News erfolgreich gelöscht"
msgid "oauth.invalid-state"
msgstr "Ungültiger OAuth-Status"
msgid "oauth.provider-error"
msgstr "Login-Provider-Fehler"
msgid "oauth.already-connected"
msgstr "Dieser Account wurde bereits mit einem anderen Helfer*innen-Benutzer verbunden."
msgid "oauth.connected"
msgstr "Login-Provider verbunden"
msgid "oauth.disconnected"
msgstr "Login-Provider getrennt"
msgid "oauth.not-found"
msgstr "Account nicht gefunden"
msgid "oauth.provider-not-found"
msgstr "OAuth-Provider nicht gefunden"
msgid "settings.profile"
msgstr "Profil"
msgid "settings.password.success"
msgstr "Passwort wurde erfolgreich geändert"
msgid "faq.delete.success"
msgstr "FAQ-Eintrag erfolgreich gelöscht"
msgid "faq.edit.success"
msgstr "FAQ-Eintrag erfolgreich aktualisiert"
msgid "question.delete.success"
msgstr "Frage erfolgreich gelöscht"
msgid "question.add.success"
msgstr "Frage erstellt"
msgid "question.edit.success"
msgstr "Frage erfolgreich bearbeitet"
msgid "notification.news.new"
msgstr "Neuer Newspost: %s"
msgid "user.edit.success"
msgstr "Benutzer erfolgreich bearbeitet"

File diff suppressed because it is too large Load Diff

@ -9,6 +9,7 @@
<meta name="csrf-token" content="{{ csrf_token() }}">
<link rel="stylesheet" type="text/css" href="{{ asset('assets/theme' ~ themeId ~ '.css') }}"/>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<script type="text/javascript" src="{{ asset('assets/vendor.js') }}"></script>
{% if page() in ['news', 'meetings'] and is_user() and has_permission_to('atom') -%}

@ -39,7 +39,7 @@
{{ _self.toolbar_item(__('Register'), url('register'), 'register', 'plus') }}
{% endif %}
{% if has_permission_to('login') %}
{% if is_guest() and has_permission_to('login') %}
{{ _self.toolbar_item(__('login.login'), url('login'), 'login', 'box-arrow-in-right') }}
{% endif %}

@ -28,6 +28,22 @@
{% endfor %}
</div>
<div class="row mb-5">
<div class="col text-center">
<h2>{{ __('Register') }}</h2>
{% if has_permission_to('register') and config('registration_enabled') %}
{% if config('enable_password') %}
<p>{{ __('Please sign up, if you want to help us!') }}</p>
<a href="{{ url('register') }}" class="btn btn-primary">{{ __('Register') }} &raquo;</a>
{% else %}
<p>{{ __('Registration is only available via external login.') }}</p>
{% endif %}
{% else %}
{{ m.alert(__('Registration is disabled.'), 'danger') }}
{% endif %}
</div>
</div>
<div class="row mb-5">
<div class="col-md-6 offset-md-3 col-lg-4 offset-lg-4">
<div class="card {{ m.type_bg_class() }}">
@ -95,33 +111,5 @@
</div>
</div>
</div>
<div class="row mb-5">
<div class="col-sm-6 text-center">
<h2>{{ __('Register') }}</h2>
{% if has_permission_to('register') and config('registration_enabled') %}
{% if config('enable_password') %}
<p>{{ __('Please sign up, if you want to help us!') }}</p>
<a href="{{ url('register') }}" class="btn btn-primary">{{ __('Register') }} &raquo;</a>
{% else %}
<p>{{ __('Registration is only available via external login.') }}</p>
{% endif %}
{% else %}
{{ m.alert(__('Registration is disabled.'), 'danger') }}
{% endif %}
</div>
<div class="col-sm-6 text-center">
<h2>{{ __('What can I do?') }}</h2>
<p>{{ __('Please read about the jobs you can do to help us.') }}</p>
<a href="{{ url('angeltypes', {'action': 'about'}) }}" class="btn btn-primary">
{{ __('Teams/Job description') }} &raquo;
</a>
</div>
<div class="col-md-12 text-center">
{{ m.icon('info-circle') }} {{ __('Please note: You have to activate cookies!') }}
</div>
</div>
</div>
{% endblock %}

@ -62,6 +62,10 @@ class AuthController extends BaseController
*/
public function login(): Response
{
if ($this->auth->user()) {
return $this->redirect->to($this->config->get('home_site'));
}
return $this->showLogin();
}
@ -84,6 +88,10 @@ class AuthController extends BaseController
*/
public function postLogin(Request $request): Response
{
if ($this->auth->user()) {
return $this->redirect->to($this->config->get('home_site'));
}
$data = $this->validate($request, [
'login' => 'required',
'password' => 'required',

Loading…
Cancel
Save