diff --git a/resources/migrations/002-friend-requests.down.sql b/resources/migrations/002-friend-requests.down.sql new file mode 100644 index 0000000..645f36a --- /dev/null +++ b/resources/migrations/002-friend-requests.down.sql @@ -0,0 +1 @@ +DROP TABLE friend_requests; diff --git a/resources/migrations/002-friend-requests.up.sql b/resources/migrations/002-friend-requests.up.sql new file mode 100644 index 0000000..ca5edb4 --- /dev/null +++ b/resources/migrations/002-friend-requests.up.sql @@ -0,0 +1,9 @@ +CREATE TABLE friend_requests ( + id SERIAL, + sender_username text, + recipient_username text, + request_state text, + msg text, + creation_timestamp timestamptz, + PRIMARY KEY (id) +); diff --git a/src/chaat/db/friend_request.clj b/src/chaat/db/friend_request.clj new file mode 100644 index 0000000..301e41d --- /dev/null +++ b/src/chaat/db/friend_request.clj @@ -0,0 +1,60 @@ +(ns chaat.db.friend-request + (:require + [next.jdbc :as jdbc] + [next.jdbc.sql :as sql] + [chaat.handler.errors :refer [error-table]] + [chaat.db.user :as user] + [java-time.api :as jt])) + +;; Will be more logical to have the user-exists? and exists? check in the model layer. +;; Same for the friend request exists? check +(defn exists? + "Check if friend request id exists in friend_requests table" + [connection id] + (not (empty? (sql/find-by-keys connection :friend_requests {:id id})))) + +(defn insert + "Insert a friend request into the db" + [db {:keys [sender_username recipient_username] :as content}] + (jdbc/with-transaction [tx (db)] + (if (and (user/user-exists? tx sender_username) + (user/user-exists? tx recipient_username)) + (let [query-result (sql/insert! tx :friend_requests content)] + {:result query-result :error nil}) + {:result nil :error (:username-not-exists error-table)}))) + +(defn accept + [db id] + (jdbc/with-transaction [tx (db)] + (if (exists? tx id) + (let [query-result (sql/update! (db) :friend_requests {:request_state "accepted"} {:id id}) + update-count (:next.jdbc/update-count query-result)] + (if (= 1 update-count) + {:result id :error nil} + {:result nil :error (:db-state-error error-table)})) + {:result nil :error (:friend-request-not-exists error-table)}))) + +(defn reject + [db id] + (jdbc/with-transaction [tx (db)] + (if (exists? tx id) + (let [query-result (sql/update! (db) :friend_requests {:request_state "rejected"} {:id id}) + update-count (:next.jdbc/update-count query-result)] + (if (= 1 update-count) + {:result id :error nil} + {:result nil :error (:db-state-error error-table)})) + {:result nil :error (:friend-request-not-exists error-table)}))) + +(comment + (def db (:db chaat.app/chaat-system)) + (chaat.model.user/create db "shahn" "12345678") + (chaat.model.user/create db "neena" "12345678") + (def sample {:sender_username "shahn" + :recipient_username "neena" + :request_state "pending" + :msg "hola" + :creation_timestamp (jt/instant)}) + (insert db sample) + (sql/update! (db) :friend_requests {:request_state "accepted"} {:id 0}) + (accept db 1) + (reject db 1)) diff --git a/src/chaat/handler/errors.clj b/src/chaat/handler/errors.clj index e2fc768..bfb0a39 100644 --- a/src/chaat/handler/errors.clj +++ b/src/chaat/handler/errors.clj @@ -20,4 +20,8 @@ :health-check-error {:msg "Health check error" :status-code 500} :unauthorized-action {:msg "Unauthorized action" - :status-code 401}}) + :status-code 401} + :friend-request-not-exists {:msg "Friend request does not exist" + :status-code 404} + :db-state-error {:msg "Internal error" + :status-code 500}}) diff --git a/src/chaat/handler/handler.clj b/src/chaat/handler/handler.clj index 4c47413..4e30481 100644 --- a/src/chaat/handler/handler.clj +++ b/src/chaat/handler/handler.clj @@ -1,6 +1,7 @@ (ns chaat.handler.handler (:require [ring.util.response :as res] [chaat.model.user :as model.user] + [chaat.model.friend-request :as friend-request] [java-time.api :as jt] [chaat.handler.validation :as handler.validation] [chaat.db.utils :as db.utils] @@ -61,6 +62,29 @@ (model.user/delete db username))] (send-response result))) +;; need handler layer validation +(defn create-friend-request + [db {:keys [params] :as request}] + (let [username (:username params) + content (select-keys params [:username :recipient :message]) + result (until-err-> (is-auth-user request username) + (friend-request/create db content))] + (send-response result))) + +;; need authentication +(defn accept-friend-request + [db {:keys [route-params]}] + (let [id (Integer/parseInt (:id route-params)) + result (friend-request/accept db id)] + (send-response result))) + +;; need authentication +(defn reject-friend-request + [db {:keys [route-params]}] + (let [id (Integer/parseInt (:id route-params)) + result (friend-request/reject db id)] + (send-response result))) + (defn test-page "Display the request made to this endpoint for debugging purposes" [request] @@ -73,5 +97,8 @@ (comment (def db (:db chaat.app/chaat-system)) - (is-auth-user {} "shahn") - (delete-user)) + (def params {:username "shahn" + :recipient "neena" + :message "hola"}) + (def request {:params params}) + (create-friend-request db request)) diff --git a/src/chaat/migrations.clj b/src/chaat/migrations.clj index a1a4100..6ed4518 100644 --- a/src/chaat/migrations.clj +++ b/src/chaat/migrations.clj @@ -18,4 +18,6 @@ (comment {:connection-uri - "jdbc:postgresql://127.0.0.1:8001/chaat_db?user=chaat_dev&password=password"}) + "jdbc:postgresql://127.0.0.1:8001/chaat_db?user=chaat_dev&password=password"} + (rollback (config/get-pg-dbspec)) + (run-migrations (config/get-pg-dbspec))) diff --git a/src/chaat/model/friend_request.clj b/src/chaat/model/friend_request.clj new file mode 100644 index 0000000..7f36fab --- /dev/null +++ b/src/chaat/model/friend_request.clj @@ -0,0 +1,37 @@ +(ns chaat.model.friend-request + (:require + [chaat.db.friend-request :as db.friend-request] + [java-time.api :as jt])) + + +(defn gen-friend-request + [{:keys [username recipient message]}] + {:sender_username username + :recipient_username recipient + :request_state "pending" + :msg message + :creation_timestamp (jt/instant)}) + +(defn create + [db content] + (let [;; put model layer validation + friend-request (gen-friend-request content) + result (db.friend-request/insert db friend-request)] + result)) + +(defn accept + [db id] + (let [;; put model layer validation + result (db.friend-request/accept db id)] + result)) + +(defn reject + [db id] + (let [;; put model layer validation + result (db.friend-request/reject db id)] + result)) + +(comment + (def db (:db chaat.app/chaat-system)) + (def content {:username "shahn" :recipient "neena" :message "hello"}) + (create db content)) \ No newline at end of file diff --git a/src/chaat/model/user.clj b/src/chaat/model/user.clj index f534bf1..4407e52 100644 --- a/src/chaat/model/user.clj +++ b/src/chaat/model/user.clj @@ -93,6 +93,7 @@ (comment (def db (:db chaat.app/chaat-system)) + (create db "shahn" "12345678") + (create db "neena" "12345678") (authenticate (:result (db.user/get-user-details db "john")) "12345678") - (delete db "john") (login db "john" "12345678")) diff --git a/src/chaat/routes.clj b/src/chaat/routes.clj index 92b53bf..05691eb 100644 --- a/src/chaat/routes.clj +++ b/src/chaat/routes.clj @@ -13,5 +13,8 @@ ["users" {:post #(handler/signup db %) :delete (wrap-authentication #(handler/delete-user db %) backend)}] ["login" {:post #(handler/login db %)}] + ["friend-requests/" {:post {"" (wrap-authentication #(handler/create-friend-request db %) backend) + [:id "/accept"] (wrap-authentication #(handler/accept-friend-request db %) backend) + [:id "/reject"] (wrap-authentication #(handler/reject-friend-request db %) backend)}}] ["test-page" {:get handler/test-page}] [true handler/not-found]]])