mirror of
https://github.com/penpot/penpot.git
synced 2025-05-20 16:56:11 +02:00
✨ Add support for multiple emails for profile.
This commit is contained in:
parent
282b170147
commit
3e8b570c6b
3 changed files with 79 additions and 33 deletions
|
@ -15,6 +15,37 @@ CREATE TABLE users (
|
||||||
is_demo boolean NOT NULL DEFAULT false
|
is_demo boolean NOT NULL DEFAULT false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX users__username__idx
|
||||||
|
ON users (username)
|
||||||
|
WHERE deleted_at IS null;
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX users__email__idx
|
||||||
|
ON users (email)
|
||||||
|
WHERE deleted_at IS null;
|
||||||
|
|
||||||
|
CREATE INDEX users__is_demo
|
||||||
|
ON users (is_demo)
|
||||||
|
WHERE deleted_at IS null
|
||||||
|
AND is_demo IS true;
|
||||||
|
|
||||||
|
--- Table used for register all used emails by the user
|
||||||
|
CREATE TABLE IF NOT EXISTS user_emails (
|
||||||
|
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
||||||
|
verified_at timestamptz NULL DEFAULT NULL,
|
||||||
|
|
||||||
|
email text NOT NULL,
|
||||||
|
|
||||||
|
is_main boolean NOT NULL DEFAULT false,
|
||||||
|
is_verified boolean NOT NULL DEFAULT false
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX user_emails__user_id__idx
|
||||||
|
ON user_emails (user_id);
|
||||||
|
|
||||||
|
--- Table for user key value attributes
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS user_attrs (
|
CREATE TABLE IF NOT EXISTS user_attrs (
|
||||||
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
@ -27,6 +58,8 @@ CREATE TABLE IF NOT EXISTS user_attrs (
|
||||||
PRIMARY KEY (key, user_id)
|
PRIMARY KEY (key, user_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
--- Table for store verification tokens
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS tokens (
|
CREATE TABLE IF NOT EXISTS tokens (
|
||||||
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
token text NOT NULL,
|
token text NOT NULL,
|
||||||
|
@ -37,6 +70,8 @@ CREATE TABLE IF NOT EXISTS tokens (
|
||||||
PRIMARY KEY (token, user_id)
|
PRIMARY KEY (token, user_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
--- Table for store user sessions.
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS sessions (
|
CREATE TABLE IF NOT EXISTS sessions (
|
||||||
id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
|
id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
|
||||||
|
@ -47,6 +82,9 @@ CREATE TABLE IF NOT EXISTS sessions (
|
||||||
user_agent text NULL
|
user_agent text NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE INDEX sessions__user_id__idx
|
||||||
|
ON sessions (user_id);
|
||||||
|
|
||||||
-- Insert a placeholder system user.
|
-- Insert a placeholder system user.
|
||||||
|
|
||||||
INSERT INTO users (id, fullname, username, email, photo, password)
|
INSERT INTO users (id, fullname, username, email, photo, password)
|
||||||
|
@ -57,18 +95,7 @@ VALUES ('00000000-0000-0000-0000-000000000000'::uuid,
|
||||||
'',
|
'',
|
||||||
'!');
|
'!');
|
||||||
|
|
||||||
CREATE UNIQUE INDEX users__username__idx
|
--- Triggers
|
||||||
ON users (username)
|
|
||||||
WHERE deleted_at IS null;
|
|
||||||
|
|
||||||
CREATE UNIQUE INDEX users__email__idx
|
|
||||||
ON users (email)
|
|
||||||
WHERE deleted_at IS null;
|
|
||||||
|
|
||||||
CREATE INDEX users__is_demo
|
|
||||||
ON users(is_demo)
|
|
||||||
WHERE deleted_at IS null
|
|
||||||
AND is_demo IS true;
|
|
||||||
|
|
||||||
CREATE TRIGGER users__modified_at__tgr
|
CREATE TRIGGER users__modified_at__tgr
|
||||||
BEFORE UPDATE ON users
|
BEFORE UPDATE ON users
|
||||||
|
|
|
@ -32,10 +32,14 @@
|
||||||
[uxbox.util.uuid :as uuid]
|
[uxbox.util.uuid :as uuid]
|
||||||
[vertx.core :as vc]))
|
[vertx.core :as vc]))
|
||||||
|
|
||||||
(def sql:create-demo-user
|
(def sql:insert-user
|
||||||
"insert into users (id, fullname, username, email, password, photo, is_demo)
|
"insert into users (id, fullname, username, email, password, photo, is_demo)
|
||||||
values ($1, $2, $3, $4, $5, '', true) returning *")
|
values ($1, $2, $3, $4, $5, '', true) returning *")
|
||||||
|
|
||||||
|
(def sql:insert-email
|
||||||
|
"insert into user_emails (user_id, email, is_main)
|
||||||
|
values ($1, $2, true)")
|
||||||
|
|
||||||
(sm/defmutation ::create-demo-profile
|
(sm/defmutation ::create-demo-profile
|
||||||
[params]
|
[params]
|
||||||
(let [id (uuid/next)
|
(let [id (uuid/next)
|
||||||
|
@ -47,6 +51,7 @@
|
||||||
(sodi.util/bytes->b64s))
|
(sodi.util/bytes->b64s))
|
||||||
password' (sodi.pwhash/derive password)]
|
password' (sodi.pwhash/derive password)]
|
||||||
(db/with-atomic [conn db/pool]
|
(db/with-atomic [conn db/pool]
|
||||||
(db/query-one conn [sql:create-demo-user id fullname username email password'])
|
(db/query-one conn [sql:insert-user id fullname username email password'])
|
||||||
|
(db/query-one conn [sql:insert-email id email])
|
||||||
{:username username
|
{:username username
|
||||||
:password password})))
|
:password password})))
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
|
|
||||||
(s/def ::email ::us/email)
|
(s/def ::email ::us/email)
|
||||||
(s/def ::fullname ::us/string)
|
(s/def ::fullname ::us/string)
|
||||||
(s/def ::metadata any?)
|
(s/def ::lang ::us/string)
|
||||||
(s/def ::old-password ::us/string)
|
(s/def ::old-password ::us/string)
|
||||||
(s/def ::password ::us/string)
|
(s/def ::password ::us/string)
|
||||||
(s/def ::path ::us/string)
|
(s/def ::path ::us/string)
|
||||||
|
@ -82,6 +82,15 @@
|
||||||
(-> (retrieve-user db/pool username)
|
(-> (retrieve-user db/pool username)
|
||||||
(p/then' check-user))))
|
(p/then' check-user))))
|
||||||
|
|
||||||
|
;; --- Mutation: Add additional email
|
||||||
|
;; TODO
|
||||||
|
|
||||||
|
;; --- Mutation: Mark email as main email
|
||||||
|
;; TODO
|
||||||
|
|
||||||
|
;; --- Mutation: Verify email (or maybe query?)
|
||||||
|
;; TODO
|
||||||
|
|
||||||
;; --- Mutation: Update Profile (own)
|
;; --- Mutation: Update Profile (own)
|
||||||
|
|
||||||
(defn- check-username-and-email!
|
(defn- check-username-and-email!
|
||||||
|
@ -109,23 +118,22 @@
|
||||||
(def sql:update-profile
|
(def sql:update-profile
|
||||||
"update users
|
"update users
|
||||||
set username = $2,
|
set username = $2,
|
||||||
email = $3,
|
fullname = $3,
|
||||||
fullname = $4,
|
lang = $4
|
||||||
metadata = $5
|
|
||||||
where id = $1
|
where id = $1
|
||||||
and deleted_at is null
|
and deleted_at is null
|
||||||
returning *")
|
returning *")
|
||||||
|
|
||||||
(defn- update-profile
|
(defn- update-profile
|
||||||
[conn {:keys [id username email fullname metadata] :as params}]
|
[conn {:keys [id username fullname lang] :as params}]
|
||||||
(let [sqlv [sql:update-profile id username
|
(let [sqlv [sql:update-profile
|
||||||
email fullname (blob/encode metadata)]]
|
id username fullname lang]]
|
||||||
(-> (db/query-one conn sqlv)
|
(-> (db/query-one conn sqlv)
|
||||||
(p/then' su/raise-not-found-if-nil)
|
(p/then' su/raise-not-found-if-nil)
|
||||||
(p/then' profile/strip-private-attrs))))
|
(p/then' profile/strip-private-attrs))))
|
||||||
|
|
||||||
(s/def ::update-profile
|
(s/def ::update-profile
|
||||||
(s/keys :req-un [::id ::username ::email ::fullname ::metadata]))
|
(s/keys :req-un [::id ::username ::fullname ::lang]))
|
||||||
|
|
||||||
(sm/defmutation ::update-profile
|
(sm/defmutation ::update-profile
|
||||||
[params]
|
[params]
|
||||||
|
@ -213,10 +221,14 @@
|
||||||
|
|
||||||
;; --- Mutation: Register Profile
|
;; --- Mutation: Register Profile
|
||||||
|
|
||||||
(def sql:create-user
|
(def sql:insert-user
|
||||||
"insert into users (id, fullname, username, email, password, photo)
|
"insert into users (id, fullname, username, email, password, photo)
|
||||||
values ($1, $2, $3, $4, $5, '') returning *")
|
values ($1, $2, $3, $4, $5, '') returning *")
|
||||||
|
|
||||||
|
(def sql:insert-email
|
||||||
|
"insert into user_emails (user_id, email, is_main)
|
||||||
|
values ($1, $2, true)")
|
||||||
|
|
||||||
(defn- check-profile-existence!
|
(defn- check-profile-existence!
|
||||||
[conn {:keys [username email] :as params}]
|
[conn {:keys [username email] :as params}]
|
||||||
(let [sql "select exists
|
(let [sql "select exists
|
||||||
|
@ -237,22 +249,24 @@
|
||||||
[conn {:keys [id username fullname email password] :as params}]
|
[conn {:keys [id username fullname email password] :as params}]
|
||||||
(let [id (or id (uuid/next))
|
(let [id (or id (uuid/next))
|
||||||
password (sodi.pwhash/derive password)
|
password (sodi.pwhash/derive password)
|
||||||
sqlv [sql:create-user
|
sqlv1 [sql:insert-user id
|
||||||
id
|
fullname username
|
||||||
fullname
|
email password]
|
||||||
username
|
sqlv2 [sql:insert-email id email]]
|
||||||
email
|
(p/let [profile (db/query-one conn sqlv1)]
|
||||||
password]]
|
(db/query-one conn sqlv2)
|
||||||
(db/query-one conn sqlv)))
|
profile)))
|
||||||
|
|
||||||
(defn register-profile
|
(defn register-profile
|
||||||
[conn params]
|
[conn params]
|
||||||
(-> (create-profile conn params)
|
(-> (create-profile conn params)
|
||||||
(p/then' profile/strip-private-attrs)
|
(p/then' profile/strip-private-attrs)
|
||||||
(p/then (fn [profile]
|
(p/then (fn [profile]
|
||||||
(-> (emails/send! emails/register {:to (:email params)
|
;; TODO: send a correct link for email verification
|
||||||
:name (:fullname params)})
|
(p/let [data {:to (:email params)
|
||||||
(p/then' (constantly profile)))))))
|
:name (:fullname params)}]
|
||||||
|
(emails/send! emails/register data)
|
||||||
|
profile)))))
|
||||||
|
|
||||||
(s/def ::register-profile
|
(s/def ::register-profile
|
||||||
(s/keys :req-un [::username ::email ::password ::fullname]))
|
(s/keys :req-un [::username ::email ::password ::fullname]))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue