mikuli.cz

:)
git clone https://git.sr.ht/~ashymad/mikuli.cz
Log | Files | Refs

commit 35573ecd9090ab008e0376ed2aef3bff769f3090
parent 608f411a4ca93f747c5179e9a74bb3daf25b58fa
Author: markseu <mark2011@mayberg.se>
Date:   Tue, 12 Apr 2016 15:58:56 +0200

System update (brave new world)

Diffstat:
Mcontent/1-home/page.txt | 15+++++++--------
Mcontent/2-about/page.txt | 4+---
Msystem/config/config.ini | 3+++
Msystem/plugins/commandline.php | 14++++++++++----
Msystem/plugins/core.php | 9+++++----
Msystem/plugins/language-de.txt | 56++++++++++++++++++++++++++++++++++++++++++++++++++------
Msystem/plugins/language-en.txt | 58+++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msystem/plugins/language-fr.txt | 56++++++++++++++++++++++++++++++++++++++++++++++++++------
Msystem/plugins/webinterface.css | 27+++++++++++++++++++++++----
Msystem/plugins/webinterface.js | 199++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Msystem/plugins/webinterface.php | 691+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Msystem/themes/snippets/footer.php | 2+-
12 files changed, 882 insertions(+), 252 deletions(-)

diff --git a/content/1-home/page.txt b/content/1-home/page.txt @@ -1,7 +1,6 @@ ---- -Title: Home ---- -Your website works! - -You can now [edit this page] or use your text editor. -For more information see [Yellow help](http://developers.datenstrom.se/help/). -\ No newline at end of file +--- +Title: Home +--- +Your website works! + +You can now [edit this page] or use your text editor. +\ No newline at end of file diff --git a/content/2-about/page.txt b/content/2-about/page.txt @@ -1,6 +1,4 @@ --- -Title: About +Title: About --- -A new website. - Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna pizza. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. \ No newline at end of file diff --git a/system/config/config.ini b/system/config/config.ini @@ -2,6 +2,7 @@ Sitename: Yellow Author: Yellow +Email: postmaster Language: en Theme: flatsite @@ -42,7 +43,9 @@ Siteicon: icon Parser: markdown ParserSafeMode: 0 MultiLanguageMode: 0 +InstallationMode: 1 WebinterfaceLocation: /edit/ +WebinterfaceUserPasswordMinLength: 4 WebinterfaceUserHashAlgorithm: bcrypt WebinterfaceUserHashCost: 10 WebinterfaceUserHome: / diff --git a/system/plugins/commandline.php b/system/plugins/commandline.php @@ -5,7 +5,7 @@ // Command line plugin class YellowCommandline { - const Version = "0.6.8"; + const Version = "0.6.9"; var $yellow; //access to API var $files; //number of files var $errors; //number of errors @@ -94,8 +94,13 @@ class YellowCommandline } else { $statusCode = 500; $this->files = 0; $this->errors = 1; - $fileName = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile"); - echo "ERROR building files: Please configure ServerScheme, ServerName, ServerBase, ServerTime in file '$fileName'!\n"; + if($this->yellow->config->get("installationMode")) + { + echo "ERROR building files: Please open your website in a web browser to detect server settings!\n"; + } else { + $fileName = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile"); + echo "ERROR building files: Please configure ServerScheme, ServerName, ServerBase, ServerTime in file '$fileName'!\n"; + } } echo "Yellow $command: $this->files file".($this->files!=1 ? 's' : ''); echo ", $this->errors error".($this->errors!=1 ? 's' : ''); @@ -332,10 +337,11 @@ class YellowCommandline // Check static configuration function checkStaticConfig() { + $installationMode = $this->yellow->config->get("installationMode"); $serverScheme = $this->yellow->config->get("serverScheme"); $serverName = $this->yellow->config->get("serverName"); $serverBase = $this->yellow->config->get("serverBase"); - return !empty($serverScheme) && !empty($serverName) && + return !$installationMode && !empty($serverScheme) && !empty($serverName) && $this->yellow->lookup->isValidLocation($serverBase) && $serverBase!="/"; } diff --git a/system/plugins/core.php b/system/plugins/core.php @@ -5,7 +5,7 @@ // Yellow core class YellowCore { - const Version = "0.6.3"; + const Version = "0.6.4"; var $page; //current page var $pages; //pages from file system var $files; //files from file system @@ -154,7 +154,7 @@ class YellowCore if($this->isRequestContentDirectory($location)) { $statusCode = 301; - $location = $this->lookup->isFileLocation($location) ? "$location/" : "/".$this->getRequestLanguage()."/"; + $location = $this->lookup->isFileLocation($location) ? "$location/" : "/".$this->getRequestLanguage(true)."/"; $location = $this->lookup->normaliseUrl($serverScheme, $serverName, $base, $location); $this->sendStatus($statusCode, $location); } @@ -300,9 +300,10 @@ class YellowCore } // Return request language - function getRequestLanguage() + function getRequestLanguage($multiLanguage = false) { - return $this->toolbox->detectBrowserLanguage($this->pages->getLanguages(), $this->config->get("language")); + $languages = $multiLanguage ? $this->pages->getLanguages() : $this->text->getLanguages(); + return $this->toolbox->detectBrowserLanguage($languages, $this->config->get("language")); } // Return request handler diff --git a/system/plugins/language-de.txt b/system/plugins/language-de.txt @@ -1,9 +1,9 @@ -# Yellow text strings +# Yellow language file Language: de LanguageDescription: Deutsch LanguageAuthor: David Fehrmann -LanguageVersion: 0.6.2 +LanguageVersion: 0.6.4 BlogBy: von BlogFilter: Blog: @@ -29,23 +29,67 @@ SearchQuery: Suche: SearchResultsNone: Bitte einen Suchbegriff eingeben. SearchResultsEmpty: Keine Treffer für diese Suchanfrage. SearchButton: Suchen -WebinterfaceLoginText: Yellow-Anmeldung +WebinterfaceInstallationTitle: Willkommen +WebinterfaceInstallationSitename: Webseite: +WebinterfaceInstallationAuthor: Name: +WebinterfaceInstallationHomePage: ---\nTitle: Home\n---\nDeine Webseite funktioniert!\n\nDu kannst [edit - diese Seite bearbeiten] oder einen Texteditor benutzen. +WebinterfaceLoginTitle: Yellow WebinterfaceLoginEmail: E-Mail: WebinterfaceLoginPassword: Kennwort: +WebinterfaceLoginRecover: Kennwort vergessen? +WebinterfaceLoginSignup: Benutzerkonto erstellen? WebinterfaceLoginButton: Anmelden +WebinterfaceSignupTitle: Benutzerkonto erstellen +WebinterfaceSignupName: Name: +WebinterfaceSignupEmail: E-Mail: +WebinterfaceSignupPassword: Kennwort: +WebinterfaceSignupButton: Erstellen +WebinterfaceSignupStatusNone: Hier kannst du ein neues Benutzerkonto erstellen. +WebinterfaceSignupStatusIncomplete: Bitte alle Felder ausfüllen. +WebinterfaceSignupStatusInvalid: Bitte eine gültige E-Mail angeben. +WebinterfaceSignupStatusWeak: Bitte eine anderes Kennwort angeben. +WebinterfaceSignupStatusNext: Benutzerkonto wird erstellt, bitte überprüfe deine E-Mails. +WebinterfaceRecoverTitle: Kennwort vergessen +WebinterfaceRecoverEmail: E-Mail: +WebinterfaceRecoverPassword: Kennwort: +WebinterfaceRecoverButton: Absenden +WebinterfaceRecoverStatusNone: Kein Problem, du kannst ein neues Kennwort erstellen. +WebinterfaceRecoverStatusInvalid: Bitte eine gültige E-Mail angeben. +WebinterfaceRecoverStatusPassword: Bitte ein neues Kennwort angeben. +WebinterfaceRecoverStatusWeak: Bitte eine anderes Kennwort angeben. +WebinterfaceRecoverStatusNext: Benutzerkonto wird wiederhergestellt, bitte überprüfe deine E-Mails. +WebinterfaceConfirmSubject: Benutzerkonto bestätigen +WebinterfaceConfirmMessage: Hallo @usershort, bitte bestätige dein Benutzerkonto. Klicke auf den folgenden Link. +WebinterfaceConfirmStatusDone: Benutzerkonto wurde bestätigt. Vielen Dank! +WebinterfaceConfirmStatusExpire: Benutzerkonto kann nicht bestätigt werden. Link ist abgelaufen! +WebinterfaceApproveSubject: Benutzerkonto genehmigen +WebinterfaceApproveMessage: Hallo @usershort, bitte genehmige ein neues Benutzerkonto für @useraccount. Klicke auf den folgenden Link. +WebinterfaceApproveStatusDone: Benutzerkonto wurde genehmigt. Vielen Dank! +WebinterfaceApproveStatusExpire: Benutzerkonto kann nicht genehmigt werden. Link ist abgelaufen! +WebinterfaceRecoverSubject: Benutzerkonto wiederherstellen +WebinterfaceRecoverMessage: Hallo @usershort, bitte bestätige dass du dein Kennwort vergessen hast. Klicke auf den folgenden Link. +WebinterfaceRecoverStatusDone: Benutzerkonto wurde wiederhergestellt. Vielen Dank! +WebinterfaceRecoverStatusExpire: Benutzerkonto kann nicht wiederhergestellt werden. Link ist abgelaufen! +WebinterfaceWelcomeSubject: Willkommen +WebinterfaceWelcomeMessage: Hallo @usershort, dein Benutzerkonto wurde erstellt. Viel Spass beim Bearbeiten der Webseite. +WebinterfaceInformationSubject: Willkommen zurück +WebinterfaceInformationMessage: Hallo @usershort, dein Benutzerkonto wurde wiederhergestellt. Viel Spass beim Bearbeiten der Webseite. +WebinterfaceOkButton: Ok +WebinterfaceCancelButton: Abbruch WebinterfaceCreateButton: Erzeugen WebinterfaceEditButton: Ändern WebinterfaceDeleteButton: Löschen -WebinterfaceCancelButton: Abbruch WebinterfaceEdit: Seite ändern WebinterfaceCreate: + WebinterfaceDelete: - WebinterfaceCreateTitle: Neue Seite WebinterfaceDeleteTitle: Seite löschen +WebinterfaceMarkdownHelp: Markdown WebinterfaceUserHelp: Hilfe -WebinterfaceUserHelpUrl: http://developers.datenstrom.se/help/help-de -WebinterfaceUserAccountUrl: http://developers.datenstrom.se/help/how-to-add-a-user-account-de WebinterfaceUserLogout: Abmelden WikiFilter: Wiki: WikiTag: Tags: WikiSpecialChanges: Letzte Änderungen +YellowUrl: http://datenstrom.se/yellow/yellow-deutsch +YellowUserHelpUrl: http://developers.datenstrom.se/help/help-de +YellowMarkdownHelpUrl: http://developers.datenstrom.se/help/markdown-cheat-sheet-de diff --git a/system/plugins/language-en.txt b/system/plugins/language-en.txt @@ -1,9 +1,9 @@ -# Yellow text strings +# Yellow language file Language: en LanguageDescription: English LanguageAuthor: Mark Seuffert -LanguageVersion: 0.6.2 +LanguageVersion: 0.6.4 BlogBy: by BlogFilter: Blog: @@ -16,7 +16,7 @@ ContactButton: Send message ContactStatusNone: Say hello. Your feedback is very welcome. ContactStatusIncomplete: Please fill out all fields. ContactStatusInvalid: Please enter a valid email. -ContactStatusDone: You have sucessfully sent an email. Thank you! +ContactStatusDone: You have sent an email. Thank you! ContactStatusError: Email could not be sent, please try again later! DateMonths: January, February, March, April, May, June, July, August, September, October, November, December DateWeekdays: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday @@ -29,23 +29,67 @@ SearchQuery: Search: SearchResultsNone: Enter a search term. SearchResultsEmpty: No results found. SearchButton: Search -WebinterfaceLoginText: Yellow login +WebinterfaceInstallationTitle: Welcome +WebinterfaceInstallationSitename: Website: +WebinterfaceInstallationAuthor: Name: +WebinterfaceInstallationHomePage: ---\nTitle: Home\n---\nYour website works!\n\nYou can now [edit this page] or use your text editor. +WebinterfaceLoginTitle: Yellow WebinterfaceLoginEmail: Email: WebinterfaceLoginPassword: Password: +WebinterfaceLoginRecover: Forgot your password? +WebinterfaceLoginSignup: Create user account? WebinterfaceLoginButton: Log in +WebinterfaceSignupTitle: Create user account +WebinterfaceSignupName: Name: +WebinterfaceSignupEmail: Email: +WebinterfaceSignupPassword: Password: +WebinterfaceSignupButton: Create +WebinterfaceSignupStatusNone: Here you can create a new user account. +WebinterfaceSignupStatusIncomplete: Please fill out all fields. +WebinterfaceSignupStatusInvalid: Please enter a valid email. +WebinterfaceSignupStatusWeak: Please enter a different password. +WebinterfaceSignupStatusNext: User account will be created, please check your emails. +WebinterfaceRecoverTitle: Forgot your password +WebinterfaceRecoverEmail: Email: +WebinterfaceRecoverPassword: Password: +WebinterfaceRecoverButton: Send +WebinterfaceRecoverStatusNone: No problem, you can create a new password. +WebinterfaceRecoverStatusInvalid: Please enter a valid email. +WebinterfaceRecoverStatusPassword: Please enter a new password. +WebinterfaceRecoverStatusWeak: Please enter a different password. +WebinterfaceRecoverStatusNext: User account will be recovered, please check your emails. +WebinterfaceConfirmSubject: Confirm user account +WebinterfaceConfirmMessage: Hi @usershort, please confirm your user account. Click the following link. +WebinterfaceConfirmStatusDone: User account confirmed. Thank you! +WebinterfaceConfirmStatusExpire: User account can not be confirmed. Link has expired! +WebinterfaceApproveSubject: Approve user account +WebinterfaceApproveMessage: Hi @usershort, please approve a new user account for @useraccount. Click the following link. +WebinterfaceApproveStatusDone: User account approved. Thank you! +WebinterfaceApproveStatusExpire: User account can not be approved. Link has expired! +WebinterfaceRecoverSubject: Recover user account +WebinterfaceRecoverMessage: Hi @usershort, please confirm that you forgot your password. Click the following link. +WebinterfaceRecoverStatusDone: User account recovered. Thank you! +WebinterfaceRecoverStatusExpire: User account can not be recovered. Link has expired! +WebinterfaceWelcomeSubject: Welcome +WebinterfaceWelcomeMessage: Hi @usershort, your user account has been created. Have fun editing the website. +WebinterfaceInformationSubject: Welcome back +WebinterfaceInformationMessage: Hi @usershort, your user account has been recovered. Have fun editing the website. +WebinterfaceOkButton: Ok +WebinterfaceCancelButton: Cancel WebinterfaceCreateButton: Create WebinterfaceEditButton: Save WebinterfaceDeleteButton: Delete -WebinterfaceCancelButton: Cancel WebinterfaceEdit: Edit page WebinterfaceCreate: + WebinterfaceDelete: - WebinterfaceCreateTitle: New page WebinterfaceDeleteTitle: Delete page +WebinterfaceMarkdownHelp: Markdown WebinterfaceUserHelp: Help -WebinterfaceUserHelpUrl: http://developers.datenstrom.se/help/ -WebinterfaceUserAccountUrl: http://developers.datenstrom.se/help/how-to-add-a-user-account WebinterfaceUserLogout: Logout WikiFilter: Wiki: WikiTag: Tags: WikiSpecialChanges: Recent changes +YellowUrl: http://datenstrom.se/yellow +YellowUserHelpUrl: http://developers.datenstrom.se/help/ +YellowMarkdownHelpUrl: http://developers.datenstrom.se/help/markdown-cheat-sheet diff --git a/system/plugins/language-fr.txt b/system/plugins/language-fr.txt @@ -1,9 +1,9 @@ -# Yellow text strings +# Yellow language file Language: fr LanguageDescription: Français LanguageAuthor: Juh Nibreh -LanguageVersion: 0.6.2 +LanguageVersion: 0.6.4 BlogBy: par BlogFilter: Blog: @@ -29,23 +29,67 @@ SearchQuery: Rechercher: SearchResultsNone: Entrez un mot dans le champ de recherche. SearchResultsEmpty: Pas de résultats. SearchButton: Rechercher -WebinterfaceLoginText: Yellow connexion +WebinterfaceInstallationTitle: Bienvenue +WebinterfaceInstallationSitename: Site web: +WebinterfaceInstallationAuthor: Nom: +WebinterfaceInstallationHomePage: ---\nTitle: Home\n---\nVotre site web fonctionne!\n\nVous pouvez [edit - modifier cette page] ou utilisez un éditeur de texte. +WebinterfaceLoginTitle: Yellow WebinterfaceLoginEmail: Email: WebinterfaceLoginPassword: Mot de passe: +WebinterfaceLoginRecover: Mot de passe oublié? +WebinterfaceLoginSignup: Créer un compte utilisateur? WebinterfaceLoginButton: Se connecter +WebinterfaceSignupTitle: Créer un compte utilisateur +WebinterfaceSignupName: Name: +WebinterfaceSignupEmail: Email: +WebinterfaceSignupPassword: Password: +WebinterfaceSignupButton: Create +WebinterfaceSignupStatusNone: Here you can create a new user account. +WebinterfaceSignupStatusIncomplete: Please fill out all fields. +WebinterfaceSignupStatusInvalid: Please enter a valid email. +WebinterfaceSignupStatusWeak: Please enter a different password. +WebinterfaceSignupStatusNext: User account will be created, please check your emails. +WebinterfaceRecoverTitle: Forgot your password +WebinterfaceRecoverEmail: Email: +WebinterfaceRecoverPassword: Password: +WebinterfaceRecoverButton: Send +WebinterfaceRecoverStatusNone: No problem, you can create a new password. +WebinterfaceRecoverStatusInvalid: Please enter a valid email. +WebinterfaceRecoverStatusPassword: Please enter a new password. +WebinterfaceRecoverStatusWeak: Please enter a different password. +WebinterfaceRecoverStatusNext: User account will be recovered, please check your emails. +WebinterfaceConfirmSubject: Confirm user account +WebinterfaceConfirmMessage: Bonjour @usershort, please confirm your user account. Click the following link. +WebinterfaceConfirmStatusDone: User account confirmed. Thank you! +WebinterfaceConfirmStatusExpire: User account can not be confirmed. Link has expired! +WebinterfaceApproveSubject: Approve user account +WebinterfaceApproveMessage: Bonjour @usershort, please approve a new user account for @useraccount. Click the following link. +WebinterfaceApproveStatusDone: User account approved. Thank you! +WebinterfaceApproveStatusExpire: User account can not be approved. Link has expired! +WebinterfaceRecoverSubject: Recover user account +WebinterfaceRecoverMessage: Bonjour @usershort, please confirm that you forgot your password. Click the following link. +WebinterfaceRecoverStatusDone: User account recovered. Thank you! +WebinterfaceRecoverStatusExpire: User account can not be recovered. Link has expired! +WebinterfaceWelcomeSubject: Welcome +WebinterfaceWelcomeMessage: Bonjour @usershort, your user account has been created. Have fun editing the website. +WebinterfaceInformationSubject: Welcome back +WebinterfaceInformationMessage: Bonjour @usershort, your user account has been recovered. Have fun editing the website. +WebinterfaceOkButton: Ok +WebinterfaceCancelButton: Annuler WebinterfaceCreateButton: Créer WebinterfaceEditButton: Sauvegarder WebinterfaceDeleteButton: Supprimer -WebinterfaceCancelButton: Annuler WebinterfaceEdit: Éditer page WebinterfaceCreate: + WebinterfaceDelete: - WebinterfaceCreateTitle: Nouvelle page WebinterfaceDeleteTitle: Supprimer page +WebinterfaceMarkdownHelp: Markdown WebinterfaceUserHelp: Aide -WebinterfaceUserHelpUrl: http://developers.datenstrom.se/help/help-fr -WebinterfaceUserAccountUrl: http://developers.datenstrom.se/help/how-to-add-a-user-account-fr WebinterfaceUserLogout: Déconnexion WikiFilter: Wiki: WikiTag: Tags: WikiSpecialChanges: Changements récents +YellowUrl: http://datenstrom.se/yellow/yellow-français +YellowUserHelpUrl: http://developers.datenstrom.se/help/help-fr +YellowMarkdownHelpUrl: http://developers.datenstrom.se/help/markdown-cheat-sheet-fr diff --git a/system/plugins/webinterface.css b/system/plugins/webinterface.css @@ -1,4 +1,4 @@ -/* Yellow web interface 0.6.1 */ +/* Yellow web interface 0.6.6 */ .yellow-bar { position:relative; overflow:hidden; height:2em; margin-bottom:10px; } .yellow-bar-left { display:block; float:left; } @@ -54,7 +54,7 @@ } .yellow-btn { margin:0; padding:4px 22px; - display:inline-block; min-width:7em; + display:inline-block; min-width:8em; background-color:#eaeaea; color:#333333; background-image:linear-gradient(to bottom, #f8f8f8, #e1e1e1); border:1px solid #bbb; @@ -91,15 +91,34 @@ #yellow-pane-login { text-align:center; white-space:nowrap; } #yellow-pane-login h1 { margin:0 1em; font-size:2em; } -#yellow-pane-login-status { display:inline-block; } -#yellow-pane-login-fields { width:15em; text-align:left; margin:0 auto; } #yellow-pane-login input { width:15em; box-sizing:border-box; } #yellow-pane-login .yellow-btn { width:15em; margin:1em 1em 0.5em 0; } +#yellow-pane-login-fields { width:15em; text-align:left; margin:0 auto; } +#yellow-pane-login-buttons { margin:0.5em 0; } +#yellow-pane-login-buttons p { margin:0; } + +#yellow-pane-signup { text-align:center; white-space:nowrap; } +#yellow-pane-signup h1 { margin:0 1em; font-size:2em; } +#yellow-pane-signup input { width:15em; box-sizing:border-box; } +#yellow-pane-signup .yellow-btn { width:15em; margin:1em 1em 0.5em 0; } +#yellow-pane-signup-status { margin:0.5em 0; display:inline-block; } +#yellow-pane-signup-fields { width:15em; text-align:left; margin:0 auto; } +#yellow-pane-signup-buttons { margin-top:-0.5em; } + +#yellow-pane-recover { text-align:center; white-space:nowrap; } +#yellow-pane-recover h1 { margin:0 1em; font-size:2em; } +#yellow-pane-recover input { width:15em; box-sizing:border-box; } +#yellow-pane-recover .yellow-btn { width:15em; margin:1em 1em 0.5em 0; } +#yellow-pane-recover-status { margin:0.5em 0; display:inline-block; } +#yellow-pane-recover-fields-first, #yellow-pane-recover-fields-second { width:15em; text-align:left; margin:0 auto; } +#yellow-pane-recover-buttons { margin-top:-0.5em; } + #yellow-pane-edit { } #yellow-pane-edit h1 { margin:0 0 10px 0; font-size:1.5em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; } #yellow-pane-edit-page { padding:5px; outline:none; resize:none; } #yellow-pane-edit-buttons { margin-top:5px; } #yellow-pane-edit-buttons input { margin-right:10px; } +#yellow-pane-edit-help { float:right; } #yellow-pane-user { cursor:pointer; } #yellow-pane-user a { text-decoration:none; } #yellow-pane-user a:hover { text-decoration:underline; } diff --git a/system/plugins/webinterface.js b/system/plugins/webinterface.js @@ -1,14 +1,14 @@ -// Copyright (c) 2013-2015 Datenstrom, http://datenstrom.se +// Copyright (c) 2013-2016 Datenstrom, http://datenstrom.se // This file may be used and distributed under the terms of the public license. // Yellow API var yellow = { - version: "0.6.1", + version: "0.6.6", action: function(text) { yellow.webinterface.action(text); }, onClick: function(e) { yellow.webinterface.hidePanesOnClick(yellow.toolbox.getEventElement(e)); }, onKeydown: function(e) { yellow.webinterface.hidePanesOnKeydown(yellow.toolbox.getEventKeycode(e)); }, - onResize: function() { yellow.webinterface.resizePanes(); }, + onResize: function() { yellow.webinterface.resizePane(yellow.webinterface.paneId); }, onUpdate: function() { yellow.webinterface.updatePane(yellow.webinterface.paneId, yellow.webinterface.paneType); }, webinterface:{}, toolbox:{}, page:{}, config:{}, text:{} } @@ -50,7 +50,9 @@ yellow.webinterface = } else { this.createBar("yellow-bar", false, body.firstChild); this.createPane("yellow-pane-login", false, body.firstChild); - if(yellow.config.login) this.showPane("yellow-pane-login"); + this.createPane("yellow-pane-signup", false, body.firstChild); + this.createPane("yellow-pane-recover", false, body.firstChild); + yellow.action(yellow.page.loginAction); } } clearInterval(this.intervalId); @@ -62,14 +64,18 @@ yellow.webinterface = { switch(text) { - case "create": this.togglePane("yellow-pane-edit", "create", true); break; - case "edit": this.togglePane("yellow-pane-edit", "edit", true); break; - case "delete": this.togglePane("yellow-pane-edit", "delete", true); break; - case "user": this.togglePane("yellow-pane-user"); break; - case "send": this.sendPane(this.paneId, this.paneType); break; - case "cancel": this.hidePane(this.paneId); break; - case "login": this.togglePane("yellow-pane-login"); break; - case "logout": yellow.toolbox.submitForm({"action":"logout"}); break; + case "login": this.togglePane("yellow-pane-login"); break; + case "logout": yellow.toolbox.submitForm({"action":"logout"}); break; + case "signup": this.togglePane("yellow-pane-signup", "signup"); break; + case "confirm": this.togglePane("yellow-pane-signup", "confirm"); break; + case "approve": this.togglePane("yellow-pane-signup", "approve"); break; + case "recover": this.togglePane("yellow-pane-recover", "recover"); break; + case "create": this.togglePane("yellow-pane-edit", "create", true); break; + case "edit": this.togglePane("yellow-pane-edit", "edit", true); break; + case "delete": this.togglePane("yellow-pane-edit", "delete", true); break; + case "user": this.togglePane("yellow-pane-user"); break; + case "send": this.sendPane(this.paneId, this.paneType); break; + case "close": this.hidePane(this.paneId); break; } }, @@ -116,14 +122,54 @@ yellow.webinterface = { elementDiv.innerHTML = "<form method=\"post\">"+ - "<a href=\"#\" onclick=\"yellow.action('cancel'); return false;\" class=\"yellow-cancel\">x</a>"+ - "<h1>"+this.getText("LoginText")+"</h1>"+ + "<a href=\"#\" onclick=\"yellow.action('close'); return false;\" class=\"yellow-cancel\">x</a>"+ + "<h1>"+this.getText("LoginTitle")+"</h1>"+ "<div id=\"yellow-pane-login-fields\">"+ "<input type=\"hidden\" name=\"action\" value=\"login\" />"+ "<p><label for=\"email\">"+this.getText("LoginEmail")+"</label><br /><input class=\"yellow-form-control\" name=\"email\" id=\"email\" maxlength=\"64\" value=\""+yellow.config.loginEmail+"\" /></p>"+ "<p><label for=\"password\">"+this.getText("LoginPassword")+"</label><br /><input class=\"yellow-form-control\" type=\"password\" name=\"password\" id=\"password\" maxlength=\"64\" value=\""+yellow.config.loginPassword+"\" /></p>"+ "<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("LoginButton")+"\" /></p>"+ "</div>"+ + "<div id=\"yellow-pane-login-buttons\">"+ + "<p><a href=\"#\" onclick=\"yellow.action('recover'); return false;\">"+this.getText("LoginRecover")+"</a><p>"+ + "<p><a href=\"#\" onclick=\"yellow.action('signup'); return false;\">"+this.getText("LoginSignup")+"</a><p>"+ + "</div>"+ + "</form>"; + } else if(paneId == "yellow-pane-signup") { + elementDiv.innerHTML = + "<form method=\"post\">"+ + "<a href=\"#\" onclick=\"yellow.action('close'); return false;\" class=\"yellow-cancel\">x</a>"+ + "<h1>"+this.getText("SignupTitle")+"</h1>"+ + "<div id=\"yellow-pane-signup-status\" class=\""+yellow.page.loginStatus+"\">"+this.getText("SignupStatus", "", yellow.page.loginStatus)+"</div>"+ + "<div id=\"yellow-pane-signup-fields\">"+ + "<input type=\"hidden\" name=\"action\" value=\"signup\" />"+ + "<p><label for=\"name\">"+this.getText("SignupName")+"</label><br /><input class=\"yellow-form-control\" name=\"name\" id=\"name\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(this.getRequest("Name"))+"\" /></p>"+ + "<p><label for=\"email\">"+this.getText("SignupEmail")+"</label><br /><input class=\"yellow-form-control\" name=\"email\" id=\"email\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(this.getRequest("Email"))+"\" /></p>"+ + "<p><label for=\"password\">"+this.getText("SignupPassword")+"</label><br /><input class=\"yellow-form-control\" type=\"password\" name=\"password\" id=\"password\" maxlength=\"64\" value=\"\" /></p>"+ + "<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("SignupButton")+"\" /></p>"+ + "</div>"+ + "<div id=\"yellow-pane-signup-buttons\">"+ + "<p><input class=\"yellow-btn\" type=\"button\" onclick=\"yellow.action('close'); return false;\" value=\""+this.getText("OkButton")+"\" /></p>"+ + "</div>"+ + "</form>"; + } else if(paneId == "yellow-pane-recover") { + elementDiv.innerHTML = + "<form method=\"post\">"+ + "<a href=\"#\" onclick=\"yellow.action('close'); return false;\" class=\"yellow-cancel\">x</a>"+ + "<h1>"+this.getText("RecoverTitle")+"</h1>"+ + "<div id=\"yellow-pane-recover-status\" class=\""+yellow.page.loginStatus+"\">"+this.getText("RecoverStatus", "", yellow.page.loginStatus)+"</div>"+ + "<div id=\"yellow-pane-recover-fields-first\">"+ + "<input type=\"hidden\" name=\"action\" value=\"recover\" />"+ + "<p><label for=\"email\">"+this.getText("RecoverEmail")+"</label><br /><input class=\"yellow-form-control\" name=\"email\" id=\"email\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(this.getRequest("Email"))+"\" /></p>"+ + "<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("RecoverButton")+"\" /></p>"+ + "</div>"+ + "<div id=\"yellow-pane-recover-fields-second\">"+ + "<p><label for=\"password\">"+this.getText("RecoverPassword")+"</label><br /><input class=\"yellow-form-control\" type=\"password\" name=\"password\" id=\"password\" maxlength=\"64\" value=\"\" /></p>"+ + "<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("RecoverButton")+"\" /></p>"+ + "</div>"+ + "<div id=\"yellow-pane-recover-buttons\">"+ + "<p><input class=\"yellow-btn\" type=\"button\" onclick=\"yellow.action('close'); return false;\" value=\""+this.getText("OkButton")+"\" /></p>"+ + "</div>"+ "</form>"; } else if(paneId == "yellow-pane-edit") { elementDiv.innerHTML = @@ -132,13 +178,14 @@ yellow.webinterface = "<textarea id=\"yellow-pane-edit-page\" class=\"yellow-form-control\" name=\"rawdataedit\"></textarea>"+ "<div id=\"yellow-pane-edit-buttons\">"+ "<input id=\"yellow-pane-edit-send\" class=\"yellow-btn\" type=\"button\" onclick=\"yellow.action('send'); return false;\" value=\""+this.getText("EditButton")+"\" />"+ - "<input id=\"yellow-pane-edit-cancel\" class=\"yellow-btn\" type=\"button\" onclick=\"yellow.action('cancel'); return false;\" value=\""+this.getText("CancelButton")+"\" />"+ + "<input id=\"yellow-pane-edit-close\" class=\"yellow-btn\" type=\"button\" onclick=\"yellow.action('close'); return false;\" value=\""+this.getText("CancelButton")+"\" />"+ + "<a href=\""+this.getText("MarkdownHelpUrl", "yellow")+"\" target=\"_blank\" id=\"yellow-pane-edit-help\">"+this.getText("MarkdownHelp")+"</a>" + "</div>"+ "</form>"; } else if(paneId == "yellow-pane-user") { elementDiv.innerHTML = "<p>"+yellow.config.userEmail+"</p>"+ - "<p><a href=\""+this.getText("UserHelpUrl")+"\" onclick=\"yellow.action('user'); return true;\">"+this.getText("UserHelp")+"</a></p>" + + "<p><a href=\""+this.getText("UserHelpUrl", "yellow")+"\" onclick=\"yellow.action('user'); return true;\">"+this.getText("UserHelp")+"</a></p>" + "<p><a href=\"#\" onclick=\"yellow.action('logout'); return false;\">"+this.getText("UserLogout")+"</a></p>"; } elementPane.appendChild(elementDiv); @@ -149,8 +196,41 @@ yellow.webinterface = updatePane: function(paneId, paneType, init) { if(yellow.debug) console.log("yellow.webinterface.updatePane id:"+paneId); - if(paneId == "yellow-pane-edit") + if(paneId == "yellow-pane-login") { + if(!yellow.config.loginExtra) + { + document.getElementById("yellow-pane-login-buttons").style.display = "none"; + } + } else if(paneId == "yellow-pane-signup") { + switch(paneType) + { + case "signup": text = this.getText("SignupStatus", "", yellow.page.loginStatus); break; + case "confirm": text = this.getText("ConfirmStatus", "", yellow.page.loginStatus); break; + case "approve": text = this.getText("ApproveStatus", "", yellow.page.loginStatus); break; + } + document.getElementById("yellow-pane-signup-status").innerHTML = yellow.toolbox.encodeHtml(text); + if(yellow.page.loginStatus=="next" || yellow.page.loginStatus=="done" || yellow.page.loginStatus=="expire") + { + document.getElementById("yellow-pane-signup-fields").style.display = "none"; + } else { + document.getElementById("yellow-pane-signup-buttons").style.display = "none"; + } + } else if(paneId == "yellow-pane-recover") { + if(yellow.page.loginStatus=="next" || yellow.page.loginStatus=="done" || yellow.page.loginStatus=="expire") + { + document.getElementById("yellow-pane-recover-fields-first").style.display = "none"; + document.getElementById("yellow-pane-recover-fields-second").style.display = "none"; + } else { + document.getElementById("yellow-pane-recover-buttons").style.display = "none"; + if(this.getRequest("Id")) + { + document.getElementById("yellow-pane-recover-fields-first").style.display = "none"; + } else { + document.getElementById("yellow-pane-recover-fields-second").style.display = "none"; + } + } + } else if(paneId == "yellow-pane-edit") { if(init) { var title = yellow.page.title; @@ -229,7 +309,7 @@ yellow.webinterface = } this.paneId = paneId; this.paneType = paneType; - this.resizePanes(); + this.resizePane(paneId); this.updatePane(paneId, paneType, true); } }, @@ -280,8 +360,8 @@ yellow.webinterface = if(keycode == 27) this.hidePanes(); }, - // Resize panes, recalculate width and height where needed - resizePanes: function() + // Resize panes where needed + resizePane: function(paneId) { if(document.getElementById("yellow-bar")) { @@ -289,37 +369,39 @@ yellow.webinterface = var paneTop = yellow.toolbox.getOuterTop(elementBar) + yellow.toolbox.getOuterHeight(elementBar); var paneWidth = yellow.toolbox.getOuterWidth(elementBar, true); var paneHeight = yellow.toolbox.getWindowHeight() - paneTop - yellow.toolbox.getOuterHeight(elementBar); - if(yellow.toolbox.isVisible(document.getElementById("yellow-pane-login"))) + switch(paneId) { - yellow.toolbox.setOuterTop(document.getElementById("yellow-pane-login"), paneTop); - yellow.toolbox.setOuterWidth(document.getElementById("yellow-pane-login"), paneWidth); + case "yellow-pane-login": + case "yellow-pane-signup": + case "yellow-pane-recover": + yellow.toolbox.setOuterTop(document.getElementById(paneId), paneTop); + yellow.toolbox.setOuterWidth(document.getElementById(paneId), paneWidth); + break; + case "yellow-pane-edit": + yellow.toolbox.setOuterTop(document.getElementById("yellow-pane-edit"), paneTop); + yellow.toolbox.setOuterHeight(document.getElementById("yellow-pane-edit"), paneHeight); + yellow.toolbox.setOuterWidth(document.getElementById("yellow-pane-edit"), paneWidth); + yellow.toolbox.setOuterWidth(document.getElementById("yellow-pane-edit-page"), yellow.toolbox.getWidth(document.getElementById("yellow-pane-edit"))); + var height1 = yellow.toolbox.getHeight(document.getElementById("yellow-pane-edit")); + var height2 = yellow.toolbox.getOuterHeight(document.getElementById("yellow-pane-edit-content")); + var height3 = yellow.toolbox.getOuterHeight(document.getElementById("yellow-pane-edit-page")); + yellow.toolbox.setOuterHeight(document.getElementById("yellow-pane-edit-page"), height1 - height2 + height3); + var elementLink = document.getElementById("yellow-pane-"+this.paneType+"-link"); + var position = yellow.toolbox.getOuterLeft(elementLink) + yellow.toolbox.getOuterWidth(elementLink)/2; + position -= yellow.toolbox.getOuterLeft(document.getElementById("yellow-pane-edit")) + 1; + yellow.toolbox.setOuterLeft(document.getElementById("yellow-pane-edit-arrow"), position); + break; + case "yellow-pane-user": + yellow.toolbox.setOuterTop(document.getElementById("yellow-pane-user"), paneTop); + yellow.toolbox.setOuterHeight(document.getElementById("yellow-pane-user"), paneHeight, true); + yellow.toolbox.setOuterLeft(document.getElementById("yellow-pane-user"), paneWidth - yellow.toolbox.getOuterWidth(document.getElementById("yellow-pane-user")), true); + var elementLink = document.getElementById("yellow-pane-user-link"); + var position = yellow.toolbox.getOuterLeft(elementLink) + yellow.toolbox.getOuterWidth(elementLink)/2; + position -= yellow.toolbox.getOuterLeft(document.getElementById("yellow-pane-user")); + yellow.toolbox.setOuterLeft(document.getElementById("yellow-pane-user-arrow"), position); + break; } - if(yellow.toolbox.isVisible(document.getElementById("yellow-pane-edit"))) - { - yellow.toolbox.setOuterTop(document.getElementById("yellow-pane-edit"), paneTop); - yellow.toolbox.setOuterHeight(document.getElementById("yellow-pane-edit"), paneHeight); - yellow.toolbox.setOuterWidth(document.getElementById("yellow-pane-edit"), paneWidth); - yellow.toolbox.setOuterWidth(document.getElementById("yellow-pane-edit-page"), yellow.toolbox.getWidth(document.getElementById("yellow-pane-edit"))); - var height1 = yellow.toolbox.getHeight(document.getElementById("yellow-pane-edit")); - var height2 = yellow.toolbox.getOuterHeight(document.getElementById("yellow-pane-edit-content")); - var height3 = yellow.toolbox.getOuterHeight(document.getElementById("yellow-pane-edit-page")); - yellow.toolbox.setOuterHeight(document.getElementById("yellow-pane-edit-page"), height1 - height2 + height3); - var elementLink = document.getElementById("yellow-pane-"+this.paneType+"-link"); - var position = yellow.toolbox.getOuterLeft(elementLink) + yellow.toolbox.getOuterWidth(elementLink)/2; - position -= yellow.toolbox.getOuterLeft(document.getElementById("yellow-pane-edit")) + 1; - yellow.toolbox.setOuterLeft(document.getElementById("yellow-pane-edit-arrow"), position); - } - if(yellow.toolbox.isVisible(document.getElementById("yellow-pane-user"))) - { - yellow.toolbox.setOuterTop(document.getElementById("yellow-pane-user"), paneTop); - yellow.toolbox.setOuterHeight(document.getElementById("yellow-pane-user"), paneHeight, true); - yellow.toolbox.setOuterLeft(document.getElementById("yellow-pane-user"), paneWidth - yellow.toolbox.getOuterWidth(document.getElementById("yellow-pane-user")), true); - var elementLink = document.getElementById("yellow-pane-user-link"); - var position = yellow.toolbox.getOuterLeft(elementLink) + yellow.toolbox.getOuterWidth(elementLink)/2; - position -= yellow.toolbox.getOuterLeft(document.getElementById("yellow-pane-user")); - yellow.toolbox.setOuterLeft(document.getElementById("yellow-pane-user-arrow"), position); - } - if(yellow.debug) console.log("yellow.webinterface.resizePanes bar:"+elementBar.offsetWidth+"/"+elementBar.offsetHeight); + if(yellow.debug) console.log("yellow.webinterface.resizePane bar:"+elementBar.offsetWidth+"/"+elementBar.offsetHeight); } }, @@ -329,7 +411,7 @@ yellow.webinterface = var action = ""; if(paneId == "yellow-pane-edit") { - if(yellow.page.userPermission) + if(!yellow.page.userRestrictions) { var string = document.getElementById("yellow-pane-edit-page").value; switch(paneType) @@ -343,11 +425,22 @@ yellow.webinterface = } return action; }, - + + // Return request string + getRequest: function(key, prefix) + { + if(!prefix) prefix = "request"; + key = prefix + key; + return (key in yellow.page) ? yellow.page[key] : ""; + }, + // Return text string - getText: function(key) + getText: function(key, prefix, postfix) { - return ("webinterface"+key in yellow.text) ? yellow.text["webinterface"+key] : "[webinterface"+key+"]"; + if(!prefix) prefix = "webinterface"; + if(!postfix) postfix = "" + key = prefix + key + postfix.charAt(0).toUpperCase() + postfix.slice(1); + return (key in yellow.text) ? yellow.text[key] : "["+key+"]"; } } diff --git a/system/plugins/webinterface.php b/system/plugins/webinterface.php @@ -5,11 +5,12 @@ // Web interface plugin class YellowWebinterface { - const Version = "0.6.5"; + const Version = "0.6.6"; var $yellow; //access to API var $active; //web interface is active? (boolean) - var $userLoginFailed; //web interface login failed? (boolean) - var $userPermission; //web interface can change page? (boolean) + var $loginAction; //web interface login action + var $loginStatus; //web interface login status + var $userRestrictions; //web interface user can change page? (boolean) var $users; //web interface users var $merge; //web interface merge var $rawDataSource; //raw data of page for comparison @@ -24,8 +25,10 @@ class YellowWebinterface $this->yellow->config->setDefault("webinterfaceServerScheme", $this->yellow->config->get("serverScheme")); $this->yellow->config->setDefault("webinterfaceServerName", $this->yellow->config->get("serverName")); $this->yellow->config->setDefault("webinterfaceLocation", "/edit/"); + $this->yellow->config->setDefault("webinterfaceUserPasswordMinLength", "4"); $this->yellow->config->setDefault("webinterfaceUserHashAlgorithm", "bcrypt"); $this->yellow->config->setDefault("webinterfaceUserHashCost", "10"); + $this->yellow->config->setDefault("webinterfaceUserStatus", "active"); $this->yellow->config->setDefault("webinterfaceUserHome", "/"); $this->yellow->config->setDefault("webinterfaceUserFile", "user.ini"); $this->yellow->config->setDefault("webinterfaceNewFile", "page-new-(.*).txt"); @@ -58,9 +61,9 @@ class YellowWebinterface // Handle page meta data parsing function onParseMeta($page) { - if($this->isActive() && $this->isUser()) + if($this->isActive() && $page==$this->yellow->page) { - if($page == $this->yellow->page) + if($this->isUser()) { if(empty($this->rawDataSource)) $this->rawDataSource = $page->rawData; if(empty($this->rawDataEdit)) $this->rawDataEdit = $page->rawData; @@ -69,6 +72,10 @@ class YellowWebinterface $title = $this->yellow->toolbox->createTextTitle($page->location); $this->rawDataEdit = $this->getRawDataNew($title); } + } else { + if(empty($this->loginAction)) $this->loginAction = "login"; + if(empty($this->loginStatus)) $this->loginStatus = "none"; + if($this->loginStatus == "error") $this->loginAction = "error"; } } } @@ -92,20 +99,17 @@ class YellowWebinterface $output = NULL; if($this->isActive() && $name=="header") { - if($this->users->getNumber()) - { - $location = $this->yellow->config->get("serverBase").$this->yellow->config->get("pluginLocation")."webinterface"; - $output = "<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\"".htmlspecialchars($location).".css\" />\n"; - $output .= "<script type=\"text/javascript\" src=\"".htmlspecialchars($location).".js\"></script>\n"; - $output .= "<script type=\"text/javascript\">\n"; - $output .= "// <![CDATA[\n"; - $output .= "yellow.page = ".json_encode($this->getPageData()).";\n"; - $output .= "yellow.config = ".json_encode($this->getConfigData()).";\n"; - $output .= "yellow.text = ".json_encode($this->getTextData()).";\n"; - if(defined("DEBUG") && DEBUG>=1) $output .= "yellow.debug = ".json_encode(DEBUG).";\n"; - $output .= "// ]]>\n"; - $output .= "</script>\n"; - } + $location = $this->yellow->config->get("serverBase").$this->yellow->config->get("pluginLocation")."webinterface"; + $output = "<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\"".htmlspecialchars($location).".css\" />\n"; + $output .= "<script type=\"text/javascript\" src=\"".htmlspecialchars($location).".js\"></script>\n"; + $output .= "<script type=\"text/javascript\">\n"; + $output .= "// <![CDATA[\n"; + $output .= "yellow.page = ".json_encode($this->getPageData()).";\n"; + $output .= "yellow.config = ".json_encode($this->getConfigData()).";\n"; + $output .= "yellow.text = ".json_encode($this->getTextData()).";\n"; + if(defined("DEBUG") && DEBUG>=1) $output .= "yellow.debug = ".json_encode(DEBUG).";\n"; + $output .= "// ]]>\n"; + $output .= "</script>\n"; } return $output; } @@ -135,20 +139,28 @@ class YellowWebinterface list($dummy, $command, $email, $password, $name, $language, $status, $home) = $args; if(!empty($email) && !empty($password)) { - $fileName = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile"); - $algorithm = $this->yellow->config->get("webinterfaceUserHashAlgorithm"); - $cost = $this->yellow->config->get("webinterfaceUserHashCost"); - $hash = $this->yellow->toolbox->createHash($password, $algorithm, $cost); - if(empty($hash)) + $userExisting = $this->users->isExisting($email); + $status = $this->getUserAccount($email, $password, $command); + switch($status) { - $statusCode = 500; - echo "ERROR creating hash: Algorithm '$algorithm' not supported!\n"; - } else { - $statusCode = $this->users->createUser($fileName, $email, $hash, $name, $language, $status, $home) ? 200 : 500; - if($statusCode != 200) echo "ERROR updating configuration: Can't write file '$fileName'!\n"; + case "invalid": echo "ERROR updating configuration: Please enter a valid email!\n"; break; + case "weak": echo "ERROR updating configuration: Please enter a different password!\n"; break; } + if($status == "ok") + { + $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile"); + $status = $this->users->update($fileNameUser, $email, $password, $name, $language, $status, $home) ? "ok" : "error"; + if($status == "error") echo "ERROR updating configuration: Can't write file '$fileNameUser'!\n"; + } + if($status == "ok") + { + $algorithm = $this->yellow->config->get("webinterfaceUserHashAlgorithm"); + $status = substru($this->users->getHash($email), 0, 5)!="error-hash" ? "ok" : "error"; + if($status == "error") echo "ERROR updating configuration: Hash algorithm '$algorithm' not supported!\n"; + } + $statusCode = $status=="ok" ? 200 : 500; echo "Yellow $command: User account ".($statusCode!=200 ? "not " : ""); - echo ($this->users->isExisting($email) ? "updated" : "created")."\n"; + echo ($userExisting ? "updated" : "created")."\n"; } else { $statusCode = 200; foreach($this->getUserData() as $line) echo "$line\n"; @@ -161,28 +173,36 @@ class YellowWebinterface function processRequest($serverScheme, $serverName, $base, $location, $fileName) { $statusCode = 0; - if($this->checkUser($location, $fileName)) + if($this->isActive() && $this->checkUser($location, $fileName)) { - switch($_POST["action"]) + switch($_REQUEST["action"]) + { + case "": $statusCode = $this->processRequestShow($serverScheme, $serverName, $base, $location, $fileName); break; + case "login": $statusCode = $this->processRequestLogin($serverScheme, $serverName, $base, $location, $fileName); break; + case "logout": $statusCode = $this->processRequestLogout($serverScheme, $serverName, $base, $location, $fileName); break; + case "signup": $statusCode = $this->processRequestSignup($serverScheme, $serverName, $base, $location, $fileName); break; + case "confirm": $statusCode = $this->processRequestConfirm($serverScheme, $serverName, $base, $location, $fileName); break; + case "approve": $statusCode = $this->processRequestApprove($serverScheme, $serverName, $base, $location, $fileName); break; + case "recover": $statusCode = $this->processRequestRecover($serverScheme, $serverName, $base, $location, $fileName); break; + case "create": $statusCode = $this->processRequestCreate($serverScheme, $serverName, $base, $location, $fileName); break; + case "edit": $statusCode = $this->processRequestEdit($serverScheme, $serverName, $base, $location, $fileName); break; + case "delete": $statusCode = $this->processRequestDelete($serverScheme, $serverName, $base, $location, $fileName); break; + case "install": $statusCode = $this->processRequestInstall($serverScheme, $serverName, $base, $location, $fileName); break; + } + } else { + switch($_REQUEST["action"]) { - case "": $statusCode = $this->processRequestShow($serverScheme, $serverName, $base, $location, $fileName); break; - case "create": $statusCode = $this->processRequestCreate($serverScheme, $serverName, $base, $location, $fileName); break; - case "edit": $statusCode = $this->processRequestEdit($serverScheme, $serverName, $base, $location, $fileName); break; - case "delete": $statusCode = $this->processRequestDelete($serverScheme, $serverName, $base, $location, $fileName); break; - case "login": $statusCode = $this->processRequestLogin($serverScheme, $serverName, $base, $location, $fileName); break; - case "logout": $statusCode = $this->processRequestLogout($serverScheme, $serverName, $base, $location, $fileName); break; + case "signup": $statusCode = $this->processRequestSignup($serverScheme, $serverName, $base, $location, $fileName); break; + case "confirm": $statusCode = $this->processRequestConfirm($serverScheme, $serverName, $base, $location, $fileName); break; + case "approve": $statusCode = $this->processRequestApprove($serverScheme, $serverName, $base, $location, $fileName); break; + case "recover": $statusCode = $this->processRequestRecover($serverScheme, $serverName, $base, $location, $fileName); break; + case "install": $statusCode = $this->processRequestInstall($serverScheme, $serverName, $base, $location, $fileName); break; } } if($statusCode == 0) { $statusCode = $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false); - if($this->users->getNumber()) - { - if($this->userLoginFailed) $this->yellow->page->error(500, "Login failed, [please log in](javascript:yellow.action('login');)!"); - } else { - $url = $this->yellow->text->get("webinterfaceUserAccountUrl"); - $this->yellow->page->error(500, "You are not authorised on this server, [please add a user account]($url)!"); - } + if($this->loginAction == "fail") $this->yellow->page->error(500, "Login failed, [please log in](javascript:yellow.action('login');)!"); } return $statusCode; } @@ -202,7 +222,7 @@ class YellowWebinterface $location = $this->yellow->lookup->normaliseUrl($serverScheme, $serverName, $base, $location); $this->yellow->sendStatus($statusCode, $location); } else { - $statusCode = $this->userPermission ? 424 : 404; + $statusCode = $this->userRestrictions ? 404 : 424; $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false); $this->yellow->page->error($statusCode); } @@ -210,14 +230,158 @@ class YellowWebinterface return $statusCode; } + // Process request for user login + function processRequestLogin($serverScheme, $serverName, $base, $location, $fileName) + { + $statusCode = 0; + $home = $this->users->getHome(); + if(substru($location, 0, strlenu($home)) == $home) + { + $statusCode = 303; + $location = $this->yellow->lookup->normaliseUrl($serverScheme, $serverName, $base, $location); + $this->yellow->sendStatus($statusCode, $location); + } else { + $statusCode = 302; + $location = $this->yellow->lookup->normaliseUrl($serverScheme, $serverName, $base, $home); + $this->yellow->sendStatus($statusCode, $location); + } + return $statusCode; + } + + // Process request for user logout + function processRequestLogout($serverScheme, $serverName, $base, $location, $fileName) + { + $statusCode = 302; + $this->users->destroyCookie("login"); + $this->users->email = ""; + $location = $this->yellow->lookup->normaliseUrl( + $this->yellow->config->get("serverScheme"), + $this->yellow->config->get("serverName"), + $this->yellow->config->get("serverBase"), $location); + $this->yellow->sendStatus($statusCode, $location); + return $statusCode; + } + + // Process request for user signup + function processRequestSignup($serverScheme, $serverName, $base, $location, $fileName) + { + $this->loginAction = "signup"; + $this->loginStatus = "ok"; + $name = trim(preg_replace("/[^\pL\d\-\. ]/u", "-", $_REQUEST["name"])); + $email = trim($_REQUEST["email"]); + $password = trim($_REQUEST["password"]); + if(empty($name) || empty($email) || empty($password)) $this->loginStatus = "incomplete"; + if($this->loginStatus == "ok") $this->loginStatus = $this->getUserAccount($email, $password, $this->loginAction); + if($this->loginStatus == "ok" && !$this->isExtra()) $this->loginStatus = "next"; + if($this->loginStatus == "ok" && $this->users->isExisting($email)) $this->loginStatus = "next"; + if($this->loginStatus == "ok") + { + $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile"); + $this->loginStatus = $this->users->update($fileNameUser, $email, $password, $name, "", "unconfirmed") ? "ok" : "error"; + if($this->loginStatus == "error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!"); + } + if($this->loginStatus == "ok") + { + $this->loginStatus = $this->sendMail($serverScheme, $serverName, $base, $email, "confirm") ? "next" : "error"; + if($this->loginStatus == "error") $this->yellow->page->error(500, "Can't send email on this server!"); + } + $statusCode = $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false); + return $statusCode; + } + + // Process request to confirm user signup + function processRequestConfirm($serverScheme, $serverName, $base, $location, $fileName) + { + $this->loginAction = "confirm"; + $this->loginStatus = "ok"; + $email = $_REQUEST["email"]; + $this->loginStatus = $this->getUserRequest($email, $_REQUEST["action"], $_REQUEST["expire"], $_REQUEST["id"]); + if($this->loginStatus == "ok") + { + $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile"); + $this->loginStatus = $this->users->update($fileNameUser, $email, "", "", "", "unapproved") ? "ok" : "error"; + if($this->loginStatus == "error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!"); + } + if($this->loginStatus == "ok") + { + $this->loginStatus = $this->sendMail($serverScheme, $serverName, $base, $email, "approve") ? "done" : "error"; + if($this->loginStatus == "error") $this->yellow->page->error(500, "Can't send email on this server!"); + } + $statusCode = $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false); + return $statusCode; + } + + // Process request to approve user signup + function processRequestApprove($serverScheme, $serverName, $base, $location, $fileName) + { + $this->loginAction = "approve"; + $this->loginStatus = "ok"; + $email = $_REQUEST["email"]; + $this->loginStatus = $this->getUserRequest($email, $_REQUEST["action"], $_REQUEST["expire"], $_REQUEST["id"]); + if($this->loginStatus == "ok") + { + $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile"); + $this->loginStatus = $this->users->update($fileNameUser, $email, "", "", "", "active") ? "ok" : "error"; + if($this->loginStatus == "error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!"); + } + if($this->loginStatus == "ok") + { + $this->loginStatus = $this->sendMail($serverScheme, $serverName, $base, $email, "welcome") ? "done" : "error"; + if($this->loginStatus == "error") $this->yellow->page->error(500, "Can't send email on this server!"); + } + $statusCode = $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false); + return $statusCode; + } + + // Process request to recover password + function processRequestRecover($serverScheme, $serverName, $base, $location, $fileName) + { + $this->loginAction = "recover"; + $this->loginStatus = "ok"; + $email = trim($_REQUEST["email"]); + $password = trim($_REQUEST["password"]); + if(empty($_REQUEST["id"])) + { + if(!filter_var($email, FILTER_VALIDATE_EMAIL)) $this->loginStatus = "invalid"; + if($this->loginStatus == "ok" && !$this->isExtra()) $this->loginStatus = "next"; + if($this->loginStatus == "ok" && !$this->users->isExisting($email)) $this->loginStatus = "next"; + if($this->loginStatus == "ok") + { + $this->loginStatus = $this->sendMail($serverScheme, $serverName, $base, $email, "recover") ? "next" : "error"; + if($this->loginStatus == "error") $this->yellow->page->error(500, "Can't send email on this server!"); + } + } else { + $this->loginStatus = $this->getUserRequest($email, $_REQUEST["action"], $_REQUEST["expire"], $_REQUEST["id"]); + if($this->loginStatus == "ok") + { + if(empty($password)) $this->loginStatus = "password"; + if($this->loginStatus == "ok") $this->loginStatus = $this->getUserAccount($email, $password, $this->loginAction); + if($this->loginStatus == "ok") + { + $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile"); + $this->loginStatus = $this->users->update($fileNameUser, $email, $password) ? "ok" : "error"; + if($this->loginStatus == "error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!"); + } + if($this->loginStatus == "ok") + { + $this->loginStatus = $this->sendMail($serverScheme, $serverName, $base, $email, "information") ? "done" : "error"; + if($this->loginStatus == "error") $this->yellow->page->error(500, "Can't send email on this server!"); + } + } + } + $statusCode = $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false); + return $statusCode; + } + // Process request to create page function processRequestCreate($serverScheme, $serverName, $base, $location, $fileName) { $statusCode = 0; - if($this->userPermission && !empty($_POST["rawdataedit"])) + if(!$this->userRestrictions && !empty($_POST["rawdataedit"])) { $this->rawDataSource = $this->rawDataEdit = rawurldecode($_POST["rawdatasource"]); - $page = $this->getPageNew($serverScheme, $serverName, $base, $location, $fileName, rawurldecode($_POST["rawdataedit"])); + $rawData = $this->normaliseText(rawurldecode($_POST["rawdataedit"])); + $page = $this->getPageNew($serverScheme, $serverName, $base, $location, $fileName, $rawData); if(!$page->isError()) { if($this->yellow->toolbox->createFile($page->fileName, $page->rawData)) @@ -232,7 +396,7 @@ class YellowWebinterface } } else { $statusCode = 500; - $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, $false); + $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false); $this->yellow->page->error($statusCode, $page->get("pageError")); } } @@ -243,10 +407,10 @@ class YellowWebinterface function processRequestEdit($serverScheme, $serverName, $base, $location, $fileName) { $statusCode = 0; - if($this->userPermission && !empty($_POST["rawdataedit"])) + if(!$this->userRestrictions && !empty($_POST["rawdataedit"])) { $this->rawDataSource = rawurldecode($_POST["rawdatasource"]); - $this->rawDataEdit = rawurldecode($_POST["rawdataedit"]); + $this->rawDataEdit = $this->normaliseText(rawurldecode($_POST["rawdataedit"])); $page = $this->getPageUpdate($serverScheme, $serverName, $base, $location, $fileName, $this->rawDataSource, $this->rawDataEdit, $this->yellow->toolbox->readFile($fileName)); if(!$page->isError()) @@ -275,7 +439,7 @@ class YellowWebinterface function processRequestDelete($serverScheme, $serverName, $base, $location, $fileName) { $statusCode = 0; - if($this->userPermission) + if(!$this->userRestrictions) { $this->rawDataSource = $this->rawDataEdit = rawurldecode($_POST["rawdatasource"]); if(!is_file($fileName) || $this->yellow->toolbox->deleteFile($fileName)) @@ -292,48 +456,118 @@ class YellowWebinterface return $statusCode; } - // Process request for user login - function processRequestLogin($serverScheme, $serverName, $base, $location, $fileName) + // Process request to install + function processRequestInstall($serverScheme, $serverName, $base, $location, $fileName) { $statusCode = 0; - $home = $this->users->getHome(); - if(substru($location, 0, strlenu($home)) == $home) + if($this->yellow->config->get("installationMode") && !$this->yellow->isStaticFile($location, $fileName, false)) { - $statusCode = 303; - $location = $this->yellow->lookup->normaliseUrl($serverScheme, $serverName, $base, $location); - $this->yellow->sendStatus($statusCode, $location); - } else { - $statusCode = 302; - $location = $this->yellow->lookup->normaliseUrl($serverScheme, $serverName, $base, $home); - $this->yellow->sendStatus($statusCode, $location); + $fileName = $this->yellow->config->get("configDir")."page-installation.txt"; + $this->yellow->pages->pages["root/"] = array(); + $this->yellow->page = new YellowPage($this->yellow); + $this->yellow->page->setRequestInformation($serverScheme, $serverName, $base, $location, $fileName); + $this->yellow->page->parseData($this->getRawDataInstallation($fileName, $this->yellow->getRequestLanguage()), false, 404); + $this->yellow->page->parserSafeMode = false; + $this->yellow->page->parseContent(); + $author = trim($_REQUEST["author"]); + $email = trim($_REQUEST["email"]); + $password = trim($_REQUEST["password"]); + $language = trim($_REQUEST["language"]); + $status = trim($_REQUEST["status"]); + if($status == "install") + { + $status = "ok"; + $fileNamePage = $this->yellow->lookup->findFileFromLocation("/"); + $rawData = strreplaceu("\\n", "\n", $this->yellow->text->getText("webinterfaceInstallationHomePage", "en")); + if($this->yellow->toolbox->readFile($fileNamePage)==$rawData && $language!="en") + { + $rawData = strreplaceu("\\n", "\n", $this->yellow->text->getText("webinterfaceInstallationHomePage", $language)); + $status = $this->yellow->toolbox->createFile($fileNamePage, $rawData) ? "ok" : "error"; + if($status == "error") $this->yellow->page->error(500, "Can't write file '$fileNamePage'!"); + } + } + if($status == "ok") + { + if($this->getUserAccount($email, $password, "install") == "ok") + { + $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile"); + $status = $this->users->update($fileNameUser, $email, $password, $author, $language, "active", "/") ? "ok" : "error"; + if($status == "error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!"); + } + } + if($status == "ok") + { + $fileNameConfig = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile"); + $status = $this->yellow->config->update($fileNameConfig, $this->getInstallationData()) ? "done" : "error"; + if($status == "error") $this->yellow->page->error(500, "Can't write file '$fileNameConfig'!"); + } + if($status == "done") + { + $statusCode = 303; + $location = $this->yellow->lookup->normaliseUrl($serverScheme, $serverName, $base, $location); + $this->yellow->sendStatus($statusCode, $location); + } else { + $statusCode = $this->yellow->sendPage(); + } } return $statusCode; } - - // Process request for user logout - function processRequestLogout($serverScheme, $serverName, $base, $location, $fileName) + + // Send mail to web interface user + function sendMail($serverScheme, $serverName, $base, $email, $action) { - $statusCode = 302; - $this->users->destroyCookie("login"); - $this->users->email = ""; - $location = $this->yellow->lookup->normaliseUrl( - $this->yellow->config->get("serverScheme"), - $this->yellow->config->get("serverName"), - $this->yellow->config->get("serverBase"), $location); - $this->yellow->sendStatus($statusCode, $location); - return $statusCode; + if($action=="welcome" || $action == "information") + { + $url = "$serverScheme://$serverName$base/"; + } else { + $expire = time()+60*60*24*30; + $id = $this->users->createRequestId($email, $action, $expire); + $url = "$serverScheme://$serverName$base"."/action:$action/email:$email/expire:$expire/id:$id"; + } + if($action == "approve") + { + $account = $email; + $name = $this->yellow->config->get("author"); + $email = $this->yellow->config->get("email"); + } else { + $account = $email; + $name = $this->users->getName($email); + } + $language = $this->users->getLanguage($email); + if(!$this->yellow->text->isLanguage($language)) $language = $this->yellow->config->get("language"); + $sitename = $this->yellow->config->get("sitename"); + $prefix = "webinterface".ucfirst($action); + $message = $this->yellow->text->getText("{$prefix}Message", $language); + $message = preg_replace("/@useraccount/i", $account, $message); + $message = preg_replace("/@usershort/i", strtok($name, " "), $message); + $message = preg_replace("/@username/i", $name, $message); + $message = preg_replace("/@userlanguage/i", $language, $message); + $mailTo = mb_encode_mimeheader("$name <$email>"); + $mailSubject = mb_encode_mimeheader($this->yellow->text->getText("{$prefix}Subject", $language)); + $mailHeaders = mb_encode_mimeheader("From: $sitename <noreply>")."\r\n"; + $mailHeaders .= mb_encode_mimeheader("X-Request-Url: $serverScheme://$serverName$base")."\r\n"; + $mailHeaders .= mb_encode_mimeheader("X-Remote-Addr: $_SERVER[REMOTE_ADDR]")."\r\n"; + $mailHeaders .= "Mime-Version: 1.0\r\n"; + $mailHeaders .= "Content-Type: text/plain; charset=utf-8\r\n"; + $mailMessage = "$message\r\n\r\n$url\r\n-- \r\n$sitename"; + return mail($mailTo, $mailSubject, $mailMessage, $mailHeaders); } // Check web interface request function checkRequest($location) { - if($this->yellow->toolbox->getServerScheme()==$this->yellow->config->get("webinterfaceServerScheme") && - $this->yellow->toolbox->getServerName()==$this->yellow->config->get("webinterfaceServerName")) + if($this->yellow->config->get("installationMode")) { - $locationLength = strlenu($this->yellow->config->get("webinterfaceLocation")); - $this->active = substru($location, 0, $locationLength) == $this->yellow->config->get("webinterfaceLocation"); + $_REQUEST["action"] = "install"; + } else { + if($this->yellow->toolbox->getServerScheme()==$this->yellow->config->get("webinterfaceServerScheme") && + $this->yellow->toolbox->getServerName()==$this->yellow->config->get("webinterfaceServerName")) + { + $locationLength = strlenu($this->yellow->config->get("webinterfaceLocation")); + $this->active = substru($location, 0, $locationLength) == $this->yellow->config->get("webinterfaceLocation"); + } } - return $this->isActive(); + return $this->yellow->config->get("installationMode") || $this->isActive(); } // Check web interface user @@ -347,62 +581,82 @@ class YellowWebinterface { $this->users->createCookie("login", $email); $this->users->email = $email; - $this->userPermission = $this->getUserPermission($location, $fileName); + $this->userRestrictions = $this->getUserRestrictions($email, $location, $fileName); } else { - $this->userLoginFailed = true; + $this->loginAction = "fail"; } } else if(isset($_COOKIE["login"])) { - list($email, $session) = $this->users->getCookieInformation($_COOKIE["login"]); + list($email, $session) = explode(',', $_COOKIE["login"], 2); if($this->users->checkCookie($email, $session)) { $this->users->email = $email; - $this->userPermission = $this->getUserPermission($location, $fileName); + $this->userRestrictions = $this->getUserRestrictions($email, $location, $fileName); } else { - $this->userLoginFailed = true; + $this->loginAction = "fail"; } } return $this->isUser(); } - // Return permission to change page - function getUserPermission($location, $fileName) + // Return user account request + function getUserRequest($email, $action, $expire, $id) { - $userPermission = NULL; + $loginStatus = $this->users->checkRequest($email, $action, $expire, $id) ? "ok" : "done"; + if($loginStatus=="done" && $expire<=time()) $loginStatus = "expire"; + return $loginStatus; + } + + // Return user account changes + function getUserAccount($email, $password, $action) + { + $loginStatus = NULL; foreach($this->yellow->plugins->plugins as $key=>$value) { - if(method_exists($value["obj"], "onUserPermission")) + if(method_exists($value["obj"], "onUserAccount")) { - $userPermission = $value["obj"]->onUserPermission($location, $fileName, $this->users); - if(!is_null($userPermission)) break; + $loginStatus = $value["obj"]->onUserAccount($email, $password, $action, $status, $this->users); + if(!is_null($loginStatus)) break; } } - if(is_null($userPermission)) + if(is_null($loginStatus)) { - $userPermission = is_dir(dirname($fileName)) && strlenu(basename($fileName))<128; - $userPermission &= substru($location, 0, strlenu($this->users->getHome())) == $this->users->getHome(); + $loginStatus = "ok"; + if(strlenu($password)<$this->yellow->config->get("webinterfaceUserPasswordMinLength")) $loginStatus = "weak"; + if(!filter_var($email, FILTER_VALIDATE_EMAIL)) $loginStatus = "invalid"; } - return $userPermission; + return $loginStatus; } - // Return user data - function getUserData() + // Return user restrictions to change page + function getUserRestrictions($email, $location, $fileName) { - $data = array(); - foreach($this->users->users as $key=>$value) + $userRestrictions = NULL; + foreach($this->yellow->plugins->plugins as $key=>$value) { - $data[$key] = "$value[email] - $value[name] $value[language] $value[status] $value[home]"; + if(method_exists($value["obj"], "onUserRestrictions")) + { + $userRestrictions = $value["obj"]->onUserRestrictions($email, $location, $fileName, $this->users); + if(!is_null($userRestrictions)) break; + } } - usort($data, strnatcasecmp); - return $data; + if(is_null($userRestrictions)) + { + $userRestrictions = !is_dir(dirname($fileName)) || strlenu(basename($fileName))>128; + $userRestrictions |= substru($location, 0, strlenu($this->users->getHome())) != $this->users->getHome(); + } + return $userRestrictions; } // Update request information function updateRequestInformation() { - $serverScheme = $this->yellow->config->get("webinterfaceServerScheme"); - $serverName = $this->yellow->config->get("webinterfaceServerName"); - $base = rtrim($this->yellow->config->get("serverBase").$this->yellow->config->get("webinterfaceLocation"), '/'); - $this->yellow->page->base = $base; + if($this->isActive()) + { + $serverScheme = $this->yellow->config->get("webinterfaceServerScheme"); + $serverName = $this->yellow->config->get("webinterfaceServerName"); + $base = rtrim($this->yellow->config->get("serverBase").$this->yellow->config->get("webinterfaceLocation"), '/'); + $this->yellow->page->base = $base; + } return $this->yellow->getRequestInformation($serverScheme, $serverName, $base); } @@ -461,7 +715,10 @@ class YellowWebinterface if(!$ok) $page->error(500, "Page '".$page->get("title")."' can not be created!"); } } - if(!$this->getUserPermission($page->location, $page->fileName)) $page->error(500, "Page '".$page->get("title")."' is not allowed!"); + if($this->getUserRestrictions($this->users->email, $page->location, $page->fileName)) + { + $page->error(500, "Page '".$page->get("title")."' is not allowed!"); + } return $page; } @@ -495,10 +752,43 @@ class YellowWebinterface } } } - if(!$this->getUserPermission($page->location, $page->fileName)) $page->error(500, "Page '".$page->get("title")."' is not allowed!"); + if($this->getUserRestrictions($this->users->email, $page->location, $page->fileName)) + { + $page->error(500, "Page '".$page->get("title")."' is not allowed!"); + } return $page; } + // Return raw data for installation page + function getRawDataInstallation($fileName, $language) + { + $fileData = $this->yellow->toolbox->readFile($fileName); + if(empty($fileData)) + { + $this->yellow->text->setLanguage($language); + $fileData = "---\nTitle:".$this->yellow->text->get("webinterfaceInstallationTitle")."\nLanguage:$language\nNavigation:navigation\n---\n"; + $fileData .= "<form class=\"installation-form\" action=\"".$this->yellow->page->getLocation()."\" method=\"post\">\n"; + $fileData .= "<p><label for=\"sitename\">".$this->yellow->text->get("webinterfaceInstallationSitename")."</label><br /><input class=\"form-control\" type=\"text\" name=\"sitename\" id=\"sitename\" value=\"".$this->yellow->config->getHtml("sitename")."\"></p>\n"; + $fileData .= "<p><label for=\"author\">".$this->yellow->text->get("webinterfaceInstallationAuthor")."</label><br /><input class=\"form-control\" type=\"text\" maxlength=\"64\" name=\"author\" id=\"author\" value=\"\"></p>\n"; + $fileData .= "<p><label for=\"email\">".$this->yellow->text->get("webinterfaceLoginEmail")."</label><br /><input class=\"form-control\" type=\"text\" maxlength=\"64\" name=\"email\" id=\"email\" value=\"\"></p>\n"; + $fileData .= "<p><label for=\"password\">".$this->yellow->text->get("webinterfaceLoginPassword")."</label><br /><input class=\"form-control\" type=\"password\" maxlength=\"64\" name=\"password\" id=\"password\" value=\"\"></p>\n"; + if(count($this->yellow->text->getLanguages()) > 1) + { + $fileData .= "<p>"; + foreach($this->yellow->text->getLanguages() as $language) + { + $checked = $language==$this->yellow->text->language ? " checked=\"checked\"" : ""; + $fileData .= "<label for=\"$language\"><input type=\"radio\" name=\"language\" id=\"$language\" value=\"$language\"$checked> ".$this->yellow->text->getTextHtml("languageDescription", $language)."</label><br />"; + } + $fileData .= "</p>\n"; + } + $fileData .= "<input class=\"btn\" type=\"submit\" value=\"".$this->yellow->text->get("webinterfaceOkButton")."\" />\n"; + $fileData .= "<input type=\"hidden\" name=\"status\" value=\"install\" />\n"; + $fileData .= "</form>\n"; + } + return $fileData; + } + // Return raw data for new page function getRawDataNew($title = "") { @@ -509,13 +799,14 @@ class YellowWebinterface $fileData = $this->yellow->toolbox->readFile($fileName); $fileData = preg_replace("/@datetime/i", date("Y-m-d H:i:s"), $fileData); $fileData = preg_replace("/@date/i", date("Y-m-d"), $fileData); + $fileData = preg_replace("/@usershort/i", strtok($this->users->getName(), " "), $fileData); $fileData = preg_replace("/@username/i", $this->users->getName(), $fileData); $fileData = preg_replace("/@userlanguage/i", $this->users->getLanguage(), $fileData); if(!empty($title)) $fileData = $this->updateDataTitle($fileData, $title); return $fileData; } - // Return page data including webinterface information + // Return page data including login information function getPageData() { $data = array(); @@ -525,10 +816,14 @@ class YellowWebinterface $data["rawDataSource"] = $this->rawDataSource; $data["rawDataEdit"] = $this->rawDataEdit; $data["rawDataNew"] = $this->getRawDataNew(); - $data["userPermission"] = $this->userPermission; + $data["userRestrictions"] = $this->userRestrictions; $data["pageFile"] = $this->yellow->page->get("pageFile"); $data["parserSafeMode"] = $this->yellow->page->parserSafeMode; $data["statusCode"] = $this->yellow->page->statusCode; + } else { + $data["loginAction"] = $this->loginAction; + $data["loginStatus"] = $this->loginStatus; + if($this->loginAction != "none") $data = array_merge($data, $this->getRequestData()); } return $data; } @@ -550,13 +845,54 @@ class YellowWebinterface $data["serverTime"] = $this->yellow->config->get("serverTime"); $data["serverLanguages"] = $this->yellow->text->getLanguages(); } else { - $data["login"] = $this->yellow->page->statusCode==200; $data["loginEmail"] = $this->yellow->config->get("loginEmail"); $data["loginPassword"] = $this->yellow->config->get("loginPassword"); + $data["loginExtra"] = intval($this->isExtra()); + } + return $data; + } + + // Return installation data + function getInstallationData() + { + $data = array(); + foreach($_REQUEST as $key=>$value) + { + if(!$this->yellow->config->isExisting($key)) continue; + $data[$key] = trim($value); + } + $data["# serverScheme"] = $this->yellow->toolbox->getServerScheme(); + $data["# serverName"] = $this->yellow->toolbox->getServerName(); + $data["# serverBase"] = $this->yellow->toolbox->getServerBase(); + $data["# serverTime"] = $this->yellow->toolbox->getServerTime(); + $data["installationMode"] = "0"; + return $data; + } + + // Return request strings + function getRequestData() + { + $data = array(); + foreach($_REQUEST as $key=>$value) + { + if($key == "password") continue; + $data["request".ucfirst($key)] = trim($value); } return $data; } + // Return user data + function getUserData() + { + $data = array(); + foreach($this->users->users as $key=>$value) + { + $data[$key] = "$value[email] - $value[name] $value[language] $value[status] $value[home]"; + } + usort($data, strnatcasecmp); + return $data; + } + // Return text strings function getTextData() { @@ -568,11 +904,27 @@ class YellowWebinterface return array_merge($textLanguage, $textWebinterface, $textYellow); } + // Normlise text with special characters + function normaliseText($text) + { + if($this->yellow->plugins->isExisting("emojiawesome")) + { + $text = $this->yellow->plugins->get("emojiawesome")->normaliseText($text, true, false); + } + return $text; + } + // Check if web interface request function isActive() { return $this->active; } + + // Check if extra login features + function isExtra() + { + return strposu($this->yellow->config->get("email"), '@') !== false; + } // Check if user is logged in function isUser() @@ -612,6 +964,49 @@ class YellowUsers } } + // Update users in file + function update($fileName, $email, $password = "", $name = "", $language = "", $status = "", $home = "") + { + if(!empty($password)) + { + $algorithm = $this->yellow->config->get("webinterfaceUserHashAlgorithm"); + $cost = $this->yellow->config->get("webinterfaceUserHashCost"); + $hash = $this->yellow->toolbox->createHash($password, $algorithm, $cost); + if(empty($hash)) $hash = "error-hash-algorithm-$algorithm"; + } + if($this->isExisting($email)) + { + $email = strreplaceu(',', '-', $email); + $hash = strreplaceu(',', '-', empty($hash) ? $this->users[$email]["hash"] : $hash); + $name = strreplaceu(',', '-', empty($name) ? $this->users[$email]["name"] : $name); + $language = strreplaceu(',', '-', empty($language) ? $this->users[$email]["language"] : $language); + $status = strreplaceu(',', '-', empty($status) ? $this->users[$email]["status"] : $status); + $home = strreplaceu(',', '-', empty($home) ? $this->users[$email]["home"] : $home); + } else { + $email = strreplaceu(',', '-', empty($email) ? "none" : $email); + $hash = strreplaceu(',', '-', empty($hash) ? "none" : $hash); + $name = strreplaceu(',', '-', empty($name) ? $this->yellow->config->get("sitename") : $name); + $language = strreplaceu(',', '-', empty($language) ? $this->yellow->config->get("language") : $language); + $status = strreplaceu(',', '-', empty($status) ? $this->yellow->config->get("webinterfaceUserStatus") : $status); + $home = strreplaceu(',', '-', empty($home) ? $this->yellow->config->get("webinterfaceUserHome") : $home); + } + $this->set($email, $hash, $name, $language, $status, $home); + $fileData = $this->yellow->toolbox->readFile($fileName); + foreach($this->yellow->toolbox->getTextLines($fileData) as $line) + { + preg_match("/^(.*?)\s*:\s*(.*?),\s*(.*?),\s*(.*?),\s*(.*?),\s*(.*?)\s*$/", $line, $matches); + if(!empty($matches[1]) && $matches[1]==$email) + { + $fileDataNew .= "$email: $hash,$name,$language,$status,$home\n"; + $found = true; + } else { + $fileDataNew .= $line; + } + } + if(!$found) $fileDataNew .= "$email: $hash,$name,$language,$status,$home\n"; + return $this->yellow->toolbox->createFile($fileName, $fileDataNew); + } + // Set user data function set($email, $hash, $name, $language, $status, $home) { @@ -624,42 +1019,6 @@ class YellowUsers $this->users[$email]["home"] = $home; } - // Create or update user in file - function createUser($fileName, $email, $hash, $name, $language, $status, $home) - { - $email = strreplaceu(',', '-', $email); - $hash = strreplaceu(',', '-', $hash); - $fileData = $this->yellow->toolbox->readFile($fileName); - foreach($this->yellow->toolbox->getTextLines($fileData) as $line) - { - preg_match("/^(.*?)\s*:\s*(.*?),\s*(.*?),\s*(.*?),\s*(.*?),\s*(.*?)\s*$/", $line, $matches); - if(!empty($matches[1]) && !empty($matches[2]) && !empty($matches[3]) && !empty($matches[4]) && - !empty($matches[5]) && !empty($matches[6])) - { - if($matches[1] == $email) - { - $name = strreplaceu(',', '-', empty($name) ? $matches[3] : $name); - $language = strreplaceu(',', '-', empty($language) ? $matches[4] : $language); - $status = strreplaceu(',', '-', empty($status) ? $matches[5] : $status); - $home = strreplaceu(',', '-', empty($home) ? $matches[6] : $home); - $fileDataNew .= "$email: $hash,$name,$language,$status,$home\n"; - $found = true; - continue; - } - } - $fileDataNew .= $line; - } - if(!$found) - { - $name = strreplaceu(',', '-', empty($name) ? $this->yellow->config->get("sitename") : $name); - $language = strreplaceu(',', '-', empty($language) ? $this->yellow->config->get("language") : $language); - $status = strreplaceu(',', '-', empty($status) ? "active" : $status); - $home = strreplaceu(',', '-', empty($home) ? $this->yellow->config->get("webinterfaceUserHome") : $home); - $fileDataNew .= "$email: $hash,$name,$language,$status,$home\n"; - } - return $this->yellow->toolbox->createFile($fileName, $fileDataNew); - } - // Check user login function checkUser($email, $password) { @@ -668,6 +1027,13 @@ class YellowUsers $this->yellow->toolbox->verifyHash($password, $algorithm, $this->users[$email]["hash"]); } + // Check user login from browser cookie + function checkCookie($email, $session) + { + return $this->isExisting($email) && $this->users[$email]["status"]=="active" && + $this->yellow->toolbox->verifyHash($this->users[$email]["hash"], "sha256", $session); + } + // Create browser cookie function createCookie($cookieName, $email) { @@ -689,20 +1055,26 @@ class YellowUsers setcookie($cookieName, "", time()-3600, $location, "", $serverScheme=="https"); } - // Return information from browser cookie - function getCookieInformation($cookie) + // Check user request + function checkRequest($email, $action, $expire, $id) { - return explode(',', $cookie, 2); + switch($action) + { + case "confirm": $status = "unconfirmed"; break; + case "approve": $status = "unapproved"; break; + case "recover": $status = "active"; break; + } + return $this->isExisting($email) && $this->users[$email]["status"]==$status && $expire>time() && + $this->yellow->toolbox->verifyHash($this->users[$email]["hash"].$action.$expire, "sha256", $id); } - // Check user login from browser cookie - function checkCookie($email, $session) + // Create user request ID + function createRequestId($email, $action, $expire) { - return $this->isExisting($email) && $this->users[$email]["status"]=="active" && - $this->yellow->toolbox->verifyHash($this->users[$email]["hash"], "sha256", $session); + return $this->yellow->toolbox->createHash($this->users[$email]["hash"].$action.$expire, "sha256"); } - // Retun user login information + // Retun user login information, TODO: this is an obsolete function and will be removed soon function getUserInfo($email, $password, $name, $language, $home) { $algorithm = $this->yellow->config->get("webinterfaceUserHashAlgorithm"); @@ -714,13 +1086,20 @@ class YellowUsers $hash = strreplaceu(',', '-', $hash); $name = strreplaceu(',', '-', empty($name) ? $this->yellow->config->get("sitename") : $name); $language = strreplaceu(',', '-', empty($language) ? $this->yellow->config->get("language") : $language); - $status = strreplaceu(',', '-', empty($status) ? "active" : $status); + $status = strreplaceu(',', '-', empty($status) ? $this->yellow->config->get("webinterfaceUserStatus") : $status); $home = strreplaceu(',', '-', empty($home) ? $this->yellow->config->get("webinterfaceUserHome") : $home); $user = "$email: $hash,$name,$language,$status,$home\n"; } return $user; } + // Return user hash + function getHash($email = "") + { + if(empty($email)) $email = $this->email; + return $this->isExisting($email) ? $this->users[$email]["hash"] : ""; + } + // Return user name function getName($email = "") { diff --git a/system/themes/snippets/footer.php b/system/themes/snippets/footer.php @@ -1,7 +1,7 @@ <div class="footer"> <a href="<?php echo $yellow->page->base."/" ?>">&copy; 2016 <?php echo $yellow->page->getHtml("sitename") ?></a>. <a href="<?php echo $yellow->page->get("pageEdit") ?>">Edit</a>. -<a href="http://datenstrom.se/yellow">Made with Yellow</a>. +<a href="<?php echo $yellow->text->get("yellowUrl") ?>">Made with Yellow</a>. </div> </div> <?php echo $yellow->page->getExtra("footer") ?>