2
0
Эх сурвалжийг харах

User Registration Frontend

Roman Hergenreder 3 жил өмнө
parent
commit
86f9e12b87

+ 21 - 22
core/Api/UserAPI.class.php

@@ -34,7 +34,7 @@ namespace Api {
         $row = $res[0];
         if (strcasecmp($username, $row['name']) === 0) {
           return $this->createError("This username is already taken.");
-        } else if (strcasecmp($username, $row['email']) === 0) {
+        } else if (strcasecmp($email, $row['email']) === 0) {
           return $this->createError("This email address is already in use.");
         }
       }
@@ -670,13 +670,14 @@ namespace Api\User {
       }
 
       parent::__construct($user, $externalCall, $parameters);
+      $this->csrfTokenRequired = false;
     }
 
     private function insertToken() {
       $validUntil = (new DateTime())->modify("+48 hour");
       $sql = $this->user->getSQL();
       $res = $sql->insert("UserToken", array("user_id", "token", "token_type", "valid_until"))
-        ->addRow($this->userId, $this->token, "confirmation", $validUntil)
+        ->addRow($this->userId, $this->token, "email_confirm", $validUntil)
         ->execute();
 
       $this->success = ($res !== FALSE);
@@ -732,33 +733,31 @@ namespace Api\User {
       $this->userId = $id;
       $this->token = generateRandomString(36);
       if ($this->insertToken()) {
-        return false;
-      }
-
-      $settings = $this->user->getConfiguration()->getSettings();
-      $baseUrl = htmlspecialchars($settings->getBaseUrl());
-      $siteName = htmlspecialchars($settings->getSiteName());
+        $settings = $this->user->getConfiguration()->getSettings();
+        $baseUrl = htmlspecialchars($settings->getBaseUrl());
+        $siteName = htmlspecialchars($settings->getSiteName());
 
-      if ($this->success) {
+        if ($this->success) {
 
-        $replacements = array(
-          "link" => "$baseUrl/confirmEmail?token=$this->token",
-          "site_name" => $siteName,
-          "base_url" => $baseUrl,
-          "username" => htmlspecialchars($username)
-        );
+          $replacements = array(
+            "link" => "$baseUrl/confirmEmail?token=$this->token",
+            "site_name" => $siteName,
+            "base_url" => $baseUrl,
+            "username" => htmlspecialchars($username)
+          );
 
-        foreach($replacements as $key => $value) {
-          $messageBody = str_replace("{{{$key}}}", $value, $messageBody);
-        }
+          foreach($replacements as $key => $value) {
+            $messageBody = str_replace("{{{$key}}}", $value, $messageBody);
+          }
 
-        $request = new \Api\Mail\Send($this->user);
-        $this->success = $request->execute(array(
+          $request = new \Api\Mail\Send($this->user);
+          $this->success = $request->execute(array(
             "to" => $email,
             "subject" => "[$siteName] E-Mail Confirmation",
             "body" => $messageBody
-        ));
-        $this->lastError = $request->getLastError();
+          ));
+          $this->lastError = $request->getLastError();
+        }
       }
 
       if (!$this->success) {

+ 1 - 1
core/Configuration/CreateDatabase.class.php

@@ -192,7 +192,7 @@ class CreateDatabase {
       ->addRow("User/edit", array(USER_GROUP_ADMIN), "Allows users to edit details and group memberships of any user")
       ->addRow("User/delete", array(USER_GROUP_ADMIN), "Allows users to delete any other user")
       ->addRow("Permission/fetch", array(USER_GROUP_ADMIN), "Allows users to list all API permissions")
-      ->addRow("Visitors/stats", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT), "Allowes users to see visitor statistics");
+      ->addRow("Visitors/stats", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT), "Allows users to see visitor statistics");
 
     return $queries;
   }

+ 14 - 2
core/Documents/Account.class.php

@@ -17,6 +17,7 @@ namespace Documents {
 namespace Documents\Account {
 
   use Elements\Head;
+  use Elements\Script;
   use Elements\SimpleBody;
 
   class AccountHead extends Head {
@@ -26,11 +27,21 @@ namespace Documents\Account {
     }
 
     protected function initSources() {
-
+      $this->loadJQuery();
+      $this->addJS(Script::CORE);
+      $this->addJS(Script::ACCOUNT);
+      $this->loadBootstrap();
+      $this->loadFontawesome();
     }
 
     protected function initMetas() {
-      return array();
+      return array(
+        array('name' => 'viewport', 'content' => 'width=device-width, initial-scale=1.0'),
+        array('name' => 'format-detection', 'content' => 'telephone=yes'),
+        array('charset' => 'utf-8'),
+        array("http-equiv" => 'expires', 'content' => '0'),
+        array("name" => 'robots', 'content' => 'noarchive'),
+      );
     }
 
     protected function initRawFields() {
@@ -49,6 +60,7 @@ namespace Documents\Account {
     }
 
     protected function getContent() {
+
       $view = $this->getDocument()->getView();
       if ($view === null) {
         return "The page you does not exist or is no longer valid. <a href='/'>Return to start page</a>";

+ 1 - 0
core/Elements/Script.class.php

@@ -11,6 +11,7 @@ class Script extends StaticView {
   const JQUERY    = "/js/jquery.min.js";
   const INSTALL   = "/js/install.js";
   const BOOTSTRAP = "/js/bootstrap.bundle.min.js";
+  const ACCOUNT   = "/js/account.js";
 
   private string $type;
   private string $content;

+ 43 - 0
core/Views/Account/AccountView.class.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace Views\Account;
+
+use Elements\Document;
+use Elements\View;
+
+abstract class AccountView extends View {
+
+  protected string $description;
+
+  public function __construct(Document $document, $loadView = true) {
+    parent::__construct($document, $loadView);
+    $this->description = "";
+  }
+
+  public function getCode() {
+    $html = parent::getCode();
+
+    $content = $this->getAccountContent();
+    $icon = $this->createIcon("user-plus", "fas", "fa-3x");
+
+    $html .= "<div class=\"container mt-5\">
+        <div class=\"row\">
+          <div class=\"col-md-4 py-5 bg-primary text-white text-center\" style='border-top-left-radius:.4em;border-bottom-left-radius:.4em'>
+            <div class=\"card-body\">
+              $icon
+              <h2 class=\"py-3\">$this->title</h2>
+              <p>$this->description</p>
+            </div>
+          </div>
+          <div class=\"col-md-8 pt-5 pb-2 border border-info\" style='border-top-right-radius:.4em;border-bottom-right-radius:.4em'>
+            $content
+            <div class='alert mt-2' style='display:none' id='alertMessage'></div>
+          </div>
+        </div>
+      </div>";
+
+    return $html;
+  }
+
+  protected abstract function getAccountContent();
+}

+ 40 - 4
core/Views/Account/Register.class.php

@@ -7,15 +7,51 @@ namespace Views\Account;
 use Elements\Document;
 use Elements\View;
 
-class Register extends View {
+class Register extends AccountView {
 
   public function __construct(Document $document, $loadView = true) {
     parent::__construct($document, $loadView);
+    $this->title = "Registration";
+    $this->description = "Create a new account";
   }
 
-  public function getCode() {
-    $html = parent::getCode();
+  public function loadView() {
+    parent::loadView();
 
-    return $html;
+    $document = $this->getDocument();
+    $settings = $document->getUser()->getConfiguration()->getSettings();
+    if ($settings->isRecaptchaEnabled()) {
+      $document->getHead()->loadGoogleRecaptcha($settings->getRecaptchaSiteKey());
+    }
+  }
+
+  public function getAccountContent() {
+
+    $settings = $this->getDocument()->getUser()->getConfiguration()->getSettings();
+    if (!$settings->isRegistrationAllowed()) {
+      return $this->createErrorText(
+        "Registration is not enabled on this website. If you are an administrator,
+        goto <a href=\"/admin/settings\">/admin/settings</a>, to enable the user registration"
+      );
+    }
+
+    return "<h4 class=\"pb-4\">Please fill with your details</h4>
+      <form>
+        <div class=\"form-group\">
+          <input id=\"username\" name=\"username\" placeholder=\"Username\" class=\"form-control\" type=\"text\" maxlength=\"32\">
+        </div>
+        <div class=\"form-group\">
+          <input type=\"email\" name='email' id='email' class=\"form-control\" placeholder=\"Email\" maxlength=\"64\">
+        </div>
+        <div class=\"form-group\">
+          <input type=\"password\" name='password' id='password' class=\"form-control\" placeholder=\"Password\">
+        </div>
+        <div class=\"form-group\">
+          <input type=\"password\" name='confirmPassword' id='confirmPassword' class=\"form-control\" placeholder=\"Confirm Password\">
+        </div>
+        <div class=\"form-group\">
+          <button type=\"button\" class=\"btn btn-success\" id='btnRegister'>Submit</button>
+        </div>
+     </form>";
   }
 }

+ 21 - 0
core/Views/Account/ResetPassword.class.php

@@ -0,0 +1,21 @@
+<?php
+
+
+namespace Views\Account;
+
+
+use Elements\Document;
+use Elements\View;
+
+class ResetPassword extends View {
+
+  public function __construct(Document $document, $loadView = true) {
+    parent::__construct($document, $loadView);
+  }
+
+  public function getCode() {
+    $html = parent::getCode();
+
+    return $html;
+  }
+}

+ 46 - 0
js/account.js

@@ -0,0 +1,46 @@
+$(document).ready(function () {
+
+    function showAlert(type, msg) {
+        let alert = $("#alertMessage");
+        alert.text(msg);
+        alert.attr("class", "mt-2 alert alert-" + type);
+        alert.show();
+    }
+
+    function hideAlert() {
+        $("#alertMessage").hide();
+    }
+
+    $("#btnRegister").click(function (e) {
+        e.preventDefault();
+        e.stopPropagation();
+
+        let btn = $(this);
+        let username = $("#username").val().trim();
+        let email = $("#email").val().trim();
+        let password = $("#password").val();
+        let confirmPassword = $("#confirmPassword").val();
+
+        if (username === '' || email === '' || password === '' || confirmPassword === '') {
+            showAlert("danger", "Please fill out every field.");
+        } else if(password !== confirmPassword) {
+            showAlert("danger", "Your passwords did not match.");
+        } else {
+            let textBefore = btn.text();
+            let params = { username: username, email: email, password: password, confirmPassword: confirmPassword };
+
+            btn.prop("disabled", true);
+            btn.html("Submitting… <i class='fas fa-spin fa-spinner'></i>")
+            jsCore.apiCall("user/register", params, (res) => {
+                btn.prop("disabled", false);
+                btn.text(textBefore);
+                if (!res.success) {
+                    showAlert("danger", res.msg);
+                } else {
+                    showAlert("success", "Account successfully created, check your emails.");
+                    $("input").val("");
+                }
+            });
+        }
+    });
+});

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 1
js/jquery.min.js


+ 9 - 135
js/script.js

@@ -3,32 +3,20 @@ let Core = function () {
   this.__construct = function () {
     this.url = document.location.href;
     this.parseParameters();
-    this.langEntries = {};
   };
 
-  this.apiCall = function (func, aParams, callback, onerror) {
-    aParams = typeof aParams !== 'undefined' ? aParams : {};
+  this.apiCall = function (func, params, callback) {
+    params = typeof params !== 'undefined' ? params : {};
     callback = typeof callback !== 'undefined' ? callback : function (data) {};
 
-    onerror = typeof onerror !== 'undefined' ? onerror : function (msg) {
-      bootbox.alert("An error occurred: " + msg);
-    };
-
-    const path = '/api' + (func.startsWith('/') ? '' : '/') + func;
-    $.post(path, aParams, function (data) {
+    const path = '/api/' + (func.startsWith('/') ? '' : '/') + func;
+    $.post(path, params, function (data) {
       console.log(func + "(): success=" + data.success + " msg=" + data.msg);
-      if (data.hasOwnProperty('logoutIn') && $("#logoutTimer").length > 0) {
-        $("#logoutTimer").attr("data-time", data.logoutIn);
-      }
-
-      if (!data.success) {
-        onerror.call(this, data.msg);
-      } else {
-        callback.call(this, data);
-      }
+      callback.call(this, data);
     }, "json").fail(function (jqXHR, textStatus, errorThrown) {
-      console.log("API-Function Error: " + func + " Status: " + textStatus + " error thrown: " + errorThrown);
-      onerror.call(this, "An error occurred. API-Function: " + func + " Status: " + textStatus + " - " + errorThrown);
+      let msg = func + " Status: " + textStatus + " error thrown: " + errorThrown;
+      console.log("API-Function Error: " + msg);
+      callback.call(this, {success: false, msg: "An error occurred. API-Function: " + msg });
     });
   };
 
@@ -48,18 +36,6 @@ let Core = function () {
     return "";
   };
 
-  this.addLangEntry = function (key, val) {
-    this.langEntries[key] = val;
-  };
-
-  this.getLangEntry = function (key) {
-    if (typeof this.langEntries[key] !== 'undefined' && this.langEntries.hasOwnProperty(key)) {
-      return this.langEntries[key];
-    }
-
-    return key;
-  };
-
   this.getUrl = function () {
     return this.url;
   };
@@ -155,10 +131,6 @@ let Core = function () {
       this.url = this.url.substring(0, this.url.indexOf('?'));
   };
 
-  this.logout = function () {
-    this.apiCall('user/logout');
-  };
-
   this.getJsonDateTime = function (date) {
     return date.getFullYear() + "-" +
         ((date.getMonth() + 1 < 10) ? "0" : "") + (date.getMonth() + 1) + "-" +
@@ -176,105 +148,7 @@ let Core = function () {
     return this.getJsonDateTime(date).split(' ')[1];
   };
 
-  this.showInputDialog = function (title, aInputs, callback, element, onCreated) {
-    title = typeof title !== "undefined" ? title : "";
-    aInputs = typeof aInputs !== "undefined" ? aInputs : {};
-    callback = typeof callback !== "undefined" ? callback : function (aResult, element) {
-    };
-    onCreated = typeof onCreated !== "undefined" ? onCreated : function () {
-    };
-
-    var html = '<div class="modal-header"><h4 class="modal-title">' + title + '</h4></div>' +
-        '<form class="bootbox-form">';
-
-    for (var i in aInputs) {
-      var input = aInputs[i];
-
-      if (input.type !== "hidden" && input.type !== "checkbox")
-        html += '<label for="' + input.name + '">' + input.name + ':</label>';
-
-      if (input.type === "select") {
-        html += '<select id="' + input.id + '" class="bootbox-input bootbox-input-select form-control">';
-
-        var aValues = (input.hasOwnProperty("aValues") && typeof input.aValues !== "undefined") ? input.aValues : {};
-        for (var value in aValues) {
-          var name = aValues[value];
-          var selected = (input.value === value) ? " selected" : "";
-          html += '<option value="' + value + '"' + selected + '>' + name + '</option>';
-        }
-
-        html += '</select>';
-        input.type = "select";
-      } else if (input.type === "checkbox") {
-        html += '<div class="checkbox">' +
-            '<label><table><tr>' +
-            '<td style="vertical-align:top;padding-top:3px;">' +
-            '<input class="bootbox-input bootbox-input-checkbox" id="' + input.id + '" value="1" type="checkbox"' + (input.value ? " checked" : "") + '>' +
-            '</td>' +
-            '<td style="padding-left: 5px;">' + input.text + '</td>' +
-            '</tr></table></label>' +
-            '</div>';
-      } else if (input.type === "date") {
-        html += '<input class="bootbox-input form-control customDatePicker" autocomplete="off" ' +
-            'type="text" ' +
-            'name="' + input.name + '" ' +
-            'id="' + input.id + '" ' +
-            'value="' + (input.value ? input.value : "") + '"' + (input.readonly ? " readonly" : "") +
-            (input.maxlength ? ' maxlength="' + input.maxlength + '"' : '') + '>';
-      } else if (input.type === "time") {
-        html += '<div class="input-group">' +
-            '<input class="bootbox-input" autocomplete="off" value="0" pattern="[0-9][0-9]" type="number" name="' + input.name + '" id="' + input.id + 'Hour" style="width:60px;text-align: center">' +
-            '<span>:</span>' +
-            '<input class="bootbox-input" autocomplete="off" type="number" name="' + input.name + '" id="' + input.id + 'Minute" value="00" style="width:60px;text-align: center">' +
-            '</div>';
-      } else {
-        html += '<input class="bootbox-input form-control" autocomplete="off" ' +
-            'type="' + input.type + '" ' +
-            'name="' + input.name + '" ' +
-            'id="' + input.id + '" ' +
-            'value="' + (input.value ? input.value : "") + '"' + (input.readonly ? " readonly" : "") +
-            (input.maxlength ? ' maxlength="' + input.maxlength + '"' : '') + '>';
-      }
-    }
-
-    html += '</form>';
-    var dialog = bootbox.confirm(html, function (result) {
-      if (result) {
-        var aResult = [];
-        for (var i in aInputs) {
-          var input = aInputs[i];
-          var value = $("#" + input.id).val();
-
-          if (input.type === "select")
-            value = $("#" + input.id).find(":selected").val();
-          else if (input.type === "checkbox")
-            value = $("#" + input.id).prop("checked");
-
-          aResult[input.id] = value;
-        }
-        callback.call(this, aResult, element);
-      }
-    });
-
-    dialog.init(function () {
-      $(".modal-body").on("keypress", "input", function (e) {
-        if (e.keyCode === 13) {
-          e.preventDefault();
-          $(".modal-footer .btn-primary").click();
-        }
-      });
-      onCreated.call(this);
-    });
-  };
-
   this.__construct();
 };
 
-let jsCore = new Core();
-$(document).ready(function() {
-
-});
-
-function createLoadingIcon() {
-  return '<i class="fas fa-spin fa-spinner"></i>';
-}
+let jsCore = new Core();

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно