Skip to content

Commit

Permalink
Refactor invitation prst layer to use with plastic strategy
Browse files Browse the repository at this point in the history
[Re #1611]

* Also refactor it to follow new conventions on the persistence layer
side, handling errors at that level.
  • Loading branch information
lucassousaf committed Oct 10, 2023
1 parent a187b0b commit ed3e40c
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 32 deletions.
112 changes: 108 additions & 4 deletions backend/src/gpml/db/invitation.clj
Original file line number Diff line number Diff line change
@@ -1,9 +1,113 @@
(ns gpml.db.invitation
{:ns-tracker/resource-deps ["invitation.sql"]}
(:require [hugsql.core :as hugsql]))
(:require [gpml.db.jdbc-util :as jdbc-util]
[gpml.util :as util]
[gpml.util.postgresql :as util.pgsql]
[gpml.util.sql :as util.sql]
[hugsql.core :as hugsql]))

(declare create-invitations
get-invitations
accept-invitation)
(declare create-invitations*
get-invitations*
accept-invitation*
delete-invitation*)

(hugsql/def-db-fns "gpml/db/invitation.sql" {:quoting :ansi})

(defn- p-invitation->invitation
[p-invitation]
(util/update-if-not-nil p-invitation :type keyword))

(defn- invitation->p-invitation
[invitation]
(util/update-if-not-nil invitation :type util.pgsql/->PGEnum "invitation_type"))

(defn get-invitations
[conn opts]
(try
{:success? true
:invitations (->> (get-invitations* conn opts)
(jdbc-util/db-result-snake-kw->db-result-kebab-kw)
(map p-invitation->invitation))}
(catch Throwable t
{:success? false
:reason :exception
:error-details {:msg (ex-message t)}})))

(defn get-invitation
[conn opts]
(try
(let [invitations (get-invitations conn opts)]
(if (and (seq invitations)
(= (count invitations) 1))
{:success? true
:invitation (first invitations)}
{:success? false
:reason :not-found}))
(catch Throwable t
{:success? false
:reason :exception
:error-details {:msg (ex-message t)}})))

(defn create-invitations
[conn invitations]
(try
(let [p-invitations (jdbc-util/db-params-kebab-kw->db-params-snake-kw
(map invitation->p-invitation invitations))
cols (util.sql/get-insert-columns-from-entity-col p-invitations)
values (util.sql/entity-col->persistence-entity-col p-invitations)
created-invitations (create-invitations* conn {:cols cols
:values values})]
(if (= (count created-invitations) (count invitations))
{:success? true
:invitations (map p-invitation->invitation created-invitations)}
{:success? false
:reason :unexpected-number-of-affected-rows
:error-details {:expected-affected-rows (count invitations)
:actual-affected-rows (count created-invitations)}}))
(catch Throwable t
{:success? false
:reason :exception
:error-details {:msg (ex-message t)}})))

(defn create-invitation
[conn invitation]
(try
(let [result (create-invitations conn [invitation])]
(if (:success? result)
{:success? true
:invitation (first (:invitations result))}
result))
(catch Throwable t
{:success? false
:reason :exception
:error-details {:msg (ex-message t)}})))

(defn accept-invitation
[conn invitation-id]
(try
(let [affected (accept-invitation* conn {:id invitation-id})]
(if (= affected 1)
{:success? true}
{:success? false
:reason :unexpected-number-of-affected-rows
:error-details {:expected-affected-rows 1
:actual-affected-rows affected}}))
(catch Throwable t
{:success? false
:reason :exception
:error-details {:msg (ex-message t)}})))

(defn delete-invitation
[conn invitation-id]
(try
(let [affected (delete-invitation* conn {:id invitation-id})]
(if (= affected 1)
{:success? true}
{:success? false
:reason :unexpected-number-of-affected-rows
:error-details {:expected-affected-rows 1
:actual-affected-rows affected}}))
(catch Throwable t
{:success? false
:reason :exception
:error-details {:msg (ex-message t)}})))
14 changes: 9 additions & 5 deletions backend/src/gpml/db/invitation.sql
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
-- :name create-invitations :returning-execute :many
INSERT INTO invitation(id, stakeholder_id, email)
-- :name create-invitations* :returning-execute :many
INSERT INTO invitation(:i*:cols)
VALUES :t*:values RETURNING *;

-- :name get-invitations :query :many
-- :name get-invitations* :query :many
SELECT * FROM invitation
WHERE 1=1
--~ (when (seq (get-in params [:filters :emails])) " AND email IN (:v*:filters.emails)")
Expand All @@ -11,7 +11,11 @@ WHERE 1=1
--~ (when (true? (get-in params [:filters :pending?])) " AND accepted_at IS NULL")
--~ (when (false? (get-in params [:filters :pending?])) " AND accepted_at IS NOT NULL")

-- :name accept-invitation :execute :affected
-- :name accept-invitation* :execute :affected
UPDATE invitation
SET accepted_at = :accepted-at
SET accepted_at = now()
WHERE id = :id

-- :name delete-invitation* :execute :affected
DELETE FROM invitation
WHERE id = :id;
34 changes: 17 additions & 17 deletions backend/src/gpml/handler/invitation.clj
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
(if-not (h.r.permission/super-admin? config (:id user))
(r/forbidden {:message "Unauthorized"})
(let [opts (api-opts->opts query)
invitations (db.invitation/get-invitations (:spec db) opts)
invitations (db.invitation/get-invitations* (:spec db) opts)
stakeholders (->> (db.stakeholder/get-stakeholders (:spec db)
{:filters {:ids (map :stakeholder_id invitations)}})
(group-by :id))]
Expand Down Expand Up @@ -94,24 +94,24 @@
{{:keys [query path]} :parameters user :user}]
(try
(let [opts (api-opts->opts (merge query path))
invitation (db.invitation/get-invitations (:spec db)
{:filters {:ids [(:id opts)]}})]
(if-not (= (:stakeholder_id invitation) (:id user))
(r/forbidden {:message "Unauthorized"})
(let [accepted-at (-> (time/instant) (time-pre-j8/sql-timestamp "UTC"))
affected-rows (db.invitation/accept-invitation (:spec db) (merge opts
{:accepted-at accepted-at}))]
(if (= affected-rows 1)
(r/ok {:success? true})
(r/server-error {:success? false
:reason :could-not-update-invitation})))))
{:keys [success? invitation reason] :as get-invitation-result}
(db.invitation/get-invitation (:spec db)
{:filters {:ids [(:id opts)]}})]
(if-not success?
(if (= reason :not-found)
(r/not-found {})
(r/server-error (dissoc get-invitation-result :success?)))
(if-not (= (:stakeholder-id invitation) (:id user))
(r/forbidden {:message "Unauthorized"})
(let [result (db.invitation/accept-invitation (:spec db) (:id invitation))]
(if (:success? result)
(r/ok {})
(r/server-error (dissoc result :success?)))))))
(catch Exception e
(log logger :error ::accept-invitation {:exception-message (.getMessage e)})
(log logger :error ::failed-to-accept-invitation {:exception-message (.getMessage e)})
(if (instance? SQLException e)
(r/server-error {:success? false
:reason (pg-util/get-sql-state e)})
(r/server-error {:success? false
:reason :could-not-update-invitation
(r/server-error {:reason (pg-util/get-sql-state e)})
(r/server-error {:reason :could-not-update-invitation
:error-details {:message (.getMessage e)}})))))

(defmethod ig/init-key :gpml.handler.invitation/get [_ config]
Expand Down
23 changes: 17 additions & 6 deletions backend/src/gpml/handler/stakeholder/expert.clj
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
(ns gpml.handler.stakeholder.expert
(:require [clojure.java.jdbc :as jdbc]
(:require [camel-snake-kebab.core :refer [->snake_case]]
[camel-snake-kebab.extras :as cske]
[clojure.java.jdbc :as jdbc]
[clojure.string :as str]
[duct.logger :refer [log]]
[gpml.db.country-group :as db.country-group]
Expand All @@ -12,6 +14,7 @@
[gpml.util :as util]
[gpml.util.email :as email]
[gpml.util.postgresql :as pg-util]
[gpml.util.sql :as util.sql]
[integrant.core :as ig]
[jsonista.core :as json]
[malli.util :as mu]
Expand Down Expand Up @@ -192,12 +195,20 @@
expert-values (util/apply-select-values experts expert-cols)
expert-stakeholders (db.stakeholder/create-stakeholders conn {:cols (map name expert-cols)
:values expert-values})
invitation-values (map (fn [{:keys [id email]}]
(vector (util/uuid) id email))
expert-stakeholders)
invitations-to-create (map (fn [{:keys [id email]}]
{:id (util/uuid)
:stakeholder-id id
:email email
:type :expert})
expert-stakeholders)
invitation-cols (util.sql/get-insert-columns-from-entity-col invitations-to-create)
invitations-values (util.sql/entity-col->persistence-entity-col invitations-to-create)
experts-by-email (group-by :email experts)
invitations (->> (db.invitation/create-invitations conn {:values invitation-values})
(map #(merge % (get-in experts-by-email [(:email %) 0]))))]
invitations (->> (db.invitation/create-invitations conn {:cols invitation-cols
:values invitations-values})
:invitations
(map #(merge % (get-in experts-by-email [(:email %) 0])))
(cske/transform-keys ->snake_case))]
(doseq [{:keys [email expertise]} body
:let [stakeholder-id (get-in (group-by :email expert-stakeholders) [email 0 :id])]]
(handler.stakeholder.tag/save-stakeholder-tags
Expand Down

0 comments on commit ed3e40c

Please sign in to comment.