Rewrite Github comment PNG functionality
* removed old swing JEditorPane based html to png rendering due to it's lack of support for modern css * new implementation uses wkhtmltoimage (on prod server via wrapper script using xvfb) * no longer generating image on every GET request for QR, but rather generating image when a bounty is cretaed or contract balance changes * images stored to DB * comment image design updated according to UI spec
This commit is contained in:
parent
bb5d492631
commit
9b972625e0
|
@ -3,4 +3,5 @@
|
|||
:port 3000
|
||||
:nrepl-port 7000
|
||||
:server-address "https://commiteth.com"
|
||||
:html2png-command "/home/commiteth/html2png.sh"
|
||||
}
|
||||
|
|
|
@ -39,7 +39,8 @@
|
|||
[bk/ring-gzip "0.2.1"]
|
||||
[crypto-random "1.2.0"]
|
||||
[crypto-equality "1.0.0"]
|
||||
[cheshire "5.7.0"]]
|
||||
[cheshire "5.7.0"]
|
||||
[mpg "1.3.0"]]
|
||||
|
||||
:min-lein-version "2.0.0"
|
||||
:source-paths ["src/clj" "src/cljc"]
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
-- this column was never used
|
||||
ALTER TABLE "repositories" DROP COLUMN IF EXISTS "updated";
|
||||
|
||||
-- needde for foreign key
|
||||
ALTER TABLE "issues" ADD UNIQUE ("issue_id");
|
||||
|
||||
-- table for github PNG comment images
|
||||
CREATE TABLE issue_comment (
|
||||
id SERIAL PRIMARY KEY,
|
||||
issue_id INTEGER REFERENCES issues (issue_id),
|
||||
png_data bytea);
|
|
@ -325,6 +325,8 @@ WHERE r.user_id = :owner_id
|
|||
FROM pull_requests
|
||||
WHERE issue_number = i.issue_number);
|
||||
|
||||
-- TODO: misleading name. this is used when updating bounty balances. maybe we should exclude at least bounties that have been paid?
|
||||
|
||||
-- :name wallets-list :? :*
|
||||
-- :doc lists all contract ids
|
||||
SELECT
|
||||
|
@ -332,15 +334,19 @@ SELECT
|
|||
r.login AS login,
|
||||
r.repo AS repo,
|
||||
i.comment_id AS comment_id,
|
||||
i.issue_number AS issue_number
|
||||
i.issue_number AS issue_number,
|
||||
i.issue_id AS issue_id,
|
||||
i.balance AS balance
|
||||
FROM issues i
|
||||
INNER JOIN repositories r ON r.repo_id = i.repo_id
|
||||
WHERE contract_address IS NOT NULL;
|
||||
|
||||
-- :name get-bounty-address :? :1
|
||||
-- :name get-bounty :? :1
|
||||
SELECT
|
||||
i.contract_address AS contract_address,
|
||||
i.issue_id AS issue_id,
|
||||
i.issue_number AS issue_number,
|
||||
i.balance AS balance,
|
||||
r.login AS login,
|
||||
r.repo AS repo
|
||||
FROM issues i
|
||||
|
@ -359,3 +365,18 @@ WHERE contract_address = :contract_address;
|
|||
UPDATE issues
|
||||
SET balance = :balance
|
||||
WHERE contract_address = :contract_address;
|
||||
|
||||
|
||||
|
||||
-- :name save-issue-comment-image! :<! :1
|
||||
INSERT INTO issue_comment (issue_id, png_data)
|
||||
VALUES (:issue_id, :png_data)
|
||||
ON CONFLICT (issue_id) DO UPDATE
|
||||
SET png_data = :png_data
|
||||
RETURNING id;
|
||||
|
||||
|
||||
-- :name get-issue-comment-image :? :1
|
||||
SELECT png_data
|
||||
FROM issue_comment
|
||||
WHERE issue_id = :issue_id;
|
||||
|
|
|
@ -1,10 +1,73 @@
|
|||
<!-- This html file is converted into png image so please keep it simple.
|
||||
HTMLEditorKit doesn't support 'float' and 'display' css attributes.-->
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<div style="font-family: sans-serif; font-size: 21px;">
|
||||
<br/>
|
||||
commiteth<br/>
|
||||
<span style="font-size: 27px;">{{balance}} ETH</span><br/><br>
|
||||
{{address}}<br/>
|
||||
<span style="color: #5FC48D;">{{issue-url}}</span>
|
||||
</div>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css?family=Roboto:300&subset=latin');
|
||||
|
||||
.github-comment {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
border: #e7e7e7 solid 0.1em!important;
|
||||
border-radius: 8px!important;
|
||||
margin: 0px;
|
||||
padding: 1em;
|
||||
width: 1336px;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.commiteth-logo {
|
||||
position: fixed;
|
||||
top: 32px;
|
||||
left: 32px;
|
||||
}
|
||||
|
||||
.comment-issue-url {
|
||||
font-size: 1.1em;
|
||||
color: #a8aab1;
|
||||
position: fixed;
|
||||
top: 155px;
|
||||
left: 32px;
|
||||
}
|
||||
.comment-eth {
|
||||
color: #a8aab1;
|
||||
font-size: 3em;
|
||||
position: fixed;
|
||||
top: 196px;
|
||||
left: 32px;
|
||||
}
|
||||
.comment-balance {
|
||||
color: #343434;
|
||||
position: fixed;
|
||||
top: 196px;
|
||||
left: 135px;
|
||||
}
|
||||
|
||||
.qr-image {
|
||||
position: fixed;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
top: 24px;
|
||||
left: 1072px;
|
||||
border: none;
|
||||
background-color: red;
|
||||
}
|
||||
.qr-image>img {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
background-color: yellow;
|
||||
}
|
||||
|
||||
</style>
|
||||
{% style "/css/style.css" %}
|
||||
|
||||
<div class="github-comment">
|
||||
<div class="commiteth-logo">
|
||||
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAABT1JREFUaAXdWmtMHFUUPmcWZEVRYrDSyqNYozb+sSkxgsvysLawJfpDa1ob44/+Mjb+MDH6h/hKjMbExBKNMekPTdQmjYkvFpXIcxtNRekfY0RSnr4oMUDpspSdOZ47eLcg9+7OsrvDyE3g7px7znfPN3PuuY8ZgC1SMFs89g4OFl6YWawlojK0YLsFVMrgpYB0Vbb6EDhEjA4wDL78k1PNtSMSOyMiu77qK79sYisBtSJQExH4JXDua4z6DNo33tLwregrbyMdlofP7EKIv7gUhyMAliEwaCNAGdlQoUnwBkPUCJi0iJR/HdkBcbMNIH7MIsrPyI8sGHM47ZEwjolUdvaFrLj5EY+B66TxZtccyqPSBzss5IWurgj3PWta8LmXSKz4ii9Ln5MO9p09o35zceIkE3hUGjiuETkHwAIiLLBN1oYQg3LWwmEEbJ8MBT+R/iQNrXh0/F1WdEYCccgA7AIDuyzw/VhzoGbuNKIpO8p1rX0iZeH+40y+PaUDiJ1885+fbGn4PqVuDhWURCo6IwEis5tDKklmwl85jz8u83gOfXQEvY7Izp6hYjM69zMHdakOgY2+9BVef2Sscc+sTsdt+bqsFV+ceyo5CXz7WKj+oJdIiJu25oncHokURefNMQ6pG5R3FLG7piW4381BrPRDIVzzRBYvmk/qScCUH/CwF0kIXgkiYs6wCJ5WkLVFaBjHR0LBC7r2zZYniFhLUwFeI9+ocogntZ8mDtR9pmrziixBBCy6X+cUovEqipnawyVBhDdCSiJMYP4Wf90pD3OwXbOJ3NYzWMJXd6mc5bVNf28jxlVtXpLZRJZil+4We0iVYxxW3Sq512T2opGzlXYW5w3gQKZOV31zpjJ+2bzDAPJlimWiYRl5MDyxr+78aiybCGelbbxJURbDZ/2mbHAgFAcSf00vvLccW35YqGdnKWyCxUBl4d4v/OA/OhK6Z15g26FFFm0TF6pSUlI4o5I7kU1PX3qJdyI2CSf6aekQtMZg6XVpYxPhzKQkwoNm9ofq6mWpnH5ND6Vvk47FFXybCB8kaAIrHdDN1V15IgDKpQezK+Y4T7InSeU8fpxKI7P2K/grRAyc1gHOzETFHLOhQsX5bZxITm/IOKURdvih4BmpZmctDiwtEcs0bmblP6RBOvVUbe0i6z/iWvo1EP7kUzt1Maw6bhhUNzqTjt537zhrir+cFTu0CvzXnAXNopDIaspZ71kEtokMN1aLueKcEpewvqGHkh4bKe1cFtpERJ/2mZSycyo6Hxs4rGzykDBBRBys6fzi8HqOpxrlolJn47Y8QcQoKIvwOFHPJwR3VnQOPOi2c+n0lyAy1lgV4+wl3jcoC4HVfmu4X7kVVhq4LEwQEf1eXeR7i9ddfyt9ICiLAZ06RJkvxZX4GQrXEPklELjIO8I3tZhETd+F+0+8QLTGTqvvYsO6AbxljkzFUSgaeYc4xLTLd14ENMej82crO3vt93cu3nhtV+ueiNTcEq8VEmQ6et/n34/J6xT1OR44Yi7q8hdeO7QD9s66efqifSLC6YxevdmsMcrH5AvIM6p9Kf9p1nWymWvdEpYb/n31ZuCJyebgp9ImKRGpJF6G8knLK4zvsWyFR6cO1n8o/HTk2ESo/jWfDx8Qp46SnDdqapN+OCIilMebgx2Q59vNZN5JltEksBs17z6rZD+OiQiDyf2B3ydD9U/wBxO7DcQP+D3R2tiXqC7VPJCGZFeOxohU/m/tpY9qMiKymljiMycTyvlLIf68ydrOK/+b3PrMabUv/+vf/wB8Edrv6oR/RwAAAABJRU5ErkJggg=="/>
|
||||
</div>
|
||||
<div class="comment-issue-url">{{issue-url}}</div>
|
||||
<div class="comment-eth">ETH<div class="comment-balance">{{balance}}</div></div>
|
||||
<div class="qr-image">
|
||||
<img src="data:image/png;base64,{{qr-image}}"/>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
(:require [commiteth.db.issues :as issues]
|
||||
[commiteth.db.users :as users]
|
||||
[commiteth.db.repositories :as repos]
|
||||
[commiteth.db.comment-images :as comment-images]
|
||||
[commiteth.eth.core :as eth]
|
||||
[commiteth.github.core :as github]
|
||||
[commiteth.eth.core :as eth]
|
||||
[commiteth.util.png-rendering :as png-rendering]
|
||||
[clojure.tools.logging :as log]))
|
||||
|
||||
|
||||
|
@ -39,3 +41,11 @@
|
|||
(count bounty-issues) " existing issues")
|
||||
(doall
|
||||
(map (partial add-bounty-for-issue repo repo-id login) bounty-issues))))
|
||||
|
||||
(defn update-bounty-comment-image [issue-id issue-url contract-address balance]
|
||||
(let [png-data (png-rendering/gen-comment-image
|
||||
contract-address
|
||||
balance
|
||||
issue-url)]
|
||||
(when png-data
|
||||
(comment-images/save-image! issue-id png-data))))
|
||||
|
|
|
@ -54,10 +54,11 @@
|
|||
(jdbc/with-db-connection [con-db *db*]
|
||||
(db/update-payout-receipt con-db {:issue_id issue-id :payout_receipt payout-receipt})))
|
||||
|
||||
(defn get-bounty-address
|
||||
(defn get-bounty
|
||||
[user repo issue-number]
|
||||
(jdbc/with-db-connection [con-db *db*]
|
||||
(db/get-bounty-address con-db {:login user :repo repo :issue_number issue-number})))
|
||||
(db/get-bounty con-db {:login user :repo repo :issue_number issue-number})))
|
||||
|
||||
|
||||
(defn list-wallets
|
||||
[]
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
(ns commiteth.db.comment-images
|
||||
(:require [commiteth.db.core :refer [*db*] :as db]
|
||||
[clojure.java.jdbc :as jdbc]
|
||||
[clojure.tools.logging :as log]))
|
||||
|
||||
(defn save-image!
|
||||
[issue-id png-data]
|
||||
(jdbc/with-db-connection [con-db *db*]
|
||||
(db/save-issue-comment-image! con-db
|
||||
{:issue_id issue-id
|
||||
:png_data png-data})))
|
||||
|
||||
(defn get-image-data
|
||||
[issue-id]
|
||||
(jdbc/with-db-connection [con-db *db*]
|
||||
(db/get-issue-comment-image con-db {:issue_id issue-id})))
|
|
@ -5,7 +5,8 @@
|
|||
[conman.core :as conman]
|
||||
[commiteth.config :refer [env]]
|
||||
[mount.core :refer [defstate]]
|
||||
[migratus.core :as migratus])
|
||||
[migratus.core :as migratus]
|
||||
[mpg.core :as mpg])
|
||||
(:import org.postgresql.util.PGobject
|
||||
java.sql.Array
|
||||
clojure.lang.IPersistentMap
|
||||
|
@ -16,6 +17,7 @@
|
|||
Timestamp
|
||||
PreparedStatement]))
|
||||
|
||||
(mpg/patch)
|
||||
|
||||
(defn start []
|
||||
(let [db (env :jdbc-database-url)
|
||||
|
|
|
@ -137,7 +137,9 @@
|
|||
(let [image-url (md-image "QR Code" (get-qr-url user repo issue-number))
|
||||
balance (str balance " ETH")
|
||||
site-url (md-url (server-address) (server-address))]
|
||||
(format "Current balance: %s\nContract address: %s\n%s\n%s"
|
||||
(format (str "Current balance: %s\n"
|
||||
"Contract address: %s\n"
|
||||
"%s\n%s")
|
||||
balance contract-address image-url site-url)))
|
||||
|
||||
(defn post-comment
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
[ring.middleware.anti-forgery :refer [*anti-forgery-token*]]
|
||||
[commiteth.github.core :as github]))
|
||||
|
||||
(declare ^:dynamic *identity*)
|
||||
(declare ^:dynamic *app-context*)
|
||||
(parser/set-resource-path! (clojure.java.io/resource "templates"))
|
||||
(parser/add-tag! :csrf-field (fn [_ _] (anti-forgery-field)))
|
||||
(filters/add-filter! :markdown (fn [content] [:safe (md-to-html-string content)]))
|
||||
|
@ -23,8 +21,7 @@
|
|||
(assoc params
|
||||
:authorize-url (github/authorize-url)
|
||||
:page template
|
||||
:csrf-token *anti-forgery-token*
|
||||
:servlet-context *app-context*)))
|
||||
:csrf-token *anti-forgery-token*)))
|
||||
"text/html; charset=utf-8"))
|
||||
|
||||
(defn error-page
|
||||
|
|
|
@ -43,16 +43,16 @@
|
|||
|
||||
(defn wrap-csrf [handler]
|
||||
(wrap-anti-forgery
|
||||
handler
|
||||
{:error-response
|
||||
(error-page
|
||||
{:status 403
|
||||
:title "Invalid anti-forgery token"})}))
|
||||
handler
|
||||
{:error-response
|
||||
(error-page
|
||||
{:status 403
|
||||
:title "Invalid anti-forgery token"})}))
|
||||
|
||||
(defn wrap-formats [handler]
|
||||
(let [wrapped (wrap-restful-format
|
||||
handler
|
||||
{:formats [:json-kw :transit-json :transit-msgpack]})]
|
||||
handler
|
||||
{:formats [:json-kw :transit-json :transit-msgpack]})]
|
||||
(fn [request]
|
||||
;; disable wrap-formats for websockets
|
||||
;; since they're not compatible with this middleware
|
||||
|
@ -60,8 +60,8 @@
|
|||
|
||||
(defn on-error [request response]
|
||||
(error-page
|
||||
{:status 403
|
||||
:title (str "Access to " (:uri request) " is not authorized")}))
|
||||
{:status 403
|
||||
:title (str "Access to " (:uri request) " is not authorized")}))
|
||||
|
||||
(defn wrap-restricted [handler]
|
||||
(restrict handler {:handler authenticated?
|
||||
|
@ -75,20 +75,20 @@
|
|||
(defn wrap-auth [handler]
|
||||
(let [backend (session-backend)]
|
||||
(-> handler
|
||||
wrap-identity
|
||||
(wrap-authentication backend)
|
||||
(wrap-authorization backend))))
|
||||
wrap-identity
|
||||
(wrap-authentication backend)
|
||||
(wrap-authorization backend))))
|
||||
|
||||
(defn wrap-base [handler]
|
||||
(-> ((:middleware defaults) handler)
|
||||
wrap-auth
|
||||
;; wrap-flash
|
||||
(wrap-session {:timeout (* 60 60 6)
|
||||
:cookie-attrs {:http-only true}})
|
||||
(wrap-defaults
|
||||
(-> site-defaults
|
||||
(assoc-in [:security :anti-forgery] false)
|
||||
(dissoc :session)))
|
||||
;; wrap-context
|
||||
wrap-gzip
|
||||
wrap-internal-error))
|
||||
wrap-auth
|
||||
wrap-flash
|
||||
(wrap-session {:timeout (* 60 60 6)
|
||||
:cookie-attrs {:http-only true}})
|
||||
(wrap-defaults
|
||||
(-> site-defaults
|
||||
(assoc-in [:security :anti-forgery] false)
|
||||
(dissoc :session)))
|
||||
wrap-context
|
||||
wrap-gzip
|
||||
wrap-internal-error))
|
||||
|
|
|
@ -2,56 +2,34 @@
|
|||
(:require [ring.util.http-response :refer :all]
|
||||
[compojure.api.sweet :refer :all]
|
||||
[commiteth.db.bounties :as bounties]
|
||||
[commiteth.layout :as layout]
|
||||
[commiteth.util.images :refer :all]
|
||||
[clj.qrgen :as qr]
|
||||
[commiteth.eth.core :as eth]
|
||||
[commiteth.db.comment-images :as comment-images]
|
||||
[commiteth.github.core :as github]
|
||||
[clojure.tools.logging :as log])
|
||||
(:import [javax.imageio ImageIO]
|
||||
[java.io InputStream]))
|
||||
|
||||
(defn ^InputStream generate-qr-code
|
||||
[address]
|
||||
(qr/as-input-stream
|
||||
(qr/from (str "ethereum:" address) :size [256 256])))
|
||||
|
||||
(defn generate-html
|
||||
[address balance issue-url]
|
||||
(:body (layout/render "bounty.html" {:balance balance
|
||||
:address address
|
||||
:issue-url issue-url})))
|
||||
|
||||
(defn generate-image
|
||||
[address balance issue-url width height]
|
||||
(let [qr-code-image (ImageIO/read (generate-qr-code address))
|
||||
comment-image (html->image
|
||||
(generate-html address balance issue-url) width height)]
|
||||
(combine-images qr-code-image comment-image)))
|
||||
[clojure.tools.logging :as log]
|
||||
[clojure.java.io :as io])
|
||||
(:import [java.io ByteArrayInputStream]))
|
||||
|
||||
|
||||
(defapi qr-routes
|
||||
(context "/qr" []
|
||||
(GET "/:owner/:repo/bounty/:issue{[0-9]{1,9}}/:hash/qr.png" [owner repo issue hash]
|
||||
(log/debug "qr PNG GET" owner repo issue hash (bounties/get-bounty-address owner
|
||||
repo
|
||||
(Integer/parseInt issue)))
|
||||
(log/debug "qr PNG GET" owner repo issue hash)
|
||||
(when-let [{address :contract_address
|
||||
login :login
|
||||
repo :repo
|
||||
issue-number :issue_number}
|
||||
(bounties/get-bounty-address owner
|
||||
repo
|
||||
(Integer/parseInt issue))]
|
||||
(when address
|
||||
(let [balance (eth/get-balance-eth address 8)]
|
||||
(log/debug "address:" address "balance:" balance)
|
||||
(if (and address
|
||||
(= hash (github/github-comment-hash owner repo issue)))
|
||||
(let [issue-url (str login "/" repo "/issues/" issue-number)
|
||||
image-url (generate-image address balance issue-url 768 256)
|
||||
response (assoc-in (ok image-url)
|
||||
[:headers "cache-control"] "no-cache")]
|
||||
(log/debug "balance:" address "response" response)
|
||||
response)
|
||||
(bad-request))))))))
|
||||
issue-id :issue_id
|
||||
balance :balance}
|
||||
(bounties/get-bounty owner
|
||||
repo
|
||||
(Integer/parseInt issue))]
|
||||
(log/debug "address:" address)
|
||||
(if (and address
|
||||
(= hash (github/github-comment-hash owner repo issue)))
|
||||
(let [{png-data :png_data} (comment-images/get-image-data issue-id)
|
||||
image-byte-stream (ByteArrayInputStream. png-data)
|
||||
response {:status 200
|
||||
:content-type "image/png"
|
||||
:headers {"cache-control" "no-cache"}
|
||||
:body image-byte-stream}]
|
||||
(log/debug "response" response)
|
||||
response)
|
||||
(bad-request))))))
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
[commiteth.eth.multisig-wallet :as wallet]
|
||||
[commiteth.github.core :as github]
|
||||
[commiteth.db.issues :as issues]
|
||||
[commiteth.db.bounties :as bounties]
|
||||
[commiteth.db.bounties :as db-bounties]
|
||||
[commiteth.bounties :as bounties]
|
||||
[clojure.tools.logging :as log]
|
||||
[mount.core :as mount])
|
||||
(:import [sun.misc ThreadGroupUtils]
|
||||
|
@ -20,63 +21,75 @@
|
|||
(log/info "transaction receipt for issue #" issue-id ": " receipt)
|
||||
(when-let [contract-address (:contractAddress receipt)]
|
||||
(let [issue (issues/update-contract-address issue-id contract-address)
|
||||
{user :login
|
||||
{owner :login
|
||||
repo :repo
|
||||
issue-number :issue_number} issue
|
||||
balance (eth/get-balance-eth contract-address 4)
|
||||
{comment-id :id} (github/post-comment user
|
||||
repo
|
||||
issue-number
|
||||
contract-address
|
||||
balance)]
|
||||
(issues/update-comment-id issue-id comment-id))))))
|
||||
issue-url (str owner "/" repo "/issues/" (str issue-number))]
|
||||
(bounties/update-bounty-comment-image issue-id
|
||||
issue-url
|
||||
contract-address
|
||||
balance)
|
||||
(->> (github/post-comment owner
|
||||
repo
|
||||
issue-number
|
||||
contract-address
|
||||
balance)
|
||||
:id
|
||||
(issues/update-comment-id issue-id)))))))
|
||||
|
||||
(defn self-sign-bounty
|
||||
"Walks through all issues eligible for bounty payout and signs corresponding transaction"
|
||||
[]
|
||||
(doseq [{contract-address :contract_address
|
||||
issue-id :issue_id
|
||||
payout-address :payout_address} (bounties/pending-bounties-list)
|
||||
payout-address :payout_address} (db-bounties/pending-bounties-list)
|
||||
:let [value (eth/get-balance-hex contract-address)]]
|
||||
(->>
|
||||
(wallet/execute contract-address payout-address value)
|
||||
(bounties/update-execute-hash issue-id))))
|
||||
(db-bounties/update-execute-hash issue-id))))
|
||||
|
||||
(defn update-confirm-hash
|
||||
"Gets transaction receipt for each pending payout and updates confirm_hash"
|
||||
[]
|
||||
(doseq [{issue-id :issue_id
|
||||
execute-hash :execute_hash} (bounties/pending-payouts-list)]
|
||||
execute-hash :execute_hash} (db-bounties/pending-payouts-list)]
|
||||
(log/debug "pending payout:" execute-hash)
|
||||
(when-let [receipt (eth/get-transaction-receipt execute-hash)]
|
||||
(log/info "execution receipt for issue #" issue-id ": " receipt)
|
||||
(when-let [confirm-hash (wallet/find-confirmation-hash receipt)]
|
||||
(bounties/update-confirm-hash issue-id confirm-hash)))))
|
||||
(db-bounties/update-confirm-hash issue-id confirm-hash)))))
|
||||
|
||||
(defn update-payout-hash
|
||||
"Gets transaction receipt for each confirmed payout and updates payout_hash"
|
||||
[]
|
||||
(doseq [{issue-id :issue_id
|
||||
payout-hash :payout_hash} (bounties/confirmed-payouts-list)]
|
||||
payout-hash :payout_hash} (db-bounties/confirmed-payouts-list)]
|
||||
(log/debug "confirmed payout:" payout-hash)
|
||||
(when-let [receipt (eth/get-transaction-receipt payout-hash)]
|
||||
(log/info "payout receipt for issue #" issue-id ": " receipt)
|
||||
(bounties/update-payout-receipt issue-id receipt))))
|
||||
(db-bounties/update-payout-receipt issue-id receipt))))
|
||||
|
||||
(defn update-balance
|
||||
[]
|
||||
(doseq [{contract-address :contract_address
|
||||
login :login
|
||||
owner :login
|
||||
repo :repo
|
||||
comment-id :comment_id
|
||||
issue-number :issue_number} (bounties/list-wallets)]
|
||||
issue-id :issue_id
|
||||
old-balance :balance
|
||||
issue-number :issue_number} (db-bounties/list-wallets)]
|
||||
(when comment-id
|
||||
(let [{old-balance :balance} (issues/get-balance contract-address)
|
||||
current-balance-hex (eth/get-balance-hex contract-address)
|
||||
current-balance-eth (eth/hex->eth current-balance-hex 8)]
|
||||
(let [current-balance-hex (eth/get-balance-hex contract-address)
|
||||
current-balance-eth (eth/hex->eth current-balance-hex 8)
|
||||
issue-url (str owner "/" repo "/issues/" (str issue-number))]
|
||||
(when-not (= old-balance current-balance-hex)
|
||||
(issues/update-balance contract-address current-balance-hex)
|
||||
(github/update-comment login
|
||||
(bounties/update-bounty-comment-image issue-id
|
||||
issue-url
|
||||
contract-address
|
||||
current-balance-eth)
|
||||
(github/update-comment owner
|
||||
repo
|
||||
comment-id
|
||||
issue-number
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
(ns commiteth.util.images
|
||||
(:import [java.awt GraphicsEnvironment RenderingHints]
|
||||
[java.awt.image BufferedImage]
|
||||
[javax.swing JEditorPane]
|
||||
[java.io ByteArrayInputStream ByteArrayOutputStream]
|
||||
[javax.imageio ImageIO]))
|
||||
|
||||
(defn ^BufferedImage create-image
|
||||
[width height]
|
||||
(new BufferedImage width height BufferedImage/TYPE_INT_ARGB))
|
||||
|
||||
(defn html->image
|
||||
[html width height]
|
||||
(let [image (create-image width height)
|
||||
graphics (.createGraphics image)
|
||||
jep (new JEditorPane "text/html" html)]
|
||||
(.setRenderingHint graphics
|
||||
(RenderingHints/KEY_TEXT_ANTIALIASING)
|
||||
(RenderingHints/VALUE_TEXT_ANTIALIAS_GASP))
|
||||
(. jep (setSize width height))
|
||||
(. jep (print graphics))
|
||||
image))
|
||||
|
||||
(defn combine-images
|
||||
[^BufferedImage image1
|
||||
^BufferedImage image2]
|
||||
(let [left-width (.getWidth image1)
|
||||
width (+ left-width (.getWidth image2))
|
||||
height (max (.getHeight image1) (.getHeight image2))
|
||||
combined (create-image width height)
|
||||
graphics (.createGraphics combined)]
|
||||
(.drawImage graphics image1 nil 0 0)
|
||||
(.drawImage graphics image2 nil left-width 0)
|
||||
(let [output-stream (ByteArrayOutputStream. 2048)]
|
||||
(ImageIO/write combined "png" output-stream)
|
||||
(ByteArrayInputStream. (.toByteArray output-stream)))))
|
|
@ -0,0 +1,48 @@
|
|||
(ns commiteth.util.png-rendering
|
||||
(:require [commiteth.layout :refer [render]]
|
||||
[commiteth.config :refer [env]]
|
||||
[commiteth.db.comment-images :as db]
|
||||
[clj.qrgen :as qr]
|
||||
[clojure.data.codec.base64 :as b64]
|
||||
[clojure.tools.logging :as log]
|
||||
[clojure.java.io :as io])
|
||||
(:use [clojure.java.shell :only [sh]])
|
||||
(:import [java.io InputStream]))
|
||||
|
||||
|
||||
(defn image->base64 [input-stream]
|
||||
(let [baos (java.io.ByteArrayOutputStream.)]
|
||||
(b64/encoding-transfer input-stream baos)
|
||||
(.toByteArray baos)))
|
||||
|
||||
|
||||
(defn ^InputStream generate-qr-image
|
||||
[address]
|
||||
(qr/as-input-stream
|
||||
(qr/from (str "ethereum:" address)
|
||||
:size [255 255])))
|
||||
|
||||
|
||||
(defn gen-comment-image [address balance issue-url]
|
||||
(let [qr-image (-> (image->base64 (generate-qr-image address))
|
||||
(String. "ISO-8859-1"))
|
||||
html (:body (render "bounty.html"
|
||||
{:qr-image qr-image
|
||||
:balance balance
|
||||
:address address
|
||||
:issue-url issue-url}))
|
||||
command (env :html2png-command "wkhtmltoimage")
|
||||
{out :out err :err exit :exit}
|
||||
(sh command "-f" "png" "--quality" "80" "--width" "1336" "-" "-"
|
||||
:out-enc :bytes :in html)]
|
||||
(if (= 0 exit)
|
||||
out
|
||||
(do (log/error "Failed to generate PNG file" err)
|
||||
nil))))
|
||||
|
||||
|
||||
(defn export-comment-image
|
||||
"Retrieve image PNG from DB and write to file"
|
||||
[issue-id filename]
|
||||
(with-open [w (io/output-stream filename)]
|
||||
(.write w (:png_data (db/get-image-data issue-id)))))
|
Loading…
Reference in New Issue