more localization & yarn install script

This commit is contained in:
Roman 2022-12-02 13:52:24 +01:00
parent 963088e9b8
commit b1059717c7
13 changed files with 103 additions and 27 deletions

@ -106,6 +106,28 @@ namespace Documents\Install {
return NULL; return NULL;
} }
private function yarnInstall(string $reactDir): array {
$fds = [
"1" => ["pipe", "w"],
"2" => ["pipe", "w"],
];
$proc = proc_open("yarn install --frozen-lockfile --non-interactive", $fds, $pipes, $reactDir);
$output = stream_get_contents($pipes[1]) . stream_get_contents($pipes[2]);
$status = proc_close($proc);
return [$status, $output];
}
private function yarnBuild(string $reactDir): array {
$fds = [
"1" => ["pipe", "w"],
"2" => ["pipe", "w"],
];
$proc = proc_open("yarn run build", $fds, $pipes, $reactDir);
$output = stream_get_contents($pipes[1]) . stream_get_contents($pipes[2]);
$status = proc_close($proc);
return [$status, $output];
}
private function composerInstall(bool $dryRun = false): array { private function composerInstall(bool $dryRun = false): array {
$command = "composer install"; $command = "composer install";
if ($dryRun) { if ($dryRun) {
@ -159,6 +181,8 @@ namespace Documents\Install {
} }
} }
// TODO: check
$context = $this->getDocument()->getContext(); $context = $this->getDocument()->getContext();
$config = $context->getConfig(); $config = $context->getConfig();
@ -248,6 +272,11 @@ namespace Documents\Install {
$success = false; $success = false;
} }
if (!$this->command_exist("yarn")) {
$failedRequirements[] = "<b>Yarn</b> is not installed or cannot be found.";
$success = false;
}
if (!$success) { if (!$success) {
$msg = "The following requirements failed the check:<br>" . $msg = "The following requirements failed the check:<br>" .
$this->createUnorderedList($failedRequirements); $this->createUnorderedList($failedRequirements);
@ -259,6 +288,14 @@ namespace Documents\Install {
private function installDependencies(): array { private function installDependencies(): array {
list ($status, $output) = $this->composerInstall(); list ($status, $output) = $this->composerInstall();
if ($status === 0) {
$reactDir = implode(DIRECTORY_SEPARATOR, [WEBROOT, "react"]);
list ($status, $output) = $this->yarnInstall($reactDir);
if ($status === 0) {
list ($status, $output) = $this->yarnBuild($reactDir);
}
}
return ["success" => $status === 0, "msg" => $output]; return ["success" => $status === 0, "msg" => $output];
} }

@ -1,19 +1,32 @@
<?php <?php
return [ return [
"title" => "Account",
"login_title" => "Einloggen", "login_title" => "Einloggen",
"login_description" => "Loggen Sie sich in Ihren Account ein", "login_description" => "Loggen Sie sich in Ihren Account ein",
"accept_invite_title" => "Einladung",
"accept_invite_description" => "Schließen Sie die Registrierung ab indem Sie ein Passwort wählen",
"confirm_email_title" => "E-Mail Adresse bestätigen",
"confirm_email_description" => "Schließen Sie die Registrierung ab indem Sie Ihre E-Mail Adresse bestätigen",
"form_title" => "Bitte geben Sie ihre Daten ein", "form_title" => "Bitte geben Sie ihre Daten ein",
"username" => "Benutzername", "username" => "Benutzername",
"username_or_email" => "Benutzername oder E-Mail", "username_or_email" => "Benutzername oder E-Mail",
"email" => "E-Mail Adresse",
"password" => "Passwort", "password" => "Passwort",
"password_confirm" => "Passwort bestätigen",
"remember_me" => "Eingeloggt bleiben", "remember_me" => "Eingeloggt bleiben",
"signing_in" => "Einloggen", "signing_in" => "Einloggen",
"sign_in" => "Einloggen", "sign_in" => "Einloggen",
"forgot_password" => "Passwort vergessen?", "forgot_password" => "Passwort vergessen?",
"passwords_do_not_match" => "Die Passwörter stimmen nicht überein", "passwords_do_not_match" => "Die Passwörter stimmen nicht überein",
"back_to_login" => "Zurück zum Login",
"register_text" => "Noch keinen Account? Jetzt registrieren", "register_text" => "Noch keinen Account? Jetzt registrieren",
"6_digit_code" => "6-stelliger Code", "6_digit_code" => "6-stelliger Code",
"2fa_title" => "Es werden weitere Informationen zum Einloggen benötigt", "2fa_title" => "Es werden weitere Informationen zum Einloggen benötigt",
"2fa_text" => "Stecke dein 2FA-Gerät ein. Möglicherweise wird noch eine Interaktion benötigt, z.B. durch Eingabe einer PIN oder durch Berühren des Geräts", "2fa_text" => "Stecke dein 2FA-Gerät ein. Möglicherweise wird noch eine Interaktion benötigt, z.B. durch Eingabe einer PIN oder durch Berühren des Geräts",
"confirming_email" => "Bestätige E-Mail Adresse",
"proceed_to_login" => "Weiter zum Login",
"invalid_link" => "Den Link den Sie besucht haben ist nicht länger gültig",
"confirm_success" => "Ihre E-Mail Adresse wurde erfolgreich bestätigt, Sie können sich jetzt einloggen",
"confirm_error" => "Fehler beim Bestätigen der E-Mail Adresse",
]; ];

@ -1,6 +1,7 @@
<?php <?php
return [ return [
"title" => "Administration",
"dashboard" => "Dashboard", "dashboard" => "Dashboard",
"visitor_statistics" => "Besucherstatistiken", "visitor_statistics" => "Besucherstatistiken",
"user_groups" => "Benutzer & Gruppen", "user_groups" => "Benutzer & Gruppen",

@ -10,4 +10,5 @@ return [
"language" => "Sprache", "language" => "Sprache",
"loading" => "Laden", "loading" => "Laden",
"logout" => "Ausloggen", "logout" => "Ausloggen",
"noscript" => "Sie müssen Javascript aktivieren um diese Anwendung zu benutzen",
]; ];

@ -1,19 +1,32 @@
<?php <?php
return [ return [
"title" => "Sign In", "title" => "Account",
"description" => "Sign In into your account", "login_title" => "Sign In",
"login_description" => "Sign In into your account",
"accept_invite_title" => "Invitation",
"accept_invite_description" => "Complete your account registration by choosing a password",
"confirm_email_title" => "Confirm Email",
"confirm_email_description" => "Complete your registration by confirming the e-mail address",
"form_title" => "Please fill with your details", "form_title" => "Please fill with your details",
"username" => "Username", "username" => "Username",
"username_or_email" => "Username or E-Mail", "username_or_email" => "Username or E-Mail",
"email" => "E-Mail Address",
"password" => "Password", "password" => "Password",
"password_confirm" => "Confirm Password",
"remember_me" => "Remember Me", "remember_me" => "Remember Me",
"signing_in" => "Signing in", "signing_in" => "Signing in",
"sign_in" => "Sign In", "sign_in" => "Sign In",
"forgot_password" => "Forgot password?", "forgot_password" => "Forgot password?",
"register_text" => "Don't have an account? Sign Up", "register_text" => "Don't have an account? Sign Up",
"passwords_do_not_match" => "Your passwords did not match", "passwords_do_not_match" => "Your passwords did not match",
"back_to_login" => "Back to Login",
"6_digit_code" => "6-Digit Code", "6_digit_code" => "6-Digit Code",
"2fa_title" => "Additional information is required for logging in", "2fa_title" => "Additional information is required for logging in",
"2fa_text" => "Plugin your 2FA-Device. Interaction might be required, e.g. typing in a PIN or touching it." "2fa_text" => "Plugin your 2FA-Device. Interaction might be required, e.g. typing in a PIN or touching it.",
"confirming_email" => "Confirming email",
"proceed_to_login" => "Proceed to Login",
"invalid_link" => "The link you visited is no longer valid",
"confirm_success" => "Your e-mail address was successfully confirmed, you may now log in",
"confirm_error" => "Error confirming e-mail address",
]; ];

@ -1,6 +1,7 @@
<?php <?php
return [ return [
"title" => "Administration",
"dashboard" => "Dashboard", "dashboard" => "Dashboard",
"visitor_statistics" => "Visitor Statistics", "visitor_statistics" => "Visitor Statistics",
"user_groups" => "User & Groups", "user_groups" => "User & Groups",

@ -10,4 +10,5 @@ return [
"language" => "Language", "language" => "Language",
"loading" => "Loading", "loading" => "Loading",
"logout" => "Logout", "logout" => "Logout",
"noscript" => "You need Javascript enabled to run this app",
]; ];

@ -1,44 +1,48 @@
{% extends "account/account_base.twig" %} {% extends "account/account_base.twig" %}
{% set view_title = 'Invitation' %} {% set view_title = 'account.accept_invite_title' %}
{% set view_icon = 'user-check' %} {% set view_icon = 'user-check' %}
{% set view_description = 'Finnish your account registration by choosing a password.' %} {% set view_description = 'account.accept_invite_description' %}
{% block view_content %} {% block view_content %}
{% if not view.success %} {% if not view.success %}
<div class="alert alert-danger" role="alert">{{ view.message }}</div> <div class="alert alert-danger" role="alert">{{ view.message }}</div>
<a href='/login' class='btn btn-primary'>Back to login</a> <a href='/login' class='btn btn-primary'>{{ L("account.back_to_login") }}</a>
{% else %} {% else %}
<h4 class="pb-4">Please fill with your details</h4> <h4 class="pb-4">{{ L("account.form_title") }}</h4>
<form> <form>
<input name='token' id='token' type='hidden' value='{{ view.token }}'/> <input name='token' id='token' type='hidden' value='{{ view.token }}'/>
<div class="input-group"> <div class="input-group">
<div class="input-group-append"> <div class="input-group-append">
<span class="input-group-text"><i class="fas fa-hashtag"></i></span> <span class="input-group-text"><i class="fas fa-hashtag"></i></span>
</div> </div>
<input id="username" name="username" placeholder="Username" class="form-control" type="text" maxlength="32" value='{{ view.invited_user.name }}' disabled> <input id="username" name="username" placeholder="{{ L('account.username') }}"
class="form-control" type="text" maxlength="32" value='{{ view.invited_user.name }}' disabled>
</div> </div>
<div class="input-group mt-3"> <div class="input-group mt-3">
<div class="input-group-append"> <div class="input-group-append">
<span class="input-group-text"><i class="fas fa-at"></i></span> <span class="input-group-text"><i class="fas fa-at"></i></span>
</div> </div>
<input type="email" name='email' id='email' class="form-control" placeholder="Email" maxlength="64" value='{{ view.invited_user.email }}' disabled> <input type="email" name='email' id='email' class="form-control"
placeholder="{{ L('account.email') }}" maxlength="64" value='{{ view.invited_user.email }}' disabled>
</div> </div>
<div class="input-group mt-3"> <div class="input-group mt-3">
<div class="input-group-append"> <div class="input-group-append">
<span class="input-group-text"><i class="fas fa-key"></i></span> <span class="input-group-text"><i class="fas fa-key"></i></span>
</div> </div>
<input type="password" autocomplete='new-password' name='password' id='password' class="form-control" placeholder="Password"> <input type="password" autocomplete='new-password' name='password'
id='password' class="form-control" placeholder="{{ L('account.password') }}">
</div> </div>
<div class="input-group mt-3"> <div class="input-group mt-3">
<div class="input-group-append"> <div class="input-group-append">
<span class="input-group-text"><i class="fas fa-key"></i></span> <span class="input-group-text"><i class="fas fa-key"></i></span>
</div> </div>
<input type="password" autocomplete='new-password' name='confirmPassword' id='confirmPassword' class="form-control" placeholder="Confirm Password"> <input type="password" autocomplete='new-password' name='confirmPassword'
id='confirmPassword' class="form-control" placeholder="{{ L('account.password_confirm') }}">
</div> </div>
<div class="input-group mt-3"> <div class="input-group mt-3">
<button type="button" class="btn btn-success" id='btnAcceptInvite'>Submit</button> <button type="button" class="btn btn-success" id='btnAcceptInvite'>{{ L("general.submit") }}</button>
</div> </div>
</form> </form>
{% endif %} {% endif %}

@ -8,7 +8,7 @@
<script src="/js/bootstrap.bundle.min.js" nonce="{{ site.csp.nonce }}"></script> <script src="/js/bootstrap.bundle.min.js" nonce="{{ site.csp.nonce }}"></script>
<link rel="stylesheet" href="/css/fontawesome.min.css" nonce="{{ site.csp.nonce }}"> <link rel="stylesheet" href="/css/fontawesome.min.css" nonce="{{ site.csp.nonce }}">
<link rel="stylesheet" href="/css/account.css" nonce="{{ site.csp.nonce }}"> <link rel="stylesheet" href="/css/account.css" nonce="{{ site.csp.nonce }}">
<title>Account - {{ L(view_title) }}</title> <title>{{ L("account.title")}} - {{ L(view_title) }}</title>
{% if site.recaptcha.enabled %} {% if site.recaptcha.enabled %}
<script src="https://www.google.com/recaptcha/api.js?render={{ site.recaptcha.key }}" nonce="{{ site.csp.nonce }}"></script> <script src="https://www.google.com/recaptcha/api.js?render={{ site.recaptcha.key }}" nonce="{{ site.csp.nonce }}"></script>
{% endif %} {% endif %}

@ -1,17 +1,21 @@
{% extends "account/account_base.twig" %} {% extends "account/account_base.twig" %}
{% set view_title = 'Confirm Email' %} {% set view_title = 'account.confirm_email_title' %}
{% set view_icon = 'user-check' %} {% set view_icon = 'user-check' %}
{% set view_description = 'Request a password reset, once you got the e-mail address, you can choose a new password' %} {% set view_description = 'account.confirm_email_description' %}
{% block view_content %} {% block view_content %}
<noscript> <noscript>
<div class="alert alert-danger">Javascript is required</div> <div class="alert alert-danger">{{ L('general.noscript') }}</div>
</noscript> </noscript>
<div class="alert alert-info" id="confirm-status"> <div class="alert alert-info" id="confirm-status">
Confirming email… <i class="fas fa-spinner fa-spin"></i> {{ L('account.confirming_email') }}… <i class="fas fa-spinner fa-spin"></i>
</div> </div>
<a href='/login'><button class='btn btn-primary' style='position: absolute; bottom: 10px' type='button'>Proceed to Login</button></a> <a href='/login'>
<button class='btn btn-primary' style='position: absolute; bottom: 30px' type='button'>
{{ L("account.proceed_to_login") }}
</button>
</a>
<script nonce="{{ site.csp.nonce }}"> <script nonce="{{ site.csp.nonce }}">
$(document).ready(function() { $(document).ready(function() {
let token = jsCore.getParameter("token"); let token = jsCore.getParameter("token");
@ -21,16 +25,16 @@
confirmStatus.removeClass("alert-info"); confirmStatus.removeClass("alert-info");
if (!res.success) { if (!res.success) {
confirmStatus.addClass("alert-danger"); confirmStatus.addClass("alert-danger");
confirmStatus.text("Error confirming e-mail address: " + res.msg); confirmStatus.text("{{ L('account.confirm_error') }}: " + res.msg);
} else { } else {
confirmStatus.addClass("alert-success"); confirmStatus.addClass("alert-success");
confirmStatus.text("Your e-mail address was successfully confirmed, you may now log in."); confirmStatus.text("{{ L('account.confirm_success') }}");
} }
}); });
} else { } else {
confirmStatus.removeClass("alert-info"); confirmStatus.removeClass("alert-info");
confirmStatus.addClass("alert-danger"); confirmStatus.addClass("alert-danger");
confirmStatus.text("The link you visited is no longer valid"); confirmStatus.text("{{ L('account.invalid_link') }}");
} }
}); });
</script> </script>

@ -1,8 +1,8 @@
{% extends "account/account_base.twig" %} {% extends "account/account_base.twig" %}
{% set view_title = 'account.title' %} {% set view_title = 'account.login_title' %}
{% set view_icon = 'user-lock' %} {% set view_icon = 'user-lock' %}
{% set view_description = 'account.description' %} {% set view_description = 'account.login_description' %}
{% block view_content %} {% block view_content %}

@ -1,12 +1,12 @@
{% extends "base.twig" %} {% extends "base.twig" %}
{% block head %} {% block head %}
<title>{{ site.name }} - Administration</title> <title>{{ site.name }} - {{ L("admin.admin") }}</title>
<link rel="stylesheet" href="/css/fontawesome.min.css" nonce="{{ site.csp.nonce }}"> <link rel="stylesheet" href="/css/fontawesome.min.css" nonce="{{ site.csp.nonce }}">
{% endblock %} {% endblock %}
{% block body %} {% block body %}
<noscript>You need Javascript enabled to run this app</noscript> <noscript>{{ L("general.noscript") }}</noscript>
<div type="module" id="admin-panel"></div> <div type="module" id="admin-panel"></div>
<script src="/react/dist/admin-panel/index.js" nonce="{{ site.csp.nonce }}"></script> <script src="/react/dist/admin-panel/index.js" nonce="{{ site.csp.nonce }}"></script>
<link rel="stylesheet" href="/react/dist/admin-panel/index.css" nonce="{{ site.csp.nonce }}"></link> <link rel="stylesheet" href="/react/dist/admin-panel/index.css" nonce="{{ site.csp.nonce }}"></link>

@ -7,10 +7,11 @@ RUN mkdir -p /application/core/Configuration /var/www/.gnupg && \
# YAML + dev dependencies # YAML + dev dependencies
RUN apt-get update -y && \ RUN apt-get update -y && \
apt-get install -y libyaml-dev libzip-dev libgmp-dev libpng-dev gnupg2d && \ apt-get install -y libyaml-dev libzip-dev libgmp-dev libpng-dev gnupg2d nodejs npm && \
apt-get clean && \ apt-get clean && \
pecl install yaml && docker-php-ext-enable yaml && \ pecl install yaml && docker-php-ext-enable yaml && \
docker-php-ext-install gd docker-php-ext-install gd && \
npm install --global yarn && ln -s /usr/local/bin/yarn /usr/bin/yarn
# Runkit (no stable release available) # Runkit (no stable release available)
RUN pecl install runkit7-4.0.0a3 && docker-php-ext-enable runkit7 && \ RUN pecl install runkit7-4.0.0a3 && docker-php-ext-enable runkit7 && \