diff --git a/backend/deps.edn b/backend/deps.edn index 97a4b0f24..109a20ba4 100644 --- a/backend/deps.edn +++ b/backend/deps.edn @@ -5,7 +5,6 @@ funcool/promesa {:mvn/version "2.0.0"} funcool/cuerdas {:mvn/version "2.2.0"} funcool/datoteka {:mvn/version "1.0.0"} - funcool/catacumba {:mvn/version "2.1.0"} funcool/struct {:mvn/version "1.4.0"} ring/ring {:mvn/version "1.7.1"} @@ -15,6 +14,7 @@ metosin/reitit-spec {:mvn/version "0.3.7"} metosin/reitit-dev {:mvn/version "0.3.7"} + danlentz/clj-uuid {:mvn/version "0.1.9"} org.jsoup/jsoup {:mvn/version "1.10.2"} hiccup/hiccup {:mvn/version "1.0.5"} org.im4java/im4java {:mvn/version "1.4.0"} diff --git a/backend/src/uxbox/api/debug_emails.clj b/backend/src/uxbox/api/debug_emails.clj new file mode 100644 index 000000000..664f54f55 --- /dev/null +++ b/backend/src/uxbox/api/debug_emails.clj @@ -0,0 +1,67 @@ +;; 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) 2019 Andrey Antukh + +(ns uxbox.api.debug-emails + "A helper namespace for just render emails." + (:require [clojure.edn :as edn] + [hiccup.page :refer (html5)] + [uxbox.emails :as emails] + [uxbox.emails.core :as emails-core])) + +;; (def +available-emails+ +;; {:users/register +;; {:name "Cirilla"} +;; :users/password-recovery +;; {:name "Cirilla" +;; :token "agNFhA6SolcFb4Us2NOTNWh0cfFDquVLAav400xQPjw"}}) + +;; (defn- render-emails-list +;; [] +;; (html5 +;; [:section {:style "font-family: Monoid, monospace; font-size: 14px;"} +;; [:h1 "Available emails"] +;; [:table {:style "width: 500px;"} +;; [:tbody +;; [:tr +;; (for [[type email] @emails-core/emails] +;; [:tr +;; [:td (pr-str type)] +;; [:td +;; [:a {:href (str "/debug/emails/email?id=" +;; (pr-str type) +;; "&type=:text/html")} +;; "(html)"]] +;; [:td +;; [:a {:href (str "/debug/emails/email?id=" +;; (pr-str type) +;; "&type=:text/plain")} +;; "(text)"]]])]]]])) + +;; (defn list-emails +;; [context] +;; (http/ok (render-emails-list) +;; {:content-type "text/html; charset=utf-8"})) + +;; (defn- render-email +;; [type content] +;; (if (= type :text/html) +;; content +;; (html5 +;; [:pre content]))) + +;; (defn show-email +;; [{params :query-params}] +;; (let [id (edn/read-string (:id params)) +;; type (or (edn/read-string (:type params)) :text/html) +;; params (-> (get +available-emails+ id) +;; (assoc :email/name id)) +;; email (emails/render params) +;; content (->> (:body email) +;; (filter #(= (:uxbox.emails.core/type %) type)) +;; (first) +;; (:content))] +;; (-> (render-email type content) +;; (http/ok {:content-type "text/html; charset=utf-8"})))) diff --git a/backend/src/uxbox/api/middleware.clj b/backend/src/uxbox/api/middleware.clj index c24b071a2..e2c443fe9 100644 --- a/backend/src/uxbox/api/middleware.clj +++ b/backend/src/uxbox/api/middleware.clj @@ -6,6 +6,9 @@ (ns uxbox.api.middleware (:require [promesa.core :as p] + [buddy.core.hash :as hash] + [buddy.core.codecs :as codecs] + [buddy.core.codecs.base64 :as b64] [reitit.core :as rc] [reitit.ring.middleware.multipart :as multipart] [reitit.ring.middleware.muuntaja :as muuntaja] @@ -115,6 +118,18 @@ ;; "content-type" ;; "authorization"])}) +;; (defn digest +;; [^bytes data] +;; (-> (hash/blake2b-256 data) +;; (b64/encode true) +;; (codecs/bytes->str))) + +;; (defn- etag-match? +;; [^Request request ^String new-tag] +;; (let [^Headers headers (.getHeaders request)] +;; (when-let [etag (.get headers "if-none-match")] +;; (= etag new-tag)))) + (def ^:private exception-middleware (exception/create-exception-middleware (assoc exception/default-handlers diff --git a/backend/src/uxbox/fixtures.clj b/backend/src/uxbox/fixtures.clj index 2fa095cd6..60e75c15e 100644 --- a/backend/src/uxbox/fixtures.clj +++ b/backend/src/uxbox/fixtures.clj @@ -8,7 +8,6 @@ "A initial fixtures." (:require [buddy.hashers :as hashers] [buddy.core.codecs :as codecs] - [catacumba.serializers :as sz] [mount.core :as mount] [clj-uuid :as uuid] [suricatta.core :as sc] diff --git a/backend/src/uxbox/frontend.clj b/backend/src/uxbox/frontend.clj deleted file mode 100644 index dc27a0f3b..000000000 --- a/backend/src/uxbox/frontend.clj +++ /dev/null @@ -1,163 +0,0 @@ -;; 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-2017 Andrey Antukh - -(ns uxbox.frontend - (:require [mount.core :refer [defstate]] - [catacumba.core :as ct] - [catacumba.http :as http] - [catacumba.serializers :as sz] - [catacumba.handlers.auth :as cauth] - [catacumba.handlers.parse :as cparse] - [catacumba.handlers.misc :as cmisc] - [uxbox.config :as cfg] - [uxbox.frontend.auth :as auth] - [uxbox.frontend.users :as users] - [uxbox.frontend.errors :as errors] - [uxbox.frontend.projects :as projects] - [uxbox.frontend.pages :as pages] - [uxbox.frontend.images :as images] - [uxbox.frontend.icons :as icons] - [uxbox.frontend.kvstore :as kvstore] - [uxbox.frontend.svgparse :as svgparse] - [uxbox.frontend.debug-emails :as dbgemails] - [uxbox.util.response :refer [rsp]] - [uxbox.util.uuid :as uuid])) - -;; --- Top Level Handlers - -(defn- welcome-api - "A GET entry point for the api that shows - a welcome message." - [context] - (let [body {:message "Welcome to UXBox api."}] - (-> (sz/encode body :json) - (http/ok {:content-type "application/json"})))) - -(defn- debug-only - [context] - (if (-> cfg/config :server :debug) - (ct/delegate) - (http/not-found ""))) - -;; --- Config - -(def cors-conf - {:origin "*" - :max-age 3600 - :allow-methods #{:post :put :get :delete :trace} - :allow-headers #{:x-requested-with :content-type :authorization}}) - -;; --- Routes - -(def auth-opts - {:alg :a256kw :enc :a128cbc-hs256}) - -(defn routes - ([] (routes cfg/config)) - ([config] - (let [auth-opts {:secret cfg/secret - :options auth-opts}] - (ct/routes - [[:any (cauth/auth (cauth/jwe-backend auth-opts))] - [:any (cmisc/autoreloader)] - - [:get "api" #'welcome-api] - - ;; Serve assets on development server - [:assets "media" {:dir "media"}] - [:assets "static" {:dir "static"}] - - [:prefix "debug" - [:any debug-only] - [:get "emails" #'dbgemails/list-emails] - [:get "emails/email" #'dbgemails/show-email]] - - [:prefix "api" - [:any (cmisc/cors cors-conf)] - [:any (cparse/body-params)] - [:error #'errors/handler] - - [:post "auth/token" #'auth/login] - [:post "auth/register" #'users/register-user] - [:get "auth/recovery/:token" #'users/validate-recovery-token] - [:post "auth/recovery" #'users/request-recovery] - [:put "auth/recovery" #'users/recover-password] - - [:get "library/images/:id" #'images/retrieve-image] - - [:get "projects-by-token/:token" #'projects/retrieve-project-by-share-token] - - ;; SVG Parse - [:post "svg/parse" #'svgparse/parse] - - [:any #'auth/authorization] - - ;; KVStore - [:put "kvstore" #'kvstore/update] - [:get "kvstore/:key" #'kvstore/retrieve] - [:delete "kvstore/:key" #'kvstore/delete] - - ;; Projects - [:get "projects/:id/pages" #'pages/list-pages-by-project] - [:put "projects/:id" #'projects/update-project] - [:delete "projects/:id" #'projects/delete-project] - [:post "projects" #'projects/create-project] - [:get "projects" #'projects/list-projects] - - ;; Image Collections - [:put "library/image-collections/:id" #'images/update-collection] - [:delete "library/image-collections/:id" #'images/delete-collection] - [:get "library/image-collections" #'images/list-collections] - [:post "library/image-collections" #'images/create-collection] - [:get "library/image-collections/:id/images" #'images/list-images] - [:get "library/image-collections/images" #'images/list-images] - - ;; Images - [:put "library/images/copy" #'images/copy-image] - [:delete "library/images/:id" #'images/delete-image] - [:put "library/images/:id" #'images/update-image] - [:post "library/images" #'images/create-image] - - ;; Icon Collections - [:put "library/icon-collections/:id" #'icons/update-collection] - [:delete "library/icon-collections/:id" #'icons/delete-collection] - [:get "library/icon-collections" #'icons/list-collections] - [:post "library/icon-collections" #'icons/create-collection] - [:get "library/icon-collections/:id/icons" #'icons/list-icons] - [:get "library/icon-collections/icons" #'icons/list-icons] - - ;; Icons - [:put "library/icons/copy" #'icons/copy-icon] - [:delete "library/icons/:id" #'icons/delete-icon] - [:put "library/icons/:id" #'icons/update-icon] - [:post "library/icons" #'icons/create-icon] - - ;; Pages - [:put "pages/:id/metadata" #'pages/update-page-metadata] - [:get "pages/:id/history" #'pages/retrieve-page-history] - [:put "pages/:id/history/:hid" #'pages/update-page-history] - [:put "pages/:id" #'pages/update-page] - [:delete "pages/:id" #'pages/delete-page] - [:post "pages" #'pages/create-page] - - ;; Profile - [:get "profile/me" #'users/retrieve-profile] - [:put "profile/me" #'users/update-profile] - [:put "profile/me/password" #'users/update-password] - [:post "profile/me/photo" #'users/update-photo]]])))) -;; --- State Initialization - -(defn- start-server - [config] - (let [config {:port (:http-server-port config) - :debug (:http-server-debug config) - :marker-file "basedir" - :max-body-size 52428800}] - (ct/run-server (routes config) config))) - -;; (defstate server -;; :start (start-server cfg/config) -;; :stop (.stop server)) diff --git a/backend/src/uxbox/frontend/auth.clj b/backend/src/uxbox/frontend/auth.clj deleted file mode 100644 index 6e7dd757b..000000000 --- a/backend/src/uxbox/frontend/auth.clj +++ /dev/null @@ -1,33 +0,0 @@ -;; 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.frontend.auth - (:require [clojure.spec.alpha :as s] - [catacumba.core :as ct] - [catacumba.http :as http] - [promesa.core :as p] - [uxbox.util.spec :as us] - [uxbox.services :as sv] - [uxbox.util.uuid :as uuid] - [uxbox.util.response :refer (rsp)])) - -(s/def ::scope string?) -(s/def ::login (s/keys :req-un [::us/username ::us/password ::scope])) - -(defn login - [{data :data}] - (let [data (us/conform ::login data) - message (assoc data :type :login)] - (->> (sv/novelty message) - (p/map #(http/ok (rsp %)))))) - -;; TODO: improve authorization - -(defn authorization - [{:keys [identity] :as context}] - (if identity - (ct/delegate {:identity (uuid/from-string (:id identity))}) - (http/forbidden (rsp nil)))) diff --git a/backend/src/uxbox/frontend/debug_emails.clj b/backend/src/uxbox/frontend/debug_emails.clj deleted file mode 100644 index 606177889..000000000 --- a/backend/src/uxbox/frontend/debug_emails.clj +++ /dev/null @@ -1,68 +0,0 @@ -;; 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.frontend.debug-emails - "A helper namespace for just render emails." - (:require [clojure.edn :as edn] - [catacumba.http :as http] - [hiccup.page :refer (html5)] - [uxbox.emails :as emails] - [uxbox.emails.core :as emails-core])) - -(def +available-emails+ - {:users/register - {:name "Cirilla"} - :users/password-recovery - {:name "Cirilla" - :token "agNFhA6SolcFb4Us2NOTNWh0cfFDquVLAav400xQPjw"}}) - -(defn- render-emails-list - [] - (html5 - [:section {:style "font-family: Monoid, monospace; font-size: 14px;"} - [:h1 "Available emails"] - [:table {:style "width: 500px;"} - [:tbody - [:tr - (for [[type email] @emails-core/emails] - [:tr - [:td (pr-str type)] - [:td - [:a {:href (str "/debug/emails/email?id=" - (pr-str type) - "&type=:text/html")} - "(html)"]] - [:td - [:a {:href (str "/debug/emails/email?id=" - (pr-str type) - "&type=:text/plain")} - "(text)"]]])]]]])) - -(defn list-emails - [context] - (http/ok (render-emails-list) - {:content-type "text/html; charset=utf-8"})) - -(defn- render-email - [type content] - (if (= type :text/html) - content - (html5 - [:pre content]))) - -(defn show-email - [{params :query-params}] - (let [id (edn/read-string (:id params)) - type (or (edn/read-string (:type params)) :text/html) - params (-> (get +available-emails+ id) - (assoc :email/name id)) - email (emails/render params) - content (->> (:body email) - (filter #(= (:uxbox.emails.core/type %) type)) - (first) - (:content))] - (-> (render-email type content) - (http/ok {:content-type "text/html; charset=utf-8"})))) diff --git a/backend/src/uxbox/frontend/errors.clj b/backend/src/uxbox/frontend/errors.clj deleted file mode 100644 index b7ffe1143..000000000 --- a/backend/src/uxbox/frontend/errors.clj +++ /dev/null @@ -1,74 +0,0 @@ -;; 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.frontend.errors - "A errors handling for frontend api." - (:require [catacumba.core :as ct] - [catacumba.http :as http] - [uxbox.util.response :refer (rsp)])) - -(defmulti handle-exception #(:type (ex-data %))) - -(defmethod handle-exception :validation - [err] - (println "\n*********** stack trace ***********") - (.printStackTrace err) - (println "\n********* end stack trace *********") - (let [response (ex-data err)] - (http/bad-request (rsp response)))) - -(defmethod handle-exception :default - [err] - (println "\n*********** stack trace ***********") - (.printStackTrace err) - (println "\n********* end stack trace *********") - (let [response (ex-data err)] - (http/internal-server-error (rsp response)))) - -;; --- Entry Point - -(defn- handle-data-access-exception - [err] - (let [err (.getCause err) - state (.getSQLState err) - message (.getMessage err)] - (case state - "P0002" - (-> (rsp {:message message - :payload nil - :type :occ}) - (http/precondition-failed)) - - (do - (.printStackTrace err) - (-> (rsp {:message message - :type :unexpected - :payload nil}) - (http/internal-server-error)))))) - -(defn- handle-unexpected-exception - [err] - (.printStackTrace err) - (let [message (.getMessage err)] - (-> (rsp {:message message - :type :unexpected - :payload nil}) - (http/internal-server-error)))) - -(defn handler - [context err] - (cond - (instance? clojure.lang.ExceptionInfo err) - (handle-exception err) - - (instance? java.util.concurrent.CompletionException err) - (handler context (.getCause err)) - - (instance? org.jooq.exception.DataAccessException err) - (handle-data-access-exception err) - - :else - (handle-unexpected-exception err))) diff --git a/backend/src/uxbox/frontend/icons.clj b/backend/src/uxbox/frontend/icons.clj deleted file mode 100644 index 6d5adb98a..000000000 --- a/backend/src/uxbox/frontend/icons.clj +++ /dev/null @@ -1,155 +0,0 @@ -;; 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.frontend.icons - (:require [clojure.spec.alpha :as s] - [promesa.core :as p] - [catacumba.http :as http] - [uxbox.util.spec :as us] - [uxbox.services :as sv] - [uxbox.util.response :refer (rsp)] - [uxbox.util.uuid :as uuid])) - -;; --- Constants & Config - -(s/def ::collection (s/nilable ::us/uuid-string)) - -(s/def ::width (s/and number? pos?)) -(s/def ::height (s/and number? pos?)) -(s/def ::view-box (s/and (s/coll-of number?) - #(= 4 (count %)) - vector?)) - -(s/def ::mimetype string?) -(s/def ::metadata - (s/keys :opt-un [::width ::height ::view-box ::mimetype])) - -(s/def ::content string?) - -;; --- Create Collection - -(s/def ::create-collection - (s/keys :req-un [::us/name] :opt-un [::us/id])) - -(defn create-collection - [{user :identity data :data}] - (let [data (us/conform ::create-collection data) - message (assoc data - :type :create-icon-collection - :user user)] - (->> (sv/novelty message) - (p/map (fn [result] - (let [loc (str "/api/library/icons/" (:id result))] - (http/created loc (rsp result)))))))) - -;; --- Update Collection - -(s/def ::update-collection - (s/merge ::create-collection (s/keys :req-un [::us/version]))) - -(defn update-collection - [{user :identity params :route-params data :data}] - (let [data (us/conform ::update-collection data) - message (assoc data - :id (uuid/from-string (:id params)) - :type :update-icon-collection - :user user)] - (-> (sv/novelty message) - (p/then #(http/ok (rsp %)))))) - -;; --- Delete Collection - -(defn delete-collection - [{user :identity params :route-params}] - (let [message {:id (uuid/from-string (:id params)) - :type :delete-icon-collection - :user user}] - (-> (sv/novelty message) - (p/then (fn [v] (http/no-content)))))) - -;; --- List collections - -(defn list-collections - [{user :identity}] - (let [params {:user user - :type :list-icon-collections}] - (-> (sv/query params) - (p/then #(http/ok (rsp %)))))) - -;; --- Create Icon - -(s/def ::create-icon - (s/keys :req-un [::metadata ::us/name ::metadata ::content] - :opt-un [::us/id ::collection])) - -(defn create-icon - [{user :identity data :data :as request}] - (let [{:keys [id name content metadata collection]} (us/conform ::create-icon data) - id (or id (uuid/random))] - (->> (sv/novelty {:id id - :type :create-icon - :user user - :name name - :collection collection - :metadata metadata - :content content}) - (p/map (fn [entry] - (let [loc (str "/api/library/icons/" (:id entry))] - (http/created loc (rsp entry)))))))) - -;; --- Update Icon - -(s/def ::update-icon - (s/keys :req-un [::us/name ::us/version ::collection] :opt-un [::us/id])) - -(defn update-icon - [{user :identity params :route-params data :data}] - (let [data (us/conform ::update-icon data) - message (assoc data - :id (uuid/from-string (:id params)) - :type :update-icon - :user user)] - (->> (sv/novelty message) - (p/map #(http/ok (rsp %)))))) - -;; --- Copy Icon - -(s/def ::copy-icon - (s/keys :req-un [:us/id ::collection])) - -(defn copy-icon - [{user :identity data :data}] - (let [data (us/conform ::copy-icon data) - message (assoc data - :user user - :type :copy-icon)] - (->> (sv/novelty message) - (p/map #(http/ok (rsp %)))))) - -;; --- Delete Icon - -(defn delete-icon - [{user :identity params :route-params}] - (let [message {:id (uuid/from-string (:id params)) - :type :delete-icon - :user user}] - (->> (sv/novelty message) - (p/map (fn [v] (http/no-content)))))) - -;; --- List collections - -(s/def ::list-icons - (s/keys :opt-un [::us/id])) - -(defn list-icons - [{user :identity route-params :route-params}] - (let [{:keys [id]} (us/conform ::list-icons route-params) - params {:collection id - :type :list-icons - :user user}] - (->> (sv/query params) - (p/map rsp) - (p/map http/ok)))) diff --git a/backend/src/uxbox/frontend/images.clj b/backend/src/uxbox/frontend/images.clj deleted file mode 100644 index b8733f9a9..000000000 --- a/backend/src/uxbox/frontend/images.clj +++ /dev/null @@ -1,197 +0,0 @@ -;; 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.frontend.images - (:require [clojure.spec.alpha :as s] - [promesa.core :as p] - [catacumba.http :as http] - [datoteka.storages :as st] - [datoteka.core :as fs] - [uxbox.media :as media] - [uxbox.images :as images] - [uxbox.util.spec :as us] - [uxbox.services :as sv] - [uxbox.util.response :refer (rsp)] - [uxbox.util.uuid :as uuid])) - -;; --- Constants & Config - -(s/def ::file ::us/uploaded-file) -(s/def ::width ::us/integer-string) -(s/def ::height ::us/integer-string) -(s/def ::collection (s/nilable ::us/uuid-string)) -(s/def ::mimetype string?) - -(def +thumbnail-options+ {:src :path - :dst :thumbnail - :width 300 - :height 100 - :quality 92 - :format "webp"}) - -(def populate-thumbnails - #(images/populate-thumbnails % +thumbnail-options+)) - -(def populate-urls - #(images/populate-urls % media/images-storage :path :url)) - -;; --- Create Collection - -(s/def ::create-collection - (s/keys :req-un [::us/name] :opt-un [::us/id])) - -(defn create-collection - [{user :identity data :data}] - (let [data (us/conform ::create-collection data) - message (assoc data - :type :create-image-collection - :user user)] - (->> (sv/novelty message) - (p/map (fn [result] - (let [loc (str "/api/library/images/" (:id result))] - (http/created loc (rsp result)))))))) - -;; --- Update Collection - -(s/def ::update-collection - (s/merge ::create-collection (s/keys :req-un [::us/version]))) - -(defn update-collection - [{user :identity params :route-params data :data}] - (let [data (us/conform ::update-collection data) - message (assoc data - :id (uuid/from-string (:id params)) - :type :update-image-collection - :user user)] - (-> (sv/novelty message) - (p/then #(http/ok (rsp %)))))) - -;; --- Delete Collection - -(defn delete-collection - [{user :identity params :route-params}] - (let [message {:id (uuid/from-string (:id params)) - :type :delete-image-collection - :user user}] - (-> (sv/novelty message) - (p/then (fn [v] (http/no-content)))))) - -;; --- List collections - -(defn list-collections - [{user :identity}] - (let [params {:user user - :type :list-image-collections}] - (-> (sv/query params) - (p/then #(http/ok (rsp %)))))) - -;; --- Retrieve Image - -(s/def ::retrieve-image - (s/keys :req-un [::us/id])) - -(defn retrieve-image - [{user :identity params :route-params}] - (let [params (us/conform ::retrieve-image params) - params (assoc params :user user :type :retrieve-image)] - (->> (sv/query params) - (p/map (fn [result] - (if result - (-> (populate-thumbnails result) - (populate-urls) - (rsp) - (http/ok)) - (http/not-found ""))))))) - -;; --- Create Image - -(s/def ::create-image - (s/keys :req-un [::file ::width ::height ::mimetype] - :opt-un [::us/id ::collection])) - -(defn create-image - [{user :identity data :data}] - (let [{:keys [file id width height - mimetype collection]} (us/conform ::create-image data) - id (or id (uuid/random)) - filename (fs/name file) - storage media/images-storage] - (letfn [(persist-image-entry [path] - (sv/novelty {:id id - :type :create-image - :user user - :width width - :height height - :mimetype mimetype - :collection collection - :name filename - :path (str path)})) - (create-response [entry] - (let [loc (str "/api/library/images/" (:id entry))] - (http/created loc (rsp entry))))] - (->> (st/save storage filename file) - (p/mapcat persist-image-entry) - (p/map populate-thumbnails) - (p/map populate-urls) - (p/map create-response))))) - -;; --- Update Image - -(s/def ::update-image - (s/keys :req-un [::us/name ::us/version ::collection] :opt-un [::us/id])) - -(defn update-image - [{user :identity params :route-params data :data}] - (let [data (us/conform ::update-image data) - message (assoc data - :id (uuid/from-string (:id params)) - :type :update-image - :user user)] - (->> (sv/novelty message) - (p/map populate-thumbnails) - (p/map populate-urls) - (p/map #(http/ok (rsp %)))))) - -;; --- Copy Image - -(s/def ::copy-image - (s/keys :req-un [::us/id ::collection])) - -(defn copy-image - [{user :identity data :data}] - (let [data (us/conform ::copy-image data) - params (assoc data :user user :type :copy-image)] - (->> (sv/novelty params) - (p/map populate-thumbnails) - (p/map populate-urls) - (p/map #(http/ok (rsp %)))))) - -;; --- Delete Image - -(defn delete-image - [{user :identity params :route-params}] - (let [message {:id (uuid/from-string (:id params)) - :type :delete-image - :user user}] - (->> (sv/novelty message) - (p/map (fn [v] (http/no-content)))))) - -;; --- List collections - -(s/def ::list-images - (s/keys :opt-un [::us/id])) - -(defn list-images - [{user :identity route-params :route-params}] - (let [{:keys [id]} (us/conform ::list-images route-params) - params {:collection id - :type :list-images - :user user}] - (->> (sv/query params) - (p/map (partial map populate-thumbnails)) - (p/map (partial map populate-urls)) - (p/map rsp) - (p/map http/ok)))) diff --git a/backend/src/uxbox/frontend/kvstore.clj b/backend/src/uxbox/frontend/kvstore.clj deleted file mode 100644 index 1a5e1c1a8..000000000 --- a/backend/src/uxbox/frontend/kvstore.clj +++ /dev/null @@ -1,60 +0,0 @@ -;; 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.frontend.kvstore - (:refer-clojure :exclude [update]) - (:require [clojure.spec.alpha :as s] - [promesa.core :as p] - [catacumba.http :as http] - [uxbox.media :as media] - [uxbox.util.spec :as us] - [uxbox.services :as sv] - [uxbox.util.response :refer (rsp)] - [uxbox.util.uuid :as uuid])) - -(s/def ::version integer?) -(s/def ::key string?) -(s/def ::value any?) - -;; --- Retrieve - -(s/def ::retrieve (s/keys :req-un [::key])) - -(defn retrieve - [{user :identity params :route-params}] - (let [data (us/conform ::retrieve params) - params (assoc data - :type :retrieve-kvstore - :user user)] - (->> (sv/query params) - (p/map #(http/ok (rsp %)))))) - -;; --- Update (or Create) - -(s/def ::update (s/keys :req-un [::key ::value] - :opt-un [::version])) - -(defn update - [{user :identity data :data}] - (let [data (us/conform ::update data) - params (assoc data - :type :update-kvstore - :user user)] - (->> (sv/novelty params) - (p/map #(http/ok (rsp %)))))) - -;; --- Delete - -(s/def ::delete (s/keys :req-un [::key])) - -(defn delete - [{user :identity params :route-params}] - (let [data (us/conform ::delete params) - params (assoc data - :type :delete-kvstore - :user user)] - (->> (sv/novelty params) - (p/map (fn [_] (http/no-content)))))) diff --git a/backend/src/uxbox/frontend/pages.clj b/backend/src/uxbox/frontend/pages.clj deleted file mode 100644 index 621901418..000000000 --- a/backend/src/uxbox/frontend/pages.clj +++ /dev/null @@ -1,119 +0,0 @@ -;; 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.frontend.pages - (:require [clojure.spec.alpha :as s] - [promesa.core :as p] - [catacumba.http :as http] - [uxbox.util.spec :as us] - [uxbox.services :as sv] - [uxbox.util.response :refer (rsp)] - [uxbox.util.uuid :as uuid])) - -;; --- List Pages - -(defn list-pages-by-project - [{user :identity params :route-params}] - (let [params {:user user - :project (uuid/from-string (:id params)) - :type :list-pages-by-project}] - (-> (sv/query params) - (p/then #(http/ok (rsp %)))))) - -;; --- Create Page - -(s/def ::data any?) -(s/def ::metadata any?) -(s/def ::project ::us/id) -(s/def ::create-page - (s/keys :req-un [::data ::metadata ::project ::us/name] - :opt-un [::us/id])) - -(defn create-page - [{user :identity data :data}] - (let [data (us/conform ::create-page data) - message (assoc data - :type :create-page - :user user)] - (->> (sv/novelty message) - (p/map (fn [result] - (let [loc (str "/api/pages/" (:id result))] - (http/created loc (rsp result)))))))) - -;; --- Update Page - -(s/def ::update-page - (s/merge ::create-page (s/keys :req-un [::us/version]))) - -(defn update-page - [{user :identity params :route-params data :data}] - (let [data (us/conform ::update-page data) - message (assoc data - :id (uuid/from-string (:id params)) - :type :update-page - :user user)] - (->> (sv/novelty message) - (p/map #(http/ok (rsp %)))))) - -;; --- Update Page Metadata - -(s/def ::update-page-metadata - (s/keys :req-un [::us/id ::metadata ::project ::us/name])) - -(defn update-page-metadata - [{user :identity params :route-params data :data}] - (let [data (us/conform ::update-page-metadata data) - message (assoc data - :id (uuid/from-string (:id params)) - :type :update-page-metadata - :user user)] - (->> (sv/novelty message) - (p/map #(http/ok (rsp %)))))) - -;; --- Delete Page - -(defn delete-page - [{user :identity params :route-params}] - (let [message {:id (uuid/from-string (:id params)) - :type :delete-page - :user user}] - (-> (sv/novelty message) - (p/then (fn [v] (http/no-content)))))) - -;; --- Retrieve Page History - -(s/def ::max (s/and ::us/integer-string ::us/positive-integer)) -(s/def ::since ::us/integer-string) -(s/def ::pinned ::us/boolean-string) - -(s/def ::retrieve-page-history - (s/keys :opt-un [::max ::since ::pinned])) - -(defn retrieve-page-history - [{user :identity params :route-params query :query-params}] - (let [query (us/conform ::retrieve-page-history query) - message (assoc query - :id (uuid/from-string (:id params)) - :type :list-page-history - :user user)] - (->> (sv/query message) - (p/map #(http/ok (rsp %)))))) - -;; --- Update Page History - -(s/def ::label string?) -(s/def ::update-page-history - (s/keys :req-un [::label ::pinned])) - -(defn update-page-history - [{user :identity params :route-params data :data}] - (let [data (us/conform ::update-page-history data) - message (assoc data - :type :update-page-history - :id (uuid/from-string (:hid params)) - :user user)] - (->> (sv/novelty message) - (p/map #(http/ok (rsp %)))))) diff --git a/backend/src/uxbox/frontend/projects.clj b/backend/src/uxbox/frontend/projects.clj deleted file mode 100644 index e88e4020b..000000000 --- a/backend/src/uxbox/frontend/projects.clj +++ /dev/null @@ -1,73 +0,0 @@ -;; 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.frontend.projects - (:require [clojure.spec.alpha :as s] - [promesa.core :as p] - [catacumba.http :as http] - [uxbox.util.spec :as us] - [uxbox.services :as sv] - [uxbox.util.response :refer (rsp)] - [uxbox.util.uuid :as uuid])) - -;; --- List Projects - -(defn list-projects - [{user :identity}] - (let [message {:user user :type :list-projects}] - (->> (sv/query message) - (p/map #(http/ok (rsp %)))))) - -;; --- Create Projects - -(s/def ::create-project - (s/keys :req-un [::us/name] :opt-un [::us/id])) - -(defn create-project - [{user :identity data :data}] - (let [data (us/conform ::create-project data) - message (assoc data - :type :create-project - :user user)] - (->> (sv/novelty message) - (p/map (fn [result] - (let [loc (str "/api/projects/" (:id result))] - (http/created loc (rsp result)))))))) - -;; --- Update Project - -(s/def ::update-project - (s/keys :req-un [::us/name ::us/version])) - -(defn update-project - [{user :identity params :route-params data :data}] - (let [data (us/conform ::update-project data) - message (assoc data - :id (uuid/from-string (:id params)) - :type :update-project - :user user)] - (-> (sv/novelty message) - (p/then #(http/ok (rsp %)))))) - -;; --- Delete Project - -(defn delete-project - [{user :identity params :route-params}] - (let [message {:id (uuid/from-string (:id params)) - :type :delete-project - :user user}] - (-> (sv/novelty message) - (p/then (fn [v] (http/no-content)))))) - - -;; --- Retrieve project - -(defn retrieve-project-by-share-token - [{params :route-params}] - (let [message {:token (:token params) - :type :retrieve-project-by-share-token}] - (->> (sv/query message) - (p/map #(http/ok (rsp %)))))) diff --git a/backend/src/uxbox/frontend/svgparse.clj b/backend/src/uxbox/frontend/svgparse.clj deleted file mode 100644 index 827a38ff6..000000000 --- a/backend/src/uxbox/frontend/svgparse.clj +++ /dev/null @@ -1,22 +0,0 @@ -;; 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.frontend.svgparse - "A frontend exposed endpoints for svgparse functionality." - (:require [clojure.spec.alpha :as s] - [promesa.core :as p] - [catacumba.http :as http] - [uxbox.util.spec :as us] - [uxbox.services :as sv] - [uxbox.util.response :refer (rsp)] - [uxbox.util.uuid :as uuid])) - -(defn parse - [{body :body :as context}] - (let [message {:data (slurp body) - :type :parse-svg}] - (->> (sv/query message) - (p/map #(http/ok (rsp %)))))) diff --git a/backend/src/uxbox/frontend/users.clj b/backend/src/uxbox/frontend/users.clj deleted file mode 100644 index 7cc05ca02..000000000 --- a/backend/src/uxbox/frontend/users.clj +++ /dev/null @@ -1,149 +0,0 @@ -;; 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.frontend.users - (:require [clojure.spec.alpha :as s] - [promesa.core :as p] - [catacumba.http :as http] - [datoteka.storages :as st] - [datoteka.core :as fs] - [uxbox.media :as media] - [uxbox.images :as images] - [uxbox.util.spec :as us] - [uxbox.services :as sv] - [uxbox.services.users :as svu] - [uxbox.util.response :refer (rsp)] - [uxbox.util.uuid :as uuid])) - -;; --- Helpers - -(defn- resolve-thumbnail - [user] - (let [opts {:src :photo - :dst :photo - :size [100 100] - :quality 90 - :format "jpg"}] - (images/populate-thumbnails user opts))) - -;; --- Retrieve Profile - -(defn retrieve-profile - [{user :identity}] - (let [message {:user user - :type :retrieve-profile}] - (->> (sv/query message) - (p/map resolve-thumbnail) - (p/map #(http/ok (rsp %)))))) - -;; --- Update Profile - -(s/def ::fullname string?) -(s/def ::metadata any?) -(s/def ::update-profile - (s/keys :req-un [::us/id ::us/username ::us/email - ::fullname ::metadata])) - -(defn update-profile - [{user :identity data :data}] - (let [data (us/conform ::update-profile data) - message (assoc data - :type :update-profile - :user user)] - (->> (sv/novelty message) - (p/map resolve-thumbnail) - (p/map #(http/ok (rsp %)))))) - -;; --- Update Password - -(s/def ::old-password ::us/password) -(s/def ::update-password - (s/keys :req-un [::us/password ::old-password])) - -(defn update-password - [{user :identity data :data}] - (let [data (us/conform ::update-password data) - message (assoc data - :type :update-profile-password - :user user)] - (-> (sv/novelty message) - (p/then #(http/ok (rsp %)))))) - -;; --- Update Profile Photo - -(s/def ::file ::us/uploaded-file) -(s/def ::update-photo (s/keys :req-un [::file])) - -(defn update-photo - [{user :identity data :data}] - (letfn [(store-photo [file] - (let [filename (fs/name file) - storage media/images-storage] - (st/save storage filename file))) - (assign-photo [path] - (sv/novelty {:user user - :path (str path) - :type :update-profile-photo})) - (create-response [_] - (http/no-content))] - (let [{:keys [file]} (us/conform ::update-photo data)] - (->> (store-photo file) - (p/mapcat assign-photo) - (p/map create-response))))) - -;; --- Register User - -(s/def ::register - (s/keys :req-un [::us/username ::us/email ::us/password ::fullname])) - -(defn register-user - [{data :data}] - (let [data (us/conform ::register data) - message (assoc data :type :register-profile)] - (->> (sv/novelty message) - (p/map #(http/ok (rsp %)))))) - - -;; --- Request Password Recovery - -;; FIXME: rename for consistency - -(s/def ::request-recovery - (s/keys :req-un [::us/username])) - -(defn request-recovery - [{data :data}] - (let [data (us/conform ::request-recovery data) - message (assoc data :type :request-profile-password-recovery)] - (->> (sv/novelty message) - (p/map (fn [_] (http/no-content)))))) - -;; --- Password Recovery - -;; FIXME: rename for consistency - -(s/def ::token string?) -(s/def ::password-recovery - (s/keys :req-un [::token ::us/password])) - -(defn recover-password - [{data :data}] - (let [data (us/conform ::password-recovery data) - message (assoc data :type :recover-profile-password)] - (->> (sv/novelty message) - (p/map (fn [_] (http/no-content)))))) - -;; --- Valiadate Recovery Token - -(defn validate-recovery-token - [{params :route-params}] - (let [message {:type :validate-profile-password-recovery-token - :token (:token params)}] - (->> (sv/query message) - (p/map (fn [v] - (if v - (http/no-content) - (http/not-found ""))))))) diff --git a/backend/src/uxbox/images.clj b/backend/src/uxbox/images.clj index c603a1875..0d6035a4b 100644 --- a/backend/src/uxbox/images.clj +++ b/backend/src/uxbox/images.clj @@ -16,8 +16,6 @@ [uxbox.util.data :refer (dissoc-in)]) (:import java.io.InputStream java.io.ByteArrayInputStream - ratpack.form.UploadedFile - ratpack.http.TypedData org.im4java.core.IMOperation org.im4java.core.ConvertCmd)) @@ -107,27 +105,3 @@ (dissoc-in src) (assoc-in dst url)))))) -;; --- Impl - -(extend-type UploadedFile - pt/IPath - (-path [this] - (pt/-path (.getFileName ^UploadedFile this)))) - -(extend-type TypedData - pt/IContent - (-input-stream [this] - (.getInputStream this)) - - io/IOFactory - (make-reader [td opts] - (let [^InputStream is (.getInputStream td)] - (io/make-reader is opts))) - (make-writer [path opts] - (throw (UnsupportedOperationException. "read only object"))) - (make-input-stream [td opts] - (let [^InputStream is (.getInputStream td)] - (io/make-input-stream is opts))) - (make-output-stream [path opts] - (throw (UnsupportedOperationException. "read only object")))) - diff --git a/backend/src/uxbox/main.clj b/backend/src/uxbox/main.clj index c6bfaf32d..5c7478075 100644 --- a/backend/src/uxbox/main.clj +++ b/backend/src/uxbox/main.clj @@ -9,7 +9,7 @@ [uxbox.config :as cfg] [uxbox.migrations] [uxbox.db] - [uxbox.frontend] + [uxbox.api] [uxbox.scheduled-jobs]) (:gen-class)) diff --git a/backend/src/uxbox/services/icons.clj b/backend/src/uxbox/services/icons.clj index fb3164a9e..b32c52f30 100644 --- a/backend/src/uxbox/services/icons.clj +++ b/backend/src/uxbox/services/icons.clj @@ -17,8 +17,7 @@ [uxbox.util.uuid :as uuid] [uxbox.util.blob :as blob] [uxbox.util.data :as data]) - (:import ratpack.form.UploadedFile - org.apache.commons.io.FilenameUtils)) + (:import org.apache.commons.io.FilenameUtils)) ;; --- Helpers & Specs diff --git a/backend/src/uxbox/services/images.clj b/backend/src/uxbox/services/images.clj index 35ca073c1..d8c2de5dd 100644 --- a/backend/src/uxbox/services/images.clj +++ b/backend/src/uxbox/services/images.clj @@ -21,8 +21,7 @@ [uxbox.util.transit :as t] [uxbox.util.uuid :as uuid] [uxbox.util.data :as data]) - (:import ratpack.form.UploadedFile - org.apache.commons.io.FilenameUtils)) + (:import org.apache.commons.io.FilenameUtils)) (s/def ::width integer?) (s/def ::height integer?) diff --git a/backend/src/uxbox/util/response.clj b/backend/src/uxbox/util/response.clj deleted file mode 100644 index 4ecf79dae..000000000 --- a/backend/src/uxbox/util/response.clj +++ /dev/null @@ -1,73 +0,0 @@ -;; 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.util.response - "A lightweigt reponse type definition. - - At first instance it allows set the appropriate - content-type headers and encode the body using - the builtin transit abstraction. - - In future it will allow easy adapt for the content - negotiation that is coming to catacumba." - (:require [catacumba.impl.handlers :as ch] - [catacumba.impl.context :as ctx] - [buddy.core.hash :as hash] - [buddy.core.codecs :as codecs] - [buddy.core.codecs.base64 :as b64] - [uxbox.util.transit :as t]) - (:import ratpack.handling.Context - ratpack.http.Response - ratpack.http.Request - ratpack.http.Headers - ratpack.http.MutableHeaders)) - -(defn digest - [^bytes data] - (-> (hash/blake2b-256 data) - (b64/encode true) - (codecs/bytes->str))) - -(defn- etag-match? - [^Request request ^String new-tag] - (let [^Headers headers (.getHeaders request)] - (when-let [etag (.get headers "if-none-match")] - (= etag new-tag)))) - -(deftype Rsp [data] - clojure.lang.IDeref - (deref [_] data) - - ch/ISend - (-send [_ ctx] - (let [^Response response (ctx/get-response* ctx) - ^Request request (ctx/get-request* ctx) - ^MutableHeaders headers (.getHeaders response) - ^String method (.. request getMethod getName toLowerCase) - data (t/encode data)] - (if (= method "get") - (let [etag (digest data)] - (if (etag-match? request etag) - (do - (.set headers "etag" etag) - (.status response 304) - (.send response)) - (do - (.set headers "content-type" "application/transit+json") - (.set headers "etag" etag) - (ch/-send data ctx)))) - (do - (.set headers "content-type" "application/transit+json") - (ch/-send data ctx)))))) - -(defn rsp - "A shortcut for create a response instance." - [data] - (Rsp. data)) - -(defn rsp? - [v] - (instance? Rsp v)) diff --git a/backend/src/uxbox/util/spec.clj b/backend/src/uxbox/util/spec.clj index e448b4973..bbfe81b19 100644 --- a/backend/src/uxbox/util/spec.clj +++ b/backend/src/uxbox/util/spec.clj @@ -104,7 +104,7 @@ (s/def ::uuid-string (s/conformer uuid-conformer str)) (s/def ::boolean-string (s/conformer boolean-conformer boolean-unformer)) (s/def ::positive-integer #(< 0 % Long/MAX_VALUE)) -(s/def ::uploaded-file #(instance? ratpack.form.UploadedFile %)) +(s/def ::uploaded-file any?) (s/def ::uuid uuid?) (s/def ::bytes bytes?) (s/def ::path path?) diff --git a/backend/src/uxbox/util/struct.clj b/backend/src/uxbox/util/struct.clj new file mode 100644 index 000000000..f15ab1ca3 --- /dev/null +++ b/backend/src/uxbox/util/struct.clj @@ -0,0 +1,3 @@ +(ns uxbox.util.struct + (:refer-clojure :exclude [keyword uuid vector boolean long map set]) + (:require [struct.core :as st])) diff --git a/backend/src/uxbox/util/transit.clj b/backend/src/uxbox/util/transit.clj index 757258360..9f0159aa8 100644 --- a/backend/src/uxbox/util/transit.clj +++ b/backend/src/uxbox/util/transit.clj @@ -6,11 +6,8 @@ (ns uxbox.util.transit (:require [cognitect.transit :as t] - [catacumba.handlers.parse :as cparse] [uxbox.util.time :as dt]) - (:import ratpack.http.TypedData - ratpack.handling.Context - java.io.ByteArrayInputStream + (:import java.io.ByteArrayInputStream java.io.ByteArrayOutputStream)) ;; --- Handlers @@ -41,14 +38,6 @@ [writer data] (t/write writer data)) - -;; --- Catacumba Extension - -(defmethod cparse/parse-body :application/transit+json - [^Context ctx ^TypedData body] - (let [reader (reader (.getInputStream body) {:type :json})] - (read! reader))) - ;; --- High-Level Api (defn decode diff --git a/backend/test/uxbox/tests/helpers.clj b/backend/test/uxbox/tests/helpers.clj index b6ac9ddc0..9ff22d473 100644 --- a/backend/test/uxbox/tests/helpers.clj +++ b/backend/test/uxbox/tests/helpers.clj @@ -4,7 +4,6 @@ [buddy.hashers :as hashers] [buddy.core.codecs :as codecs] [cuerdas.core :as str] - [catacumba.serializers :as sz] [ring.adapter.jetty :as jetty] [mount.core :as mount] [datoteka.storages :as st]