mirror of https://github.com/logseq/logseq
Add apis
parent
2187e04439
commit
1a89bcfd18
|
@ -24,7 +24,7 @@
|
|||
[aero "1.1.6"]
|
||||
[com.stuartsierra/component "0.4.0"]
|
||||
[com.taoensso/nippy "2.14.0"]
|
||||
]
|
||||
[hiccup "1.0.5"]]
|
||||
;; :main backend.core
|
||||
:profiles {:repl {:dependencies [[io.pedestal/pedestal.service-tools "0.5.7"]]
|
||||
:source-paths ["src/backend" "dev"]}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/home/tienson/codes/projects/gitnotes/frontend/public
|
|
@ -12,7 +12,7 @@
|
|||
(let [{:keys [app-key app-secret redirect-uri]} (get-in config/config [:oauth :github])
|
||||
instance (social/make-social :github app-key app-secret redirect-uri
|
||||
:state (str (util/uuid))
|
||||
:scope "user:email")
|
||||
:scope "user:email,repo")
|
||||
access-token (social/getAccessToken instance (:code data))
|
||||
info (social/getUserInfo instance access-token)
|
||||
oauth-type "github"
|
||||
|
@ -21,9 +21,11 @@
|
|||
(toucan.db/transaction
|
||||
(if-let [token (token/get oauth-type oauth-id)]
|
||||
;; user already exists
|
||||
(let [token (assoc token :token access-token)]
|
||||
(some-> (u/get (:user_id token))
|
||||
(assoc :token token)))
|
||||
(do
|
||||
(prn {:token token})
|
||||
(let [token (assoc token :token access-token)]
|
||||
(some-> (u/get (:user_id token))
|
||||
(assoc :token token))))
|
||||
(when-let [user (u/insert {:name (:login info)
|
||||
:email (:email info)})]
|
||||
(let [token (token/create {:user_id (:id user)
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
(let [dev? config/dev?
|
||||
xsrf-token (str (util/uuid))
|
||||
domain (if-not dev?
|
||||
".chengdongchengxi.com"
|
||||
".gitnotes.com"
|
||||
"")
|
||||
secure (if-not dev?
|
||||
true
|
||||
|
@ -40,7 +40,7 @@
|
|||
|
||||
(def delete-token
|
||||
(let [domain (if-not config/dev?
|
||||
".chengdongchengxi.com"
|
||||
".gitnotes.com"
|
||||
"")]
|
||||
{"x" {:value ""
|
||||
:path "/"
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
(db/select-one Token {:oauth_type oauth-type
|
||||
:oauth_id oauth-id}))
|
||||
|
||||
(defn get-user-tokens
|
||||
[user-id]
|
||||
(db/select Token {:user_id user-id}))
|
||||
|
||||
(defn exists?
|
||||
[oauth-type oauth-id]
|
||||
(db/exists? Token {:oauth_type oauth-type
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
(defn get
|
||||
[id]
|
||||
(db/select-one User id))
|
||||
(db/select-one User :id id))
|
||||
|
||||
(defn insert
|
||||
[{:keys [name email] :as args}]
|
||||
|
@ -39,7 +39,7 @@
|
|||
[:ok (db/update! User id {:email email})]))
|
||||
|
||||
(defn generate-tokens
|
||||
[db user-id]
|
||||
[user-id]
|
||||
(cookie/token-cookie
|
||||
{:access-token (jwt/sign {:id user-id})
|
||||
:refresh-token (refresh-token/create user-id)}))
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
(ns backend.interceptors
|
||||
(:require [io.pedestal.interceptor :refer [interceptor]]
|
||||
[backend.cookie :as cookie]
|
||||
[backend.jwt :as jwt]
|
||||
[backend.db.user :as u]
|
||||
[backend.util :as util]))
|
||||
|
||||
(def cookie-interceptor
|
||||
{:name ::cookie-authenticate
|
||||
:enter
|
||||
(fn [{:keys [request] :as context}]
|
||||
(let [tokens (cookie/get-token request)]
|
||||
(if tokens
|
||||
(let [{:keys [access-token refresh-token]} tokens]
|
||||
(if access-token
|
||||
(try
|
||||
(let [user (jwt/unsign access-token)
|
||||
uid (some-> (:id user) util/->uuid)
|
||||
user (u/get uid)]
|
||||
(if (:id user)
|
||||
(-> context
|
||||
(assoc-in [:request :app-context :uid] uid)
|
||||
(assoc-in [:request :app-context :user] user))
|
||||
context))
|
||||
(catch Exception e
|
||||
nil))
|
||||
;; TODO: wrong cookie, early halt
|
||||
))
|
||||
context)))})
|
|
@ -5,7 +5,10 @@
|
|||
[backend.util :as util]
|
||||
[backend.auth :as auth]
|
||||
[backend.db.user :as u]
|
||||
[ring.util.response :as resp]))
|
||||
[backend.db.token :as token]
|
||||
[ring.util.response :as resp]
|
||||
[backend.views.home :as home]
|
||||
[backend.interceptors :as interceptors]))
|
||||
|
||||
(def routes
|
||||
[["/swagger.json"
|
||||
|
@ -14,6 +17,13 @@
|
|||
:description "with pedestal & reitit-http"}}
|
||||
:handler (swagger/create-swagger-handler)}}]
|
||||
|
||||
[
|
||||
"/"
|
||||
{:get {:no-doc true
|
||||
:handler (fn [_req]
|
||||
{:status 200
|
||||
:body (home/home)})}}]
|
||||
|
||||
["/login"
|
||||
{:swagger {:tags ["Login"]}}
|
||||
|
||||
|
@ -27,9 +37,8 @@
|
|||
"?referer="
|
||||
(get-in req [:headers "referer"] ""))
|
||||
:state (str (util/uuid))
|
||||
:scope "user:email")
|
||||
:scope "user:email,repo")
|
||||
url (social/getAuthorizationUrl social)]
|
||||
(prn "url: " url)
|
||||
(resp/redirect url))
|
||||
)}}]]
|
||||
["/auth"
|
||||
|
@ -42,13 +51,22 @@
|
|||
(if (and (:code params)
|
||||
(:state params))
|
||||
(if-let [user (auth/github params)]
|
||||
(resp/header
|
||||
(assoc :cookies
|
||||
(u/generate-tokens user)
|
||||
:status 302)
|
||||
"Location" config/website-uri)
|
||||
(-> (resp/redirect config/website-uri)
|
||||
(assoc :cookies (u/generate-tokens (:id user))))
|
||||
{:status 500
|
||||
:body "Internal Error"})
|
||||
{:status 401
|
||||
:body "Invalid request"}))}}]]
|
||||
["/api/v1" {:interceptors [interceptors/cookie-interceptor]}
|
||||
["/me"
|
||||
{:get {:summary "Get current user's information"
|
||||
:handler
|
||||
(fn [{:keys [app-context] :as req}]
|
||||
(if-let [user (:user app-context)]
|
||||
(let [tokens (token/get-user-tokens (:id user))]
|
||||
{:status 200
|
||||
:body {:user user
|
||||
:tokens tokens}})
|
||||
{:status 200
|
||||
:body {:user nil}}))}}]]
|
||||
])
|
||||
|
|
|
@ -21,46 +21,54 @@
|
|||
[com.stuartsierra.component :as component]
|
||||
[backend.components.http :as component-http]
|
||||
[backend.components.hikari :as hikari]
|
||||
[backend.routes :as routes]))
|
||||
[backend.routes :as routes]
|
||||
[backend.config :as config]
|
||||
[io.pedestal.http.ring-middlewares :as ring-middlewares]))
|
||||
|
||||
(def router
|
||||
(pedestal/routing-interceptor
|
||||
(http/router
|
||||
routes/routes
|
||||
(http/router
|
||||
routes/routes
|
||||
|
||||
{;:reitit.interceptor/transform dev/print-context-diffs ;; pretty context diffs
|
||||
;;:validate spec/validate ;; enable spec validation for route data
|
||||
;;:reitit.spec/wrap spell/closed ;; strict top-level validation
|
||||
:exception pretty/exception
|
||||
:data {:coercion reitit.coercion.spec/coercion
|
||||
:muuntaja m/instance
|
||||
:interceptors [;; swagger feature
|
||||
swagger/swagger-feature
|
||||
;; query-params & form-params
|
||||
(parameters/parameters-interceptor)
|
||||
;; content-negotiation
|
||||
(muuntaja/format-negotiate-interceptor)
|
||||
;; encoding response body
|
||||
(muuntaja/format-response-interceptor)
|
||||
;; exception handling
|
||||
(exception/exception-interceptor)
|
||||
;; decoding request body
|
||||
(muuntaja/format-request-interceptor)
|
||||
;; coercing response bodys
|
||||
(coercion/coerce-response-interceptor)
|
||||
;; coercing request parameters
|
||||
(coercion/coerce-request-interceptor)
|
||||
;; multipart
|
||||
(multipart/multipart-interceptor)]}})
|
||||
{;:reitit.interceptor/transform dev/print-context-diffs ;; pretty context diffs
|
||||
;;:validate spec/validate ;; enable spec validation for route data
|
||||
;;:reitit.spec/wrap spell/closed ;; strict top-level validation
|
||||
;; :exception pretty/exception
|
||||
:data {:coercion reitit.coercion.spec/coercion
|
||||
:muuntaja m/instance
|
||||
:interceptors [;; swagger feature
|
||||
swagger/swagger-feature
|
||||
;; query-params & form-params
|
||||
(parameters/parameters-interceptor)
|
||||
;; content-negotiation
|
||||
(muuntaja/format-negotiate-interceptor)
|
||||
;; encoding response body
|
||||
(muuntaja/format-response-interceptor)
|
||||
;; exception handling
|
||||
;; (exception/exception-interceptor)
|
||||
;; decoding request body
|
||||
(muuntaja/format-request-interceptor)
|
||||
;; coercing response bodys
|
||||
(coercion/coerce-response-interceptor)
|
||||
;; coercing request parameters
|
||||
(coercion/coerce-request-interceptor)
|
||||
;; multipart
|
||||
(multipart/multipart-interceptor)]}})
|
||||
|
||||
;; optional default ring handler (if no routes have matched)
|
||||
(ring/routes
|
||||
(swagger-ui/create-swagger-ui-handler
|
||||
{:path "/"
|
||||
:config {:validatorUrl nil
|
||||
:operationsSorter "alpha"}})
|
||||
(ring/create-resource-handler)
|
||||
(ring/create-default-handler))))
|
||||
;; optional default ring handler (if no routes have matched)
|
||||
(ring/routes
|
||||
(swagger-ui/create-swagger-ui-handler
|
||||
{:path "/swagger"
|
||||
:config {:validatorUrl nil
|
||||
:operationsSorter "alpha"}})
|
||||
(ring/create-resource-handler)
|
||||
(ring/create-default-handler))))
|
||||
|
||||
(defn merge-interceptors-map
|
||||
[system-map interceptors]
|
||||
(update system-map :io.pedestal.http/interceptors
|
||||
(fn [old]
|
||||
(vec (concat interceptors old)))))
|
||||
|
||||
(defn new-system
|
||||
[{:keys [env port hikari-spec] :as config}]
|
||||
|
@ -71,14 +79,20 @@
|
|||
;; no pedestal routes
|
||||
::server/routes []
|
||||
;; allow serving the swagger-ui styles & scripts from self
|
||||
::server/secure-headers {:content-security-policy-settings
|
||||
{:default-src "'self'"
|
||||
:style-src "'self' 'unsafe-inline'"
|
||||
:script-src "'self' 'unsafe-inline'"}}}
|
||||
;; ::server/secure-headers {:content-security-policy-settings
|
||||
;; {:default-src "'self'"
|
||||
;; :style-src "'self' 'unsafe-inline'"
|
||||
;; :script-src "'self' 'unsafe-inline'"}}
|
||||
::server/secure-headers {:content-security-policy-settings {:object-src "'none'"}}
|
||||
::server/resource-path "/public"}
|
||||
(server/default-interceptors)
|
||||
;; use the reitit router
|
||||
(pedestal/replace-last-interceptor router)
|
||||
(server/dev-interceptors))]
|
||||
(pedestal/replace-last-interceptor router))
|
||||
service-map (merge-interceptors-map
|
||||
service-map
|
||||
[ring-middlewares/cookies
|
||||
server/html-body])
|
||||
service-map (if config/dev? (server/dev-interceptors service-map) service-map)]
|
||||
(component/system-map :service-map service-map
|
||||
:hikari (hikari/new-hikari-cp hikari-spec)
|
||||
:http
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
(ns backend.views.home
|
||||
(:require [hiccup.page :as html]))
|
||||
|
||||
(defn home
|
||||
[]
|
||||
(html/html5
|
||||
[:head
|
||||
[:meta {:charset "utf-8"}]
|
||||
[:meta
|
||||
{:content
|
||||
"minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no",
|
||||
:name "viewport"}]
|
||||
[:link {:type "text/css", :href "css/style.css", :rel "stylesheet"}]
|
||||
[:link
|
||||
{:href
|
||||
"https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap",
|
||||
:rel "stylesheet"}]
|
||||
[:link {:href "css/highlight.css", :rel "stylesheet"}]
|
||||
[:title "Gitnotes"]]
|
||||
[:body
|
||||
[:div#root]
|
||||
[:script {:src "https://unpkg.com/@isomorphic-git/lightning-fs@3.4.1/dist/lightning-fs.min.js"}]
|
||||
[:script {:src "https://unpkg.com/isomorphic-git@0.78.5/dist/bundle.umd.min.js"}]
|
||||
[:script
|
||||
"window.fs = new LightningFS('gitnotes');git.plugins.set('fs', window.fs);window.pfs = window.fs.promises;"]
|
||||
[:script {:src "/js/main.js"}]
|
||||
[:script {:src "/js/highlight.pack.js"}]]))
|
|
@ -70,4 +70,11 @@
|
|||
[:div "Cloning..."]
|
||||
|
||||
:else
|
||||
(settings/settings-form github-username github-token github-repo)))))
|
||||
(mui/button {:variant "contained"
|
||||
:color "primary"
|
||||
:start-icon (mui/github-icon)
|
||||
:href "/login/github"}
|
||||
"Login with Github")
|
||||
|
||||
;; (settings/settings-form github-username github-token github-repo)
|
||||
))))
|
||||
|
|
|
@ -12,14 +12,6 @@
|
|||
(mui/grid
|
||||
{:container true
|
||||
:direction "column"}
|
||||
(mui/text-field {:id "standard-basic"
|
||||
:style {:margin-bottom 12}
|
||||
:label "Github username"
|
||||
:auto-focus true
|
||||
:on-change (fn [event]
|
||||
(let [v (util/evalue event)]
|
||||
(swap! state/state assoc :github-username v)))
|
||||
:value github-username})
|
||||
(mui/text-field {:id "standard-basic"
|
||||
:style {:margin-bottom 12}
|
||||
:label "Github repo"
|
||||
|
@ -28,13 +20,6 @@
|
|||
(swap! state/state assoc :github-repo v)))
|
||||
:value github-repo
|
||||
})
|
||||
(mui/text-field {:id "standard-basic"
|
||||
:style {:margin-bottom 12}
|
||||
:label "Github basic token"
|
||||
:on-change (fn [event]
|
||||
(let [v (util/evalue event)]
|
||||
(swap! state/state assoc :github-token v)))
|
||||
:value github-token})
|
||||
(mui/button {:variant "contained"
|
||||
:color "primary"
|
||||
:on-click (fn []
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
["@material-ui/core/DialogActions" :default DialogActions]
|
||||
["@material-ui/icons/Favorite" :default FavoriteIcon]
|
||||
["@material-ui/icons/Add" :default AddIcon]
|
||||
["@material-ui/icons/GitHub" :default GithubIcon]
|
||||
["@material-ui/icons/Share" :default ShareIcon]
|
||||
["@material-ui/icons/MoreVert" :default MoreVertIcon]
|
||||
))
|
||||
|
@ -83,6 +84,7 @@
|
|||
(defonce collapse (r/adapt-class Collapse))
|
||||
(defonce avatar (r/adapt-class Avatar))
|
||||
(defonce favorite-icon (r/adapt-class FavoriteIcon))
|
||||
(defonce github-icon (r/adapt-class GithubIcon))
|
||||
(defonce add-icon (r/adapt-class AddIcon))
|
||||
(defonce fab (r/adapt-class Fab))
|
||||
(defonce share-icon (r/adapt-class ShareIcon))
|
||||
|
|
Loading…
Reference in New Issue