0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-10 08:50:57 -05:00

Add password recovery page.

This commit is contained in:
Andrey Antukh 2016-05-31 20:54:18 +03:00
parent 0fc6efa7b0
commit 87152c6b46
No known key found for this signature in database
GPG key ID: 4DFEBCB8316A8B95
8 changed files with 194 additions and 34 deletions

View file

@ -10,7 +10,7 @@
[promesa.core :as p] [promesa.core :as p]
[uxbox.repo :as rp] [uxbox.repo :as rp]
[uxbox.rstore :as rs] [uxbox.rstore :as rs]
[uxbox.router :as r] [uxbox.router :as rt]
[uxbox.state :as st] [uxbox.state :as st]
[uxbox.schema :as us] [uxbox.schema :as us]
[uxbox.locales :refer (tr)] [uxbox.locales :refer (tr)]
@ -30,7 +30,7 @@
rs/WatchEvent rs/WatchEvent
(-apply-watch [this state s] (-apply-watch [this state s]
(rx/of (udu/fetch-profile) (rx/of (udu/fetch-profile)
(r/navigate :dashboard/projects))) (rt/navigate :dashboard/projects)))
rs/EffectEvent rs/EffectEvent
(-apply-effect [this state] (-apply-effect [this state]
@ -76,7 +76,7 @@
rs/WatchEvent rs/WatchEvent
(-apply-watch [_ state s] (-apply-watch [_ state s]
(rx/of (r/navigate :auth/login)))) (rx/of (rt/navigate :auth/login))))
(defn logout (defn logout
[] []
@ -142,3 +142,42 @@
(defn recovery-request (defn recovery-request
[data] [data]
(RecoveryRequest. 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))

View file

@ -45,6 +45,7 @@
"ds.help.line" "Line (Ctrl + L)" "ds.help.line" "Line (Ctrl + L)"
"auth.message.recovery-token-sent" "Password recovery link sent to your inbox." "auth.message.recovery-token-sent" "Password recovery link sent to your inbox."
"auth.message.password-recovered" "Password successfully recovered."
"settings.profile" "PROFILE" "settings.profile" "PROFILE"
"settings.password" "PASSWORD" "settings.password" "PASSWORD"
@ -68,5 +69,6 @@
"errors.form.password-not-match" "Password does not match" "errors.form.password-not-match" "Password does not match"
"errors.generic" "Something work has happened." "errors.generic" "Something work has happened."
"errors.auth.unauthorized" "Username or passwords seems to be wrong." "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." "errors.profile.update-password" "Error updating password, probably your old password is wrong."
}) })

View file

@ -44,3 +44,16 @@
:method :post :method :post
:body data}] :body data}]
(send! params))) (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)))

View file

@ -39,7 +39,6 @@
(defrecord Navigate [id params] (defrecord Navigate [id params]
rs/EffectEvent rs/EffectEvent
(-apply-effect [_ state] (-apply-effect [_ state]
;; (println "navigate" id params)
(let [loc (merge {:handler id} (let [loc (merge {:handler id}
(when params (when params
{:route-params params}))] {:route-params params}))]
@ -61,7 +60,8 @@
(def routes (def routes
["/" [["auth/login" :auth/login] ["/" [["auth/login" :auth/login]
["auth/register" :auth/register] ["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] ["settings/" [["profile" :settings/profile]
["password" :settings/password] ["password" :settings/password]

View file

@ -83,7 +83,7 @@
:auth/login (auth/login-page) :auth/login (auth/login-page)
:auth/register (auth/register-page) :auth/register (auth/register-page)
:auth/recovery-request (auth/recovery-request-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/projects (dashboard/projects-page)
:dashboard/elements (dashboard/elements-page) :dashboard/elements (dashboard/elements-page)
:dashboard/icons (dashboard/icons-page) :dashboard/icons (dashboard/icons-page)

View file

@ -7,8 +7,10 @@
(ns uxbox.ui.auth (ns uxbox.ui.auth
(:require [uxbox.ui.auth.login :as login] (:require [uxbox.ui.auth.login :as login]
[uxbox.ui.auth.register :as register] [uxbox.ui.auth.register :as register]
[uxbox.ui.auth.recovery-request :as recovery-request]
[uxbox.ui.auth.recovery :as recovery])) [uxbox.ui.auth.recovery :as recovery]))
(def login-page login/login-page) (def login-page login/login-page)
(def register-page register/register-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)

View file

@ -25,43 +25,44 @@
;; --- Constants ;; --- Constants
(def recovery-request-form-data (def form-data
(-> (l/in [:forms :recovery-request]) (-> (l/in [:forms :recovery])
(l/focus-atom st/state))) (l/focus-atom st/state)))
(def recovery-request-form-errors (def form-errors
(-> (l/in [:errors :recovery-request]) (-> (l/in [:errors :recovery])
(l/focus-atom st/state))) (l/focus-atom st/state)))
(def set-value! (def set-value!
(partial udf/assign-field-value :recovery-request)) (partial udf/assign-field-value :recovery))
;; --- Recovery Request Form ;; --- Recovery Request Form
(def recovery-request-schema (def schema
{:username [us/required us/string]}) {:password [us/required us/string]})
(defn- recovery-request-form-render (defn- form-render
[own] [own token]
(let [form (rum/react recovery-request-form-data) (let [form (rum/react form-data)
errors (rum/react recovery-request-form-errors) errors (rum/react form-errors)
valid? (us/valid? form recovery-request-schema)] valid? (us/valid? form schema)]
(letfn [(on-change [field event] (letfn [(on-change [field event]
(let [value (dom/event->value event)] (let [value (dom/event->value event)]
(rs/emit! (set-value! field value)))) (rs/emit! (set-value! field value))))
(on-submit [event] (on-submit [event]
(dom/prevent-default event) (dom/prevent-default event)
(rs/emit! (uda/recovery-request form)))] (rs/emit! (uda/recovery (assoc form :token token))))]
(html (html
[:form {:on-submit on-submit} [:form {:on-submit on-submit}
[:div.login-content [:div.login-content
[:input.input-text [:input.input-text
{:name "username" {:name "password"
:value (:username form "") :value (:password form "")
:on-change (partial on-change :username) :on-change (partial on-change :password)
:placeholder "username or email address" :placeholder "Password"
:type "text"}] :type "password"}]
(forms/input-error errors :username) (forms/input-error errors :password)
[:input.btn-primary [:input.btn-primary
{:name "login" {:name "login"
@ -72,25 +73,32 @@
[:div.login-links [:div.login-links
[:a {:on-click #(rt/go :auth/login)} "Go back!"]]]])))) [:a {:on-click #(rt/go :auth/login)} "Go back!"]]]]))))
(def recovery-request-form (def form
(mx/component (mx/component
{:render recovery-request-form-render {:render form-render
:name "recovery-request-form" :name "form"
:mixins [mx/static rum/reactive]})) :mixins [mx/static rum/reactive]}))
;; --- Recovery Request Page ;; --- Recovery Request Page
(defn- recovery-request-page-render (defn- recovery-page-will-mount
[own] [own]
(let [[token] (:rum/props own)]
(rs/emit! (uda/validate-recovery-token token))
own))
(defn- recovery-page-render
[own token]
(html (html
[:div.login [:div.login
[:div.login-body [:div.login-body
(uum/messages) (uum/messages)
[:a i/logo] [:a i/logo]
(recovery-request-form)]])) (form token)]]))
(def recovery-request-page (def recovery-page
(mx/component (mx/component
{:render recovery-request-page-render {:render recovery-page-render
:name "recovery-request-page" :will-mount recovery-page-will-mount
:name "recovery-page"
:mixins [mx/static]})) :mixins [mx/static]}))

View file

@ -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 <niwi@niwi.nz>
(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]}))