diff --git a/src/main/frontend/components/diff.cljs b/src/main/frontend/components/diff.cljs index d9344b2619..49667576ec 100644 --- a/src/main/frontend/components/diff.cljs +++ b/src/main/frontend/components/diff.cljs @@ -13,6 +13,7 @@ [frontend.ui :as ui] [frontend.db :as db] [frontend.git :as git] + [frontend.helper :as helper] [goog.object :as gobj] [promesa.core :as p] [frontend.github :as github] @@ -135,20 +136,22 @@ [:div "loading..."])])) ;; TODO: `n` shortcut for next diff, `p` for previous diff -(rum/defcc diff < rum/reactive +(rum/defcc diff < + rum/reactive {:will-mount (fn [state] (when-let [repo (state/get-current-repo)] (p/let [remote-latest-commit (common-handler/get-remote-ref repo) local-latest-commit (common-handler/get-ref repo) - result (git/get-local-diffs repo local-latest-commit remote-latest-commit)] + result (git/get-local-diffs repo local-latest-commit remote-latest-commit) + token (helper/get-github-token repo)] (reset! diffs result) (reset! remote-hash-id remote-latest-commit) (doseq [{:keys [type path]} result] (when (contains? #{"added" "modify"} type) (github/get-content - (state/get-github-token repo) + token repo path remote-latest-commit @@ -167,7 +170,6 @@ :href (str "https://github.com/apps/" config/github-app-name "/installations/new"))] :error false)))))))) - state) :will-unmount (fn [state] (reset! diffs nil) @@ -197,9 +199,9 @@ path)) [:div (ui/textarea - {:placeholder "Commit message (optional)" - :on-change (fn [e] - (reset! commit-message (util/evalue e)))}) + {:placeholder "Commit message (optional)" + :on-change (fn [e] + (reset! commit-message (util/evalue e)))}) (if pushing? [:span (ui/loading "Pushing")] (ui/button "Commit and push" diff --git a/src/main/frontend/core.cljs b/src/main/frontend/core.cljs index bebd059528..c0dbaa0ebc 100644 --- a/src/main/frontend/core.cljs +++ b/src/main/frontend/core.cljs @@ -4,8 +4,10 @@ [frontend.handler.route :as route] [frontend.page :as page] [frontend.routes :as routes] + [frontend.spec] [reitit.frontend :as rf] - [reitit.frontend.easy :as rfe])) + [reitit.frontend.easy :as rfe] + )) (defn set-router! [] diff --git a/src/main/frontend/handler.cljs b/src/main/frontend/handler.cljs index 271d9ecb28..99b2f366d4 100644 --- a/src/main/frontend/handler.cljs +++ b/src/main/frontend/handler.cljs @@ -12,7 +12,8 @@ [frontend.handler.file :as file-handler] [frontend.handler.ui :as ui-handler] [frontend.ui :as ui] - [goog.object :as gobj])) + [goog.object :as gobj] + [frontend.helper :as helper])) (defn- watch-for-date! [] @@ -50,7 +51,7 @@ (state/set-db-restoring! false)) (if (seq (:repos me)) ;; FIXME: handle error - (repo-handler/request-app-tokens! + (helper/request-app-tokens! (fn [] (repo-handler/clone-and-pull-repos me)) (fn [] diff --git a/src/main/frontend/handler/git.cljs b/src/main/frontend/handler/git.cljs index eab82aee10..fd52e0fbc5 100644 --- a/src/main/frontend/handler/git.cljs +++ b/src/main/frontend/handler/git.cljs @@ -10,7 +10,8 @@ [frontend.handler.notification :as notification] [frontend.handler.route :as route-handler] [frontend.handler.common :as common-handler] - [cljs-time.local :as tl])) + [cljs-time.local :as tl] + [frontend.helper :as helper])) (defn- set-git-status! [repo-url value] @@ -43,9 +44,8 @@ (p/let [remote-oid (common-handler/get-remote-ref repo) commit-oid (git/commit repo commit-message (array remote-oid)) result (git/write-ref! repo commit-oid) - push-result (git/push repo - (state/get-github-token repo) - true)] + token (helper/get-github-token repo) + push-result (git/push repo token true)] (reset! pushing? false) (notification/clear! nil) (route-handler/redirect! {:to :home})))) diff --git a/src/main/frontend/handler/repo.cljs b/src/main/frontend/handler/repo.cljs index 4d803774d2..21be03567e 100644 --- a/src/main/frontend/handler/repo.cljs +++ b/src/main/frontend/handler/repo.cljs @@ -21,8 +21,7 @@ [cljs.reader :as reader] [clojure.string :as string] [frontend.dicts :as dicts] - ;; [clojure.set :as set] -)) + [frontend.helper :as helper])) ;; Project settings should be checked in two situations: ;; 1. User changes the config.edn directly in logseq.com (fn: alter-file) @@ -43,42 +42,6 @@ :error false)) -(defn get-new-token - [repo] - (when-let [installation-id (-> (filter - (fn [r] - (= (:url r) repo)) - (:repos (state/get-me))) - (first) - :installation_id)] - (util/post (str config/api "refresh_github_token") - {:installation-ids [installation-id]} - (fn [result] - (let [token (:token (first result))] - (state/set-github-token! repo token))) - (fn [error] - (println "Something wrong!") - (js/console.dir error))))) - -(defn request-app-tokens! - [ok-handler error-handler] - (let [repos (:repos (state/get-me)) - installation-ids (->> (map :installation_id repos) - (remove nil?) - (distinct))] - (when (or (seq repos) - (seq installation-ids)) - (util/post (str config/api "refresh_github_token") - {:installation-ids installation-ids - :repos repos} - (fn [result] - (state/set-github-installation-tokens! result) - (when ok-handler (ok-handler))) - (fn [error] - (println "Something wrong!") - (js/console.dir error) - (when error-handler (error-handler))))))) - (defn journal-file-changed? [repo-url diffs] (contains? (set (map :path diffs)) @@ -364,10 +327,11 @@ (and (or (string/includes? (str error) "401") (string/includes? (str error) "404")) (not fallback?)) - (request-app-tokens! - (fn [] - (pull repo-url (state/get-github-token repo-url) {:fallback? true})) - nil) + (p/let [token (helper/get-github-token repo-url)] + (helper/request-app-tokens! + (fn [] + (pull repo-url token {:fallback? true})) + nil)) (or (string/includes? (str error) "401") (string/includes? (str error) "404")) @@ -400,9 +364,10 @@ (let [commit-message (if (string/blank? commit-message) "Logseq auto save" commit-message)] - (p/let [commit-oid (git/commit repo-url commit-message)] + (p/let [commit-oid (git/commit repo-url commit-message) + token (helper/get-github-token repo-url)] (git-handler/set-git-status! repo-url :pushing) - (when-let [token (state/get-github-token repo-url)] + (when token (util/p-handle (git/push repo-url token force?) (fn [result] @@ -417,27 +382,27 @@ (string/includes? (str error) "404"))] (cond (and permission? (not fallback?)) - (request-app-tokens! + (helper/request-app-tokens! (fn [] (git-handler/set-git-status! repo-url :re-push) (push repo-url - {:commit-message commit-message - :fallback? true})) + {:commit-message commit-message + :fallback? true})) nil) - :else - (do - (git-handler/set-git-status! repo-url :push-failed) - (git-handler/set-git-error! repo-url error) - (cond - permission? - (show-install-error! repo-url (util/format "Failed to push to %s. " repo-url)) + :else + (do + (git-handler/set-git-status! repo-url :push-failed) + (git-handler/set-git-error! repo-url error) + (cond + permission? + (show-install-error! repo-url (util/format "Failed to push to %s. " repo-url)) - (state/online?) - (pull repo-url token {:force-pull? true}) + (state/online?) + (pull repo-url token {:force-pull? true}) - :else ; offline - nil))))))))))) + :else ; offline + nil)))))))))) (p/catch (fn [error] (println "Git push error: ") (git-handler/set-git-status! repo-url :push-failed) @@ -452,39 +417,40 @@ (defn pull-current-repo [] (when-let [repo (state/get-current-repo)] - (when-let [token (state/get-github-token repo)] - (pull repo token {:force-pull? true})))) + (p/let [token (helper/get-github-token repo)] + (when token (pull repo token {:force-pull? true}))))) (defn clone ([repo-url] (clone repo-url false)) ([repo-url fallback?] - (when-let [token (state/get-github-token repo-url)] - (util/p-handle - (do - (state/set-cloning! true) - (git/clone repo-url token)) - (fn [result] - (state/set-git-clone-repo! "") - (state/set-current-repo! repo-url) - (db/start-db-conn! (:me @state/state) repo-url) - (db/mark-repo-as-cloned repo-url)) - (fn [e] - (if (and (not fallback?) - (or (string/includes? (str e) "401") - (string/includes? (str e) "404"))) - (request-app-tokens! - (fn [] - (clone repo-url true)) - nil) - (do - (println "Clone failed, error: ") - (js/console.error e) - (state/set-cloning! false) - (git-handler/set-git-status! repo-url :clone-failed) - (git-handler/set-git-error! repo-url e) + (p/let [token (helper/get-github-token repo-url)] + (when token + (util/p-handle + (do + (state/set-cloning! true) + (git/clone repo-url token)) + (fn [result] + (state/set-git-clone-repo! "") + (state/set-current-repo! repo-url) + (db/start-db-conn! (:me @state/state) repo-url) + (db/mark-repo-as-cloned repo-url)) + (fn [e] + (if (and (not fallback?) + (or (string/includes? (str e) "401") + (string/includes? (str e) "404"))) + (helper/request-app-tokens! + (fn [] + (clone repo-url true)) + nil) + (do + (println "Clone failed, error: ") + (js/console.error e) + (state/set-cloning! false) + (git-handler/set-git-status! repo-url :clone-failed) + (git-handler/set-git-error! repo-url e) - (show-install-error! repo-url (util/format "Failed to clone %s." repo-url))))))))) + (show-install-error! repo-url (util/format "Failed to clone %s." repo-url)))))))))) (defn set-config-content! [repo path new-config] @@ -543,18 +509,18 @@ (defn periodically-pull [repo-url pull-now?] - (when-let [token (state/get-github-token repo-url)] - (when pull-now? (pull repo-url token nil)) - (js/setInterval #(pull repo-url token nil) - (* (config/git-pull-secs) 1000)))) + (p/let [token (helper/get-github-token repo-url)] + (when token + (when pull-now? (pull repo-url token nil)) + (js/setInterval #(pull repo-url token nil) + (* (config/git-pull-secs) 1000))))) (defn periodically-push-tasks [repo-url] - (let [token (state/get-github-token repo-url) - push (fn [] + (let [push (fn [] (when (and (not (false? (:git-auto-push (state/get-config repo-url)))) - ;; (not config/dev?) -) + ;; (not config/dev?) + ) (push repo-url nil)))] (js/setInterval push (* (config/git-push-secs) 1000)))) diff --git a/src/main/frontend/helper.cljs b/src/main/frontend/helper.cljs new file mode 100644 index 0000000000..61f3a33ee6 --- /dev/null +++ b/src/main/frontend/helper.cljs @@ -0,0 +1,57 @@ +(ns frontend.helper + (:require [cljs-time.format :as tf] + [cljs-time.core :as t] + [frontend.util :as util] + [frontend.state :as state] + [frontend.config :as config] + [promesa.core :as p])) + +(defn request-app-tokens! + [ok-handler error-handler] + (let [repos (:repos (state/get-me)) + installation-ids (->> (map :installation_id repos) + (remove nil?) + (distinct))] + (when (or (seq repos) + (seq installation-ids)) + (util/post (str config/api "refresh_github_token") + {:installation-ids installation-ids + :repos repos} + (fn [result] + (state/set-github-installation-tokens! result) + (when ok-handler (ok-handler))) + (fn [error] + (println "Something wrong!") + (js/console.dir error) + (when error-handler (error-handler))))))) + +(defn get-github-token* + [repo] + (when repo + (let [{:keys [token expires_at] :as token-state} + (state/get-github-token repo) + expires-at (tf/parse (tf/formatters :date-time-no-ms) expires_at) + request-time-gap (t/minutes 1) + expired? (t/after? (t/now) (t/plus expires-at request-time-gap))] + {:expired? expired? + :token token}))) + +(defn get-github-token + ([] + (get-github-token (state/get-current-repo))) + ([repo] + (js/Promise. + (fn [resolve reject] + (let [{:keys [expired? token]} (get-github-token* repo)] + (if-not expired? + (resolve token) + (request-app-tokens! + (fn [] + (let [{:keys [expired? token]} (get-github-token* repo)] + (if-not expired? + (resolve token) + (do (js/console.error "Failed to get GitHub token.") + (reject))))) + nil))))))) + + diff --git a/src/main/frontend/state.cljs b/src/main/frontend/state.cljs index df40511e54..7bbad37c1b 100644 --- a/src/main/frontend/state.cljs +++ b/src/main/frontend/state.cljs @@ -491,36 +491,36 @@ (storage/set :git/clone-repo repo)) (defn set-github-token! - [repo token] - (when token - (swap! state update-in [:me :repos] - (fn [repos] - (map (fn [r] - (if (= repo (:url r)) - (assoc r :token token) - repo)) repos))))) + [repo token-result] + (when token-result + (let [{:keys [token expires_at]} token-result] + (swap! state update-in [:me :repos] + (fn [repos] + (map (fn [r] + (if (= repo (:url r)) + (merge r {:token token :expires_at expires_at}) + repo)) repos)))))) (defn set-github-installation-tokens! [tokens] (when (seq tokens) - (let [tokens (medley/map-keys name tokens) + (let [tokens (medley/index-by :installation_id tokens) repos (get-repos)] (when (seq repos) - (let [repos (mapv (fn [{:keys [installation_id] :as r}] - (if-let [token (get tokens installation_id)] - (assoc r :token token) - r)) repos)] + (let [set-token-f + (fn [{:keys [installation_id] :as repo}] + (let [{:keys [token expires_at] :as m} (get tokens installation_id)] + (if (and token expires_at) + (merge repo {:token token :expires_at expires_at}) + (do (js/conole.log "Can't find token, expires_at key") m)))) + repos (mapv set-token-f repos)] (swap! state assoc-in [:me :repos] repos)))))) (defn get-github-token - ([] - (get-github-token (get-current-repo))) - ([repo] - (when repo - (let [repos (get-repos)] - (-> (filter #(= repo (:url %)) repos) - first - :token))))) + [repo] + (when repo + (let [repos (get-repos)] + (some #(when (= repo (:url %)) %) repos)))) (defn toggle-sidebar-open?! []