diff --git a/src/uxbox/data/auth.cljs b/src/uxbox/data/auth.cljs index 4353c86330..809abd6fe2 100644 --- a/src/uxbox/data/auth.cljs +++ b/src/uxbox/data/auth.cljs @@ -10,7 +10,7 @@ [promesa.core :as p] [uxbox.repo :as rp] [uxbox.rstore :as rs] - [uxbox.router :as r] + [uxbox.router :as rt] [uxbox.state :as st] [uxbox.schema :as us] [uxbox.locales :refer (tr)] @@ -30,7 +30,7 @@ rs/WatchEvent (-apply-watch [this state s] (rx/of (udu/fetch-profile) - (r/navigate :dashboard/projects))) + (rt/navigate :dashboard/projects))) rs/EffectEvent (-apply-effect [this state] @@ -76,7 +76,7 @@ rs/WatchEvent (-apply-watch [_ state s] - (rx/of (r/navigate :auth/login)))) + (rx/of (rt/navigate :auth/login)))) (defn logout [] @@ -142,3 +142,42 @@ (defn recovery-request [data] (RecoveryRequest. data)) + +;; --- Check Recovery Token + +(defrecord ValidateRecoveryToken [token] + rs/WatchEvent + (-apply-watch [_ state stream] + (letfn [(on-error [{payload :payload}] + (rx/of + (rt/navigate :auth/login) + (udm/show-error (tr "errors.auth.invalid-recovery-token"))))] + (->> (rp/req :auth/validate-recovery-token token) + (rx/ignore) + (rx/catch rp/client-error? on-error))))) + + +(defn validate-recovery-token + [data] + (ValidateRecoveryToken. data)) + +;; --- Recovery (Password) + +(defrecord Recovery [token password] + rs/WatchEvent + (-apply-watch [_ state stream] + (letfn [(on-error [{payload :payload}] + (udm/error (tr "errors.auth.invalid-recovery-token"))) + (on-success [{payload :payload}] + (rx/of + (rt/navigate :auth/login) + (udm/show-info (tr "auth.message.password-recovered"))))] + (->> (rp/req :auth/recovery {:token token :password password}) + (rx/mapcat on-success) + (rx/catch rp/client-error? on-error))))) + + +(defn recovery + [{:keys [token password]}] + (Recovery. token password)) + diff --git a/src/uxbox/locales/en.cljs b/src/uxbox/locales/en.cljs index a3ec3d9617..5f0d7318bf 100644 --- a/src/uxbox/locales/en.cljs +++ b/src/uxbox/locales/en.cljs @@ -45,6 +45,7 @@ "ds.help.line" "Line (Ctrl + L)" "auth.message.recovery-token-sent" "Password recovery link sent to your inbox." + "auth.message.password-recovered" "Password successfully recovered." "settings.profile" "PROFILE" "settings.password" "PASSWORD" @@ -68,5 +69,6 @@ "errors.form.password-not-match" "Password does not match" "errors.generic" "Something work has happened." "errors.auth.unauthorized" "Username or passwords seems to be wrong." + "errors.auth.invalid-recovery-token" "The recovery token is invalid." "errors.profile.update-password" "Error updating password, probably your old password is wrong." }) diff --git a/src/uxbox/repo/auth.cljs b/src/uxbox/repo/auth.cljs index ca0848de0f..a830c6d72d 100644 --- a/src/uxbox/repo/auth.cljs +++ b/src/uxbox/repo/auth.cljs @@ -44,3 +44,16 @@ :method :post :body data}] (send! params))) + +(defmethod request :auth/validate-recovery-token + [_ token] + (let [params {:url (str url "/auth/recovery/" token) + :method :get}] + (send! params))) + +(defmethod request :auth/recovery + [_ data] + (let [params {:url (str url "/auth/recovery") + :method :put + :body data}] + (send! params))) diff --git a/src/uxbox/router.cljs b/src/uxbox/router.cljs index 5d993b25bb..2a687b1672 100644 --- a/src/uxbox/router.cljs +++ b/src/uxbox/router.cljs @@ -39,7 +39,6 @@ (defrecord Navigate [id params] rs/EffectEvent (-apply-effect [_ state] - ;; (println "navigate" id params) (let [loc (merge {:handler id} (when params {:route-params params}))] @@ -61,7 +60,8 @@ (def routes ["/" [["auth/login" :auth/login] ["auth/register" :auth/register] - ["auth/recovery-request" :auth/recovery-request] + ["auth/recovery/request" :auth/recovery-request] + [["auth/recovery/token/" :token] :auth/recovery] ["settings/" [["profile" :settings/profile] ["password" :settings/password] diff --git a/src/uxbox/ui.cljs b/src/uxbox/ui.cljs index 7a8b750bdd..fd3ecbf61d 100644 --- a/src/uxbox/ui.cljs +++ b/src/uxbox/ui.cljs @@ -83,7 +83,7 @@ :auth/login (auth/login-page) :auth/register (auth/register-page) :auth/recovery-request (auth/recovery-request-page) - ;; :auth/recovery (auth/recovery-page) + :auth/recovery (auth/recovery-page (:token params)) :dashboard/projects (dashboard/projects-page) :dashboard/elements (dashboard/elements-page) :dashboard/icons (dashboard/icons-page) diff --git a/src/uxbox/ui/auth.cljs b/src/uxbox/ui/auth.cljs index a577b38fe0..8e73fef80b 100644 --- a/src/uxbox/ui/auth.cljs +++ b/src/uxbox/ui/auth.cljs @@ -7,8 +7,10 @@ (ns uxbox.ui.auth (:require [uxbox.ui.auth.login :as login] [uxbox.ui.auth.register :as register] + [uxbox.ui.auth.recovery-request :as recovery-request] [uxbox.ui.auth.recovery :as recovery])) (def login-page login/login-page) (def register-page register/register-page) -(def recovery-request-page recovery/recovery-request-page) +(def recovery-page recovery/recovery-page) +(def recovery-request-page recovery-request/recovery-request-page) diff --git a/src/uxbox/ui/auth/recovery.cljs b/src/uxbox/ui/auth/recovery.cljs index a8cb004a5d..1df936dc57 100644 --- a/src/uxbox/ui/auth/recovery.cljs +++ b/src/uxbox/ui/auth/recovery.cljs @@ -25,43 +25,44 @@ ;; --- Constants -(def recovery-request-form-data - (-> (l/in [:forms :recovery-request]) +(def form-data + (-> (l/in [:forms :recovery]) (l/focus-atom st/state))) -(def recovery-request-form-errors - (-> (l/in [:errors :recovery-request]) +(def form-errors + (-> (l/in [:errors :recovery]) (l/focus-atom st/state))) (def set-value! - (partial udf/assign-field-value :recovery-request)) + (partial udf/assign-field-value :recovery)) ;; --- Recovery Request Form -(def recovery-request-schema - {:username [us/required us/string]}) +(def schema + {:password [us/required us/string]}) -(defn- recovery-request-form-render - [own] - (let [form (rum/react recovery-request-form-data) - errors (rum/react recovery-request-form-errors) - valid? (us/valid? form recovery-request-schema)] +(defn- form-render + [own token] + (let [form (rum/react form-data) + errors (rum/react form-errors) + valid? (us/valid? form schema)] (letfn [(on-change [field event] (let [value (dom/event->value event)] (rs/emit! (set-value! field value)))) (on-submit [event] (dom/prevent-default event) - (rs/emit! (uda/recovery-request form)))] + (rs/emit! (uda/recovery (assoc form :token token))))] (html [:form {:on-submit on-submit} [:div.login-content + [:input.input-text - {:name "username" - :value (:username form "") - :on-change (partial on-change :username) - :placeholder "username or email address" - :type "text"}] - (forms/input-error errors :username) + {:name "password" + :value (:password form "") + :on-change (partial on-change :password) + :placeholder "Password" + :type "password"}] + (forms/input-error errors :password) [:input.btn-primary {:name "login" @@ -72,25 +73,32 @@ [:div.login-links [:a {:on-click #(rt/go :auth/login)} "Go back!"]]]])))) -(def recovery-request-form +(def form (mx/component - {:render recovery-request-form-render - :name "recovery-request-form" + {:render form-render + :name "form" :mixins [mx/static rum/reactive]})) ;; --- Recovery Request Page -(defn- recovery-request-page-render +(defn- recovery-page-will-mount [own] + (let [[token] (:rum/props own)] + (rs/emit! (uda/validate-recovery-token token)) + own)) + +(defn- recovery-page-render + [own token] (html [:div.login [:div.login-body (uum/messages) [:a i/logo] - (recovery-request-form)]])) + (form token)]])) -(def recovery-request-page +(def recovery-page (mx/component - {:render recovery-request-page-render - :name "recovery-request-page" + {:render recovery-page-render + :will-mount recovery-page-will-mount + :name "recovery-page" :mixins [mx/static]})) diff --git a/src/uxbox/ui/auth/recovery_request.cljs b/src/uxbox/ui/auth/recovery_request.cljs new file mode 100644 index 0000000000..cc5787c13b --- /dev/null +++ b/src/uxbox/ui/auth/recovery_request.cljs @@ -0,0 +1,96 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) 2016 Andrey Antukh + +(ns uxbox.ui.auth.recovery-request + (:require [sablono.core :as html :refer-macros [html]] + [lentes.core :as l] + [cuerdas.core :as str] + [rum.core :as rum] + [uxbox.router :as rt] + [uxbox.state :as st] + [uxbox.rstore :as rs] + [uxbox.schema :as us] + [uxbox.data.auth :as uda] + [uxbox.data.messages :as udm] + [uxbox.data.forms :as udf] + [uxbox.ui.forms :as forms] + [uxbox.ui.icons :as i] + [uxbox.ui.messages :as uum] + [uxbox.ui.navigation :as nav] + [uxbox.ui.mixins :as mx] + [uxbox.util.dom :as dom])) + +;; --- Recovery Request Constants + +(def form-data + (-> (l/in [:forms :recovery-request]) + (l/focus-atom st/state))) + +(def form-errors + (-> (l/in [:errors :recovery-request]) + (l/focus-atom st/state))) + +(def set-value! + (partial udf/assign-field-value :recovery-request)) + +;; --- Recovery Request Form + +(def schema + {:username [us/required us/string]}) + +(defn- form-render + [own] + (let [form (rum/react form-data) + errors (rum/react form-errors) + valid? (us/valid? form schema)] + (letfn [(on-change [field event] + (let [value (dom/event->value event)] + (rs/emit! (set-value! field value)))) + (on-submit [event] + (dom/prevent-default event) + (rs/emit! (uda/recovery-request form)))] + (html + [:form {:on-submit on-submit} + [:div.login-content + [:input.input-text + {:name "username" + :value (:username form "") + :on-change (partial on-change :username) + :placeholder "username or email address" + :type "text"}] + (forms/input-error errors :username) + + [:input.btn-primary + {:name "login" + :class (when-not valid? "btn-disabled") + :disabled (not valid?) + :value "Recover password" + :type "submit"}] + [:div.login-links + [:a {:on-click #(rt/go :auth/login)} "Go back!"]]]])))) + +(def form + (mx/component + {:render form-render + :name "form" + :mixins [mx/static rum/reactive]})) + +;; --- Recovery Request Page + +(defn- recovery-request-page-render + [own] + (html + [:div.login + [:div.login-body + (uum/messages) + [:a i/logo] + (form)]])) + +(def recovery-request-page + (mx/component + {:render recovery-request-page-render + :name "recovery-request-page" + :mixins [mx/static]}))