Remove home screen widgets, build new i18n system, close #4

V2_Rewrite
Skylar Ittner 6 years ago
parent 3d309ac68b
commit deca0d330d

@ -1,24 +0,0 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
dieifnotloggedin();
addMultiLangStrings(["en_us" => [
"manage account security" => "Manage account security",
"manage security description" => "Review security features or change your password."
]
]);
$APPS["account_security"]["i18n"] = TRUE;
$APPS["account_security"]["title"] = "account security";
$APPS["account_security"]["icon"] = "lock";
$APPS["account_security"]["type"] = "brown";
$content = "<p>"
. lang("manage security description", false)
. '</p> '
. '<a href="home.php?page=security" class="btn btn-primary btn-block">'
. lang("manage account security", false)
. '</a>';
$APPS["account_security"]["content"] = $content;
?>

@ -1,24 +0,0 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
dieifnotloggedin();
addMultiLangStrings(["en_us" => [
"inventory" => "Inventory",
"open inventory system" => "Open the inventory system"
]
]);
$APPS["inventory_link"]["i18n"] = TRUE;
$APPS["inventory_link"]["title"] = "inventory";
$APPS["inventory_link"]["icon"] = "cubes";
$APPS["inventory_link"]["type"] = "teal";
$content = "<p class='mobile-app-hide'>" . lang("open inventory system", false) . '</p><a href="' . INVENTORY_HOME . '" class="btn btn-primary btn-block mobile-app-hide">' . lang("open app", false) . ' &nbsp;<i class="fa fa-external-link-square"></i></a>';
$APPS["inventory_link"]["content"] = $content;
require_once __DIR__ . "/../lib/login.php";
if (account_has_permission($_SESSION['username'], "INV_VIEW") !== true) {
unset($APPS['inventory_link']);
}
?>

@ -1,61 +0,0 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
dieifnotloggedin();
require_once __DIR__ . "/../lib/login.php";
addMultiLangStrings(["en_us" => [
"qwikclock" => "QwikClock",
"punch in" => "Punch in",
"punch out" => "Punch out",
"permission denied" => "You do not have permission to do that."
]
]);
$APPS["qwikclock_inout"]["i18n"] = TRUE;
$APPS["qwikclock_inout"]["title"] = "qwikclock";
$APPS["qwikclock_inout"]["icon"] = "clock-o";
$APPS["qwikclock_inout"]["type"] = "blue";
$content = "";
use GuzzleHttp\Exception\ClientException;
if (!is_empty($_GET['qwikclock']) && ($_GET['qwikclock'] === "punchin" || $_GET['qwikclock'] === "punchout")) {
try {
$client = new GuzzleHttp\Client();
$response = $client->request('POST', QWIKCLOCK_API, ['form_params' => [
'action' => $_GET['qwikclock'],
'username' => $_SESSION['username'],
'password' => $_SESSION['password']
]]);
$resp = json_decode($response->getBody(), TRUE);
if ($resp['status'] == "OK") {
$content = "<div class=\"alert alert-success alert-dismissable\"><button type=\"button\" class=\"close\">&times;</button>" . $resp['msg'] . "</div>";
} else {
$content = "<div class=\"alert alert-danger alert-dismissable\"><button type=\"button\" class=\"close\">&times;</button>" . $resp['msg'] . "</div>";
}
} catch (ClientException $e) {
if ($e->getResponse()->getStatusCode() == 403) {
$content = "<div class=\"alert alert-danger alert-dismissable\"><button type=\"button\" class=\"close\">&times;</button>" . lang("permission denied", false) . "</div>";
}
} catch (Exception $e) {
$content = "<div class=\"alert alert-danger alert-dismissable\"><button type=\"button\" class=\"close\">&times;</button>" . lang("error loading widget", false) . " " . $e->getMessage() . "</div>";
}
}
$lang_punchin = lang("punch in", false);
$lang_punchout = lang("punch out", false);
$content .= <<<END
<a href="home.php?&qwikclock=punchin" class="btn btn-block btn-success btn-lg"><i class="fa fa-play"></i> $lang_punchin</a>
<a href="home.php?qwikclock=punchout" class="btn btn-block btn-danger btn-lg"><i class="fa fa-stop"></i> $lang_punchout</a>
END;
$content .= '<br /><a href="' . QWIKCLOCK_HOME . '" class="btn btn-primary btn-block mobile-app-hide">' . lang("open app", false) . ' &nbsp;<i class="fa fa-external-link-square"></i></a>';
$APPS["qwikclock_inout"]["content"] = $content;
if (account_has_permission($_SESSION['username'], "QWIKCLOCK") !== true) {
unset($APPS['qwikclock_inout']);
}
?>

@ -1,34 +0,0 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
dieifnotloggedin();
// Additional i18n strings
addMultiLangStrings(["en_us" => [
"sample app" => "Sample Application",
]
]);
// Set to true to automatically parse the app title as a language string.
$APPS["sample_app"]["i18n"] = TRUE;
// App title.
$APPS["sample_app"]["title"] = "sample app";
// App icon, from FontAwesome.
$APPS["sample_app"]["icon"] = "rocket";
// App content.
$APPS["sample_app"]["content"] = <<<'CONTENTEND'
<div class="list-group">
<div class="list-group-item">
Item 1
</div>
<div class="list-group-item">
Item 2
</div>
<div class="list-group-item">
Item 3
</div>
</div>
CONTENTEND;
?>

@ -10,19 +10,6 @@ use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\QrCode;
if (MOBILE_ENABLED) {
addMultiLangStrings(["en_us" => [
"sync mobile" => "Sync Mobile App",
"scan sync qrcode" => "Scan this code with the mobile app or enter the code manually.",
"sync explained" => "Access your account and apps on the go. Use a sync code to securely connect your phone or tablet to AccountHub with the Netsyms Business mobile app.",
"generate sync" => "Create new sync code",
"active sync codes" => "Active codes",
"no active codes" => "No active codes.",
"done adding sync code" => "Done adding code",
"manual setup" => "Manual Setup:",
"sync key" => "Sync key:",
"url" => "URL:",
]
]);
$APPS["sync_mobile"]["title"] = lang("sync mobile", false);
$APPS["sync_mobile"]["icon"] = "mobile";

@ -1,67 +0,0 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
dieifnotloggedin();
addMultiLangStrings(["en_us" => [
"messages" => "Messages",
"no messages" => "No messages found."
]
]);
$APPS["taskfloor_messages"]["i18n"] = TRUE;
$APPS["taskfloor_messages"]["title"] = "messages";
$APPS["taskfloor_messages"]["icon"] = "comments";
$APPS["taskfloor_messages"]["type"] = "deep-purple";
$content = "";
use GuzzleHttp\Exception\ClientException;
try {
$client = new GuzzleHttp\Client();
$response = $client->request('POST', TASKFLOOR_API, ['form_params' => [
'action' => "getmsgs",
'username' => $_SESSION['username'],
'password' => $_SESSION['password'],
'max' => 5
]]);
$resp = json_decode($response->getBody(), TRUE);
if ($resp['status'] == "OK") {
if (count($resp['messages']) > 0) {
$content = '<div class="list-group">';
foreach ($resp['messages'] as $msg) {
$content .= '<div class="list-group-item">';
$content .= $msg['text'];
$fromuser = $msg['from']['username'];
$fromname = $msg['from']['name'];
$touser = $msg['to']['username'];
$toname = $msg['to']['name'];
$content .= <<<END
<br />
<span class="small">
<span data-toggle="tooltip" title="$fromuser">$fromname</span>
<i class="fa fa-caret-right"></i>
<span data-toggle="tooltip" title="$touser">$toname</span>
</span>
END;
$content .= '</div>';
}
$content .= "</div>";
} else {
$content = "<div class=\"alert alert-info\">" . lang("no messages", false) . "</div>";
}
}
$content .= '<a href="' . TASKFLOOR_HOME . '" class="btn btn-primary btn-block mobile-app-hide">' . lang("open app", false) . ' &nbsp;<i class="fa fa-external-link-square"></i></a>';
$APPS["taskfloor_messages"]["content"] = $content;
} catch (ClientException $e) {
if ($e->getResponse()->getStatusCode() == 403) {
unset($APPS['taskfloor_messages']);
}
} catch (Exception $e) {
$content = "<div class=\"alert alert-danger\">" . lang("error loading widget", false) . " " . $e->getMessage() . "</div>";
$content .= '<a href="' . TASKFLOOR_HOME . '" class="btn btn-primary btn-block mobile-app-hide">' . lang("open app", false) . ' &nbsp;<i class="fa fa-external-link-square"></i></a>';
$APPS["taskfloor_messages"]["content"] = $content;
}
?>

@ -1,56 +0,0 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
dieifnotloggedin();
addMultiLangStrings(["en_us" => [
"tasks" => "Tasks",
"no tasks found" => "No tasks found."
]
]);
$APPS["taskfloor_tasks"]["i18n"] = TRUE;
$APPS["taskfloor_tasks"]["title"] = "tasks";
$APPS["taskfloor_tasks"]["icon"] = "tasks";
$APPS["taskfloor_tasks"]["type"] = "blue-grey";
$content = "";
use GuzzleHttp\Exception\ClientException;
try {
$client = new GuzzleHttp\Client();
$response = $client->request('POST', TASKFLOOR_API, ['form_params' => [
'action' => "gettasks",
'username' => $_SESSION['username'],
'password' => $_SESSION['password'],
'max' => 5
]]);
$resp = json_decode($response->getBody(), TRUE);
if ($resp['status'] == "OK") {
if (count($resp['tasks']) > 0) {
$content = '<div class="list-group">';
foreach ($resp['tasks'] as $task) {
$content .= '<div class="list-group-item">';
$content .= '<i class="fa fa-fw fa-' . $task['icon'] . '"></i> ' . $task['title'] . '';
$content .= '</div>';
}
$content .= "</div>";
} else {
$content = "<div class=\"alert alert-success\">" . lang("no tasks found", false) . "</div>";
}
}
$content .= '<a href="' . TASKFLOOR_HOME . '" class="btn btn-primary btn-block mobile-app-hide">' . lang("open app", false) . ' &nbsp;<i class="fa fa-external-link-square"></i></a>';
$APPS["taskfloor_tasks"]["content"] = $content;
} catch (ClientException $e) {
if ($e->getResponse()->getStatusCode() == 403) {
unset($APPS['taskfloor_tasks']);
}
} catch (Exception $e) {
$content = "<div class=\"alert alert-danger\">" . lang("error loading widget", false) . " " . $e->getMessage() . "</div>";
$content .= '<a href="' . TASKFLOOR_HOME . '" class="btn btn-primary btn-block mobile-app-hide">' . lang("open app", false) . ' &nbsp;<i class="fa fa-external-link-square"></i></a>';
$APPS["taskfloor_tasks"]["content"] = $content;
}
?>

@ -0,0 +1,16 @@
{
"setup 2fa": "Setup 2-factor authentication",
"2fa removed": "2-factor authentication disabled.",
"2fa enabled": "2-factor authentication activated.",
"remove 2fa": "Disable 2-factor authentication",
"2fa explained": "2-factor authentication adds more security to your account. You can use the Auth Keys (key icon) feature of the Netsyms Business Mobile app, or another TOTP-enabled app (Authy, FreeOTP, etc) on your smartphone. When you have the app installed, you can enable 2-factor authentication by clicking the button below and scanning a QR code with the app. Whenever you sign in in the future, you'll need to input a six-digit code from your phone into the login page when prompted. You can disable 2-factor authentication from this page if you change your mind.",
"2fa active": "2-factor authentication is active on your account. To remove 2fa, reset your authentication secret, or change to a new security device, click the button below.",
"enable 2fa": "Enable 2-factor authentication",
"scan 2fa qrcode": "Scan the QR Code with the authenticator app, or enter the information manually. Then type in the six-digit code the app gives you and press Finish Setup.",
"confirm 2fa": "Finish setup",
"enter otp code": "Enter 6-digit code",
"secret key": "Secret key",
"label": "Label",
"issuer": "Issuer",
"no such code or code expired": "That code is incorrect or expired."
}

@ -0,0 +1,3 @@
{
"user does not exist": "User does not exist."
}

@ -0,0 +1,26 @@
{
"sign in": "Sign In",
"username": "Username",
"password": "Password",
"continue": "Continue",
"authcode": "Authentication code",
"2fa prompt": "Enter the six-digit code from your mobile authenticator app.",
"2fa incorrect": "Authentication code incorrect.",
"login incorrect": "Login incorrect.",
"login server unavailable": "Login server unavailable. Try again later or contact technical support.",
"account locked": "This account has been disabled. Contact technical support.",
"password expired": "You must change your password before continuing.",
"account terminated": "Account terminated. Access denied.",
"account state error": "Your account state is not stable. Log out, restart your browser, and try again.",
"welcome user": "Welcome, {user}!",
"sign out": "Sign out",
"404 error": "404 Error",
"page not found": "Page not found.",
"invalid parameters": "Invalid request parameters.",
"login server error": "The login server returned an error: {arg}",
"login server user data error": "The login server refused to provide account information. Try again or contact technical support.",
"captcha error": "There was a problem with the CAPTCHA (robot test). Try again.",
"no access permission": "You do not have permission to access this system.",
"generic op error": "An unknown error occurred. Try again later.",
"home": "Home"
}

@ -0,0 +1,4 @@
{
"ldap server error": "The LDAP server returned an error: {arg}",
"ldap error": "LDAP error: {error}"
}

@ -0,0 +1,13 @@
{
"password on 500 list": "The given password is ranked number {arg} out of the 500 most common passwords. Try a different one.",
"change password": "Change password",
"current password incorrect": "The current password is incorrect. Try again.",
"new password mismatch": "The new passwords did not match. Try again.",
"weak password": "Password does not meet requirements.",
"password updated": "Password updated successfully.",
"current password": "Current password",
"new password": "New password",
"confirm password": "New password (again)",
"password complexity insufficent": "The new password does not meet the minumum requirements defined by your system administrator.",
"old and new passwords match": "Your current and new passwords are the same."
}

@ -0,0 +1,9 @@
{
"pin explanation": "Change or set a login PIN for the Station kiosk Quick Access. PIN codes must be between one and eight digits.",
"change pin": "Change PIN",
"new pin": "New PIN",
"confirm pin": "New PIN (again)",
"pin updated": "PIN updated.",
"new pin mismatch": "The new PINs don't match each other.",
"invalid pin format": "PIN codes must be numeric and between one and eight digits in length."
}

@ -0,0 +1,7 @@
{
"sign in again": "Please sign in again to continue.",
"login failed try on web": "There is a problem with your account. Visit AccountHub via a web browser for more information.",
"mobile login disabled": "Mobile login has been disabled by your system administrator. Contact technical support for more information.",
"admin alert email subject": "Alert: User login notification",
"admin alert email message": "You (or another administrator) requested to be notified when user \"{username}\" logged in, an event which happened just now.\r\n\r\nUsername: \t{username}\r\nApplication: \t{appname}\r\nDate\/Time: \t{datetime}\r\nIP address: \t{ipaddr}\r\n\r\nThese notifications can be disabled by editing the user in ManagePanel."
}

@ -0,0 +1,12 @@
{
"sync mobile": "Sync Mobile App",
"scan sync qrcode": "Scan this code with the mobile app or enter the code manually.",
"sync explained": "Access your account and apps on the go. Use a sync code to securely connect your phone or tablet to AccountHub with the Netsyms Business mobile app.",
"generate sync": "Create new sync code",
"active sync codes": "Active codes",
"no active codes": "No active codes.",
"done adding sync code": "Done adding code",
"manual setup": "Manual Setup:",
"sync key": "Sync key:",
"url": "URL:"
}

@ -0,0 +1,8 @@
{
"account security": "Account security",
"security options": "Security options",
"account options": "Account options",
"sync": "Sync settings",
"settings": "Settings",
"account": "Account"
}

@ -0,0 +1,118 @@
<?php
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/**
* Provides translated language strings.
*/
class Strings {
private $language = "en";
private $strings = [];
function __construct($language = "en") {
if (!preg_match("/[a-zA-Z\_\-]+/", $language)) {
throw new Exception("Invalid language code $language");
}
$this->load("en");
if (file_exists(__DIR__ . "/../langs/$language/")) {
$this->language = $language;
$this->load($language);
} else {
trigger_error("Language $language could not be found.", E_USER_WARNING);
}
}
/**
* Load all JSON files for the specified language.
* @param string $language
*/
private function load(string $language) {
$files = glob(__DIR__ . "/../langs/$language/*.json");
foreach ($files as $file) {
$strings = json_decode(file_get_contents($file), true);
foreach ($strings as $key => $val) {
if (array_key_exists($key, $this->strings)) {
trigger_error("Language key \"$key\" is defined more than once.", E_USER_WARNING);
}
$this->strings[$key] = $val;
}
}
}
/**
* Add language strings dynamically.
* @param array $strings ["key" => "value", ...]
*/
function addStrings(array $strings) {
foreach ($strings as $key => $val) {
$this->strings[$key] = $val;
}
}
/**
* I18N string getter. If the key isn't found, it outputs the key itself.
* @param string $key
* @param bool $echo True to echo the result, false to return it. Default is true.
* @return string
*/
function get(string $key, bool $echo = true): string {
$str = $key;
if (array_key_exists($key, $this->strings)) {
$str = $this->strings[$key];
} else {
trigger_error("Language key \"$key\" does not exist in " . $this->language, E_USER_WARNING);
}
if ($echo) {
echo $str;
}
return $str;
}
/**
* I18N string getter (with builder). If the key doesn't exist, outputs the key itself.
* @param string $key
* @param array $replace key-value array of replacements.
* If the string value is "hello {abc}" and you give ["abc" => "123"], the
* result will be "hello 123".
* @param bool $echo True to echo the result, false to return it. Default is true.
* @return string
*/
function build(string $key, array $replace, bool $echo = true): string {
$str = $key;
if (array_key_exists($key, $this->strings)) {
$str = $this->strings[$key];
} else {
trigger_error("Language key \"$key\" does not exist in " . $this->language, E_USER_WARNING);
}
foreach ($replace as $find => $repl) {
$str = str_replace("{" . $find . "}", $repl, $str);
}
if ($echo) {
echo $str;
}
return $str;
}
/**
* Builds and returns a JSON key:value string for the supplied array of keys.
* @param array $keys ["key1", "key2", ...]
*/
function getJSON(array $keys): string {
$strings = [];
foreach ($keys as $k) {
$strings[$k] = $this->get($k, false);
}
return json_encode($strings);
}
}

@ -30,13 +30,7 @@ define("PAGES", [
// Which apps to load on a given page
define("APPS", [
"home" => [
"taskfloor_tasks",
"qwikclock_inout",
"taskfloor_messages",
"inventory_link",
"account_security"
],
"home" => [],
"security" => [
"change_password",
"change_pin",

@ -62,7 +62,8 @@ if ($_SESSION['mobile'] === TRUE) {
// List of alert messages
require __DIR__ . '/lang/messages.php';
// text strings (i18n)
require __DIR__ . '/lang/' . LANGUAGE . ".php";
require __DIR__ . '/lib/Strings.php';
$Strings = new Strings(LANGUAGE);
function sendError($error) {
global $SECURE_NONCE;
@ -136,18 +137,8 @@ function is_empty($str) {
* @param boolean $echo whether to echo the result or return it (default echo)
*/
function lang($key, $echo = true) {
if (array_key_exists($key, $GLOBALS['STRINGS'])) {
$str = $GLOBALS['STRINGS'][$key];
} else {
trigger_error("Language key \"$key\" does not exist in " . LANGUAGE, E_USER_WARNING);
$str = $key;
}
if ($echo) {
echo $str;
} else {
return $str;
}
global $Strings;
return $Strings->get($key, $echo);
}
/**
@ -159,22 +150,8 @@ function lang($key, $echo = true) {
* @param boolean $echo whether to echo the result or return it (default echo)
*/
function lang2($key, $replace, $echo = true) {
if (array_key_exists($key, $GLOBALS['STRINGS'])) {
$str = $GLOBALS['STRINGS'][$key];
} else {
trigger_error("Language key \"$key\" does not exist in " . LANGUAGE, E_USER_WARNING);
$str = $key;
}
foreach ($replace as $find => $repl) {
$str = str_replace("{" . $find . "}", $repl, $str);
}
if ($echo) {
echo $str;
} else {
return $str;
}
global $Strings;
return $Strings->build($key, $replace, $echo);
}
/**
@ -191,9 +168,7 @@ function addLangStrings($strings) {
* @param array $strings ['en_us' => ['key' => 'value']]
*/
function addMultiLangStrings($strings) {
if (!is_empty($strings[LANGUAGE])) {
$GLOBALS['STRINGS'] = array_merge($GLOBALS['STRINGS'], $strings[LANGUAGE]);
}
throw new Exception("Calling broken function addMultiLangStrings()");
}
/**

Loading…
Cancel
Save