diff --git a/resources/migrations/20170226162507-issues-updated-timestamp.down.sql b/resources/migrations/20170226162507-issues-updated-timestamp.down.sql new file mode 100644 index 0000000..e69de29 diff --git a/resources/migrations/20170226162507-issues-updated-timestamp.up.sql b/resources/migrations/20170226162507-issues-updated-timestamp.up.sql new file mode 100644 index 0000000..f15e893 --- /dev/null +++ b/resources/migrations/20170226162507-issues-updated-timestamp.up.sql @@ -0,0 +1,5 @@ +ALTER TABLE "public"."issues" ADD COLUMN "updated" timestamp without time zone DEFAULT timezone('utc'::text, now()); + +ALTER TABLE "public"."issues" RENAME COLUMN "commit_id" TO "commit_sha"; + +ALTER TABLE "public"."pull_requests" RENAME COLUMN "commit_id" TO "commit_sha"; diff --git a/resources/migrations/20170226230237-activity-feed.down.sql b/resources/migrations/20170226230237-activity-feed.down.sql new file mode 100644 index 0000000..e69de29 diff --git a/resources/migrations/20170226230237-activity-feed.up.sql b/resources/migrations/20170226230237-activity-feed.up.sql new file mode 100644 index 0000000..1e6e917 --- /dev/null +++ b/resources/migrations/20170226230237-activity-feed.up.sql @@ -0,0 +1,87 @@ +create view bounties_view as +select + i.title as issue_title, + i.issue_number, + r.repo as repo_name, + u.name as user_name, + u.avatar_url as user_avatar_url, + i.payout_receipt, + i.balance, + i.updated as updated +FROM issues i, users u, repositories r +WHERE r.repo_id = i.repo_id +AND r.user_id = u.id +and contract_address is not null +and comment_id is not null +order by updated; + +create view claims_view as +select + i.title as issue_title, + i.issue_number, + r.repo as repo_name, + u.name as user_name, + u.avatar_url as user_avatar_url, + i.payout_receipt, + p.updated as updated, + i.balance, + p.state as pr_state +FROM issues i, users u, repositories r, pull_requests p +WHERE r.repo_id = i.repo_id +AND p.issue_id = i.issue_id +AND p.user_id = u.id +and i.contract_address is not null +and i.comment_id is not null +order by p.updated; + +create view activity_feed_view as +select 'open-claim' as type, +issue_title, +repo_name, +issue_number, +user_name, +user_avatar_url, +balance, +updated +from claims_view +where +pr_state=0 +and payout_receipt is null +union +select 'claim-payout' as type, +issue_title, +repo_name, +issue_number, +user_name, +user_avatar_url, +balance, +updated +from claims_view +where +pr_state=1 +and payout_receipt is not null +union +select 'new-bounty' as type, +issue_title, +repo_name, +issue_number, +user_name, +user_avatar_url, +balance, +updated +from bounties_view +where balance=0 +and payout_receipt is null +union +select 'balance-update' as type, +issue_title, +repo_name, +issue_number, +user_name, +user_avatar_url, +balance, +updated +from bounties_view +where balance>0 +and payout_receipt is null +order by updated desc; diff --git a/resources/sql/queries.sql b/resources/sql/queries.sql index 28faf64..b40c124 100644 --- a/resources/sql/queries.sql +++ b/resources/sql/queries.sql @@ -121,17 +121,19 @@ INSERT INTO issues (repo_id, issue_id, issue_number, title) FROM issues WHERE repo_id = :repo_id AND issue_id = :issue_id); --- :name update-commit-id :str) activity-items))) + + (defapi service-routes {:swagger {:ui "/swagger-ui" :spec "/swagger.json" @@ -127,10 +132,9 @@ (GET "/top-hunters" [] (log/debug "/top-hunters") (ok (top-hunters))) - (context "/bounties" [] - (GET "/all" [] - (log/debug "/bounties/all") - (ok (bounties-db/list-all-bounties)))) + (GET "/activity-feed" [] + (log/debug "/activity-feed") + (ok (activity-feed))) (context "/user" [] (GET "/" [] :auth-rules authenticated? diff --git a/src/clj/commiteth/routes/webhooks.clj b/src/clj/commiteth/routes/webhooks.clj index daaec7e..eb5690f 100644 --- a/src/clj/commiteth/routes/webhooks.clj +++ b/src/clj/commiteth/routes/webhooks.clj @@ -30,9 +30,9 @@ (= "labeled" action) (= bounties/label-name (get-in issue [:label :name])))) -(defn find-commit-id +(defn find-commit-sha [user repo issue-number event-types] - (log/debug "find-commit-id" user repo issue-number event-types) + (log/debug "find-commit-sha" user repo issue-number event-types) (some identity (map #(-> (github/get-issue-events user repo issue-number) (find-issue-event % user) @@ -55,8 +55,8 @@ [{{{owner :login} :owner repo :name} :repository {issue-id :id issue-number :number} :issue}] (log/debug "handle-issue-closed" owner repo issue-number issue-id) - (when-let [commit-id (find-commit-id owner repo issue-number ["referenced" "closed"])] - (log/debug (format "Issue %s/%s/%s closed with commit %s" owner repo issue-number commit-id)) + (when-let [commit-sha (find-commit-sha owner repo issue-number ["referenced" "closed"])] + (log/debug (format "Issue %s/%s/%s closed with commit %s" owner repo issue-number commit-sha)) (log/info "NOT considering event as bounty winner") ;; TODO: disabled for now since the system is meant to be used ;; exclusively via pull requests. issue closed event without a PR @@ -65,7 +65,7 @@ ;; maintainer (could be that the bounty hunter had write access ;; to master, but that scenario should be very rare and better ;; not to support it) - #_(issues/close commit-id issue-id))) + #_(issues/close commit-sha issue-id))) (def ^:const keywords [#"(?i)close:?\s+#(\d+)" @@ -148,19 +148,19 @@ (log/info "PR with reference to bounty issue" bounty-issue-number "opened") (pull-requests/save (merge pr-data {:state :opened - :commit_id head-sha}))) + :commit-sha head-sha}))) :closed (if merged? (do (log/info "PR with reference to bounty issue" bounty-issue-number "merged") (pull-requests/save (merge pr-data {:state :merged - :commit_id head-sha})) - (issues/update-commit-id head-sha (:id issue))) + :commit-sha head-sha})) + (issues/update-commit-sha (:id issue) head-sha)) (do (log/info "PR with reference to bounty issue" bounty-issue-number "closed with no merge") (pull-requests/save (merge pr-data {:state :closed - :commit_id head-sha})))))))) + :commit-sha head-sha})))))))) (defn handle-issue diff --git a/src/cljs/commiteth/activity.cljs b/src/cljs/commiteth/activity.cljs index 9e55ff6..056878b 100644 --- a/src/cljs/commiteth/activity.cljs +++ b/src/cljs/commiteth/activity.cljs @@ -1,12 +1,15 @@ (ns commiteth.activity - (:require [re-frame.core :as rf])) + (:require [re-frame.core :as rf] + [reagent.core :as r])) -(defn activity-item [{{image-url :avatar-url - display-name :display-name} :user - timestamp :timestamp - description :description} item] +(defn activity-item [{image-url :user_avatar_url + display-name :user_name + timestamp :updated + balance :balance + issue-title :issue_title + item-type :type} item] [:div.item.activity-item [:div.ui.mini.circular.image @@ -14,13 +17,16 @@ [:div.content [:div.header display-name] [:div.description - [:p description]] - [:div.time timestamp]]]) + [:p item-type] + [:p issue-title]] + #_[:div.time timestamp]]]) (defn activity-page [] (let [activity-items (rf/subscribe [:activity-feed])] (fn [] [:div.ui.container - (into [:div.ui.items] - (for [item @activity-items] - [activity-item item]))]))) + (if (empty? @activity-items) + [:div.ui.text "No data"] + (into [:div.ui.items] + (for [item @activity-items] + [activity-item item])))]))) diff --git a/src/cljs/commiteth/core.cljs b/src/cljs/commiteth/core.cljs index 7563958..760819c 100644 --- a/src/cljs/commiteth/core.cljs +++ b/src/cljs/commiteth/core.cljs @@ -112,16 +112,18 @@ (defn top-hunters [] (let [top-hunters (rf/subscribe [:top-hunters])] (fn [] - (into [:div.ui.items.top-hunters] - (map-indexed (fn [idx hunter] - [:div.item - [:div.leader-ordinal (str (+ 1 idx))] - [:div.ui..mini.circular.image - [:img {:src (:avatar-url hunter)}]] - [:div.content - [:div.header (:display-name hunter)] - [:div.description (str "ETH " (:total-eth hunter))]]]) - @top-hunters))))) + (if (empty? @top-hunters) + [:div.ui.text "No data"] + (into [:div.ui.items.top-hunters] + (map-indexed (fn [idx hunter] + [:div.item + [:div.leader-ordinal (str (+ 1 idx))] + [:div.ui..mini.circular.image + [:img {:src (:avatar-url hunter)}]] + [:div.content + [:div.header (:display-name hunter)] + [:div.description (str "ETH " (:total-eth hunter))]]]) + @top-hunters)))))) (defn page [] (fn [] @@ -174,6 +176,7 @@ (reset! active-user nil))) (defn load-data [] + (rf/dispatch [:load-activity-feed]) (rf/dispatch [:load-top-hunters]) (load-user)) diff --git a/src/cljs/commiteth/db.cljs b/src/cljs/commiteth/db.cljs index e1ca519..50eab52 100644 --- a/src/cljs/commiteth/db.cljs +++ b/src/cljs/commiteth/db.cljs @@ -6,19 +6,23 @@ :repos-loading? false :repos {} :owner-bounties {} - :top-hunters [{:avatar-url "https://randomuser.me/api/portraits/men/4.jpg" - :display-name "Place Holder" - :total-eth "11 000.00"} - {:avatar-url "https://randomuser.me/api/portraits/men/6.jpg" - :display-name "Dummy User" - :total-eth "8 400.00"}] - :activity-feed [{:type :submit-claim - :user {:display-name "Dummy User" - :avatar-url "https://randomuser.me/api/portraits/men/6.jpg"} - :description "Submitted a claim for X" - :timestamp "1 day ago"} - {:type :submit-claim - :user {:display-name "Place Holder" - :avatar-url "https://randomuser.me/api/portraits/men/4.jpg"} - :description "Posted ETH 15 bounty to Y" - :timestamp "2 days ago"}]}) + :top-hunters [] + :activity-feed [] #_[{:type :create-bounty + :user {:display-name "Dummy User" + :avatar-url "https://randomuser.me/api/portraits/men/6.jpg"} + :issue-title "Feature X" + :issue-url "https://github.com/foo/bar/issues/2" + :timestamp "1 day ago"} + {:type :submit-claim + :user {:display-name "Place Holder" + :avatar-url "https://randomuser.me/api/portraits/men/4.jpg"} + :balance-eth "15" + :timestamp "2 days ago"} + {:type :balance-update + :user {:display-name "Place Holder" + :avatar-url "https://randomuser.me/api/portraits/men/4.jpg"} + + :issue-title "Feature Y" + :issue-url "https://github.com/foo/bar/issues/1" + :balance-eth "15" + :timestamp "2 days ago"}]}) diff --git a/src/cljs/commiteth/handlers.cljs b/src/cljs/commiteth/handlers.cljs index 0a5ab56..ba59f7d 100644 --- a/src/cljs/commiteth/handlers.cljs +++ b/src/cljs/commiteth/handlers.cljs @@ -94,6 +94,20 @@ (fn [db [_ top-hunters]] (assoc db :top-hunters top-hunters))) +(reg-event-fx + :load-activity-feed + (fn [{:keys [db]} [_]] + {:db db + :http {:method GET + :url "/api/activity-feed" + :on-success #(dispatch [:set-activity-feed %])}})) + + +(reg-event-db + :set-activity-feed + (fn [db [_ activity-feed]] + (assoc db :activity-feed activity-feed))) + (reg-event-fx :load-owner-bounties