Skip to content

Commit 0bd0e0a

Browse files
committed
Migrate to a more standard structure
1 parent 8590fde commit 0bd0e0a

File tree

13 files changed

+242
-210
lines changed

13 files changed

+242
-210
lines changed

.gitignore

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
/.shards/
2-
/.deps/
1+
/doc/
32
/libs/
43
/.crystal/
5-
/doc/
6-
/app
4+
/.shards/
5+
6+

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
language: crystal

app.cr

Lines changed: 0 additions & 206 deletions
This file was deleted.

shard.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
name: shards
22
version: 0.1.0
33
license: MIT
4+
authors:
5+
- Russell Smith <[email protected]>
46

57
dependencies:
68
kemal:

spec/plusone_spec.cr

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
require "./spec_helper"
2+
3+
describe Plusone do
4+
# TODO: Write tests
5+
6+
it "works" do
7+
false.should eq(true)
8+
end
9+
end

spec/spec_helper.cr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
require "spec"
2+
require "../src/plusone"

src/plusone.cr

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
require "./plusone/*"
2+
require "kemal"
3+
require "openssl/hmac"
4+
require "redis"
5+
require "json"
6+
require "uri"
7+
require "http/params"
8+
9+
Kemal.config.port = ENV["PORT"].to_i
10+
11+
uri = URI.parse(ENV["REDIS_URL"])
12+
$redis = Redis.new(uri.host.to_s, uri.port.to_s.to_i, nil, uri.password)
13+
14+
Plusone::Ping.start_pinging_redis
15+
16+
logger = Kemal::LogHandler.new
17+
18+
module Plusone
19+
def self.set_headers(context)
20+
# Caching headers - see https://github.com/github/markup/issues/224#issuecomment-37663375
21+
context.response.headers.add "Cache-Control", "no-cache, no-store, private, must-revalidate, max-age=0, max-stale=0, post-check=0, pre-check=0"
22+
context.response.headers.add "Pragma", "no-cache"
23+
context.response.headers.add "Expires", "0"
24+
context.response.content_type = "image/svg+xml"
25+
end
26+
27+
def self.get_svg(text)
28+
color = "green"
29+
w = 100
30+
s_x = w * 0.7
31+
32+
"<svg xmlns='http://www.w3.org/2000/svg' width='#{w}' height='20'><linearGradient id='a' x2='0' y2='100%'><stop offset='0' stop-color='#bbb' stop-opacity='.1'/><stop offset='1' stop-opacity='.1'/></linearGradient><rect rx='3' width='#{w}' height='20' fill='#555'/><rect rx='3' x='37' width='#{w - 37}' height='20' fill='#{color}'/><path fill='#{color}' d='M37 0h4v20h-4z'/><rect rx='3' width='#{w}' height='20' fill='url(#a)'/><g fill='#fff' text-anchor='middle' font-family='Geneva,sans-serif' font-size='11'><text x='19.5' y='15' fill='#010101' fill-opacity='.3'>build</text><text x='19.5' y='14'>+1s:</text><text x='#{s_x}' y='15' fill='#010101' fill-opacity='.3'>#{text}</text><text x='#{s_x}' y='14'>#{text}</text></g></svg>"
33+
end
34+
35+
get "/" do |context|
36+
if Plusone::Auth.authed?(context, ENV["HTTP_USERNAME"], ENV["HTTP_PASSWORD"])
37+
repo = context.params.fetch("repo", "") as String
38+
issue = context.params.fetch("issue", "") as String
39+
40+
instructions = ""
41+
42+
if repo != "" && issue != ""
43+
counter = Plusone::Counter.new(repo, issue)
44+
badge = "https://#{ENV["HEROKU_APP_NAME"]}.herokuapp.com/count.svg?repo=#{repo}&issue=#{issue}&sig=#{counter.badge_signature}"
45+
webhook = "https://#{ENV["HEROKU_APP_NAME"]}.herokuapp.com/injest?repo=#{repo}&sig=#{counter.injest_signature}"
46+
47+
# build the actual badge
48+
badge = "[![Issue " + issue + "](" + badge + ")](https://github.com/" + repo + "/issues/" + issue + ")"
49+
50+
instructions = <<-HTML
51+
<h2>1. Setup Webhook</h2>
52+
<p>Set this once per repo. Go to <a href="https://github.com/#{repo}/settings/hooks">your github settings</a>:</p>
53+
54+
<ol>
55+
<li>Set the <em>Payload URL</em> to:<br /><code>#{webhook}</code></li>
56+
<li>Then select "Let me select individual events."</li>
57+
<li>Then check "Issues" &amp; "Issue comment"</li>
58+
</ol>
59+
60+
<h2>2. Get Badge</h2>
61+
<p>Paste the following code in to your issue:</p>
62+
63+
<code>#{badge}</code>
64+
HTML
65+
end
66+
67+
template = <<-HTML
68+
<!DOCTYPE html>
69+
<html>
70+
<head>
71+
<meta charset="UTF-8">
72+
<title>+1</title>
73+
<style type="text/css">
74+
body { font-family:helvetica,arial;color:#888;margin:2em}
75+
ol li { margin-bottom: 1em; }
76+
code { margin: 0.5em; padding: 0.5em; background-color: #eee; display: inline-block; }
77+
</style>
78+
</head>
79+
<body>
80+
<h1>Hello.</h1>
81+
<p>Enter your repo name and issue number to get started.</p>
82+
83+
<form method="get">
84+
<input type="text" name="repo" value="#{repo}" placeholder="ukd1/plusone" />
85+
<input type="number" name="issue" value="#{issue}" placeholder="1" />
86+
<input type="submit" value="Get URLs" />
87+
</form>
88+
89+
#{instructions}
90+
</body>
91+
</html>
92+
HTML
93+
94+
template
95+
end
96+
end
97+
98+
post "/injest" do |context|
99+
if context.params.fetch("repo", false) && context.params.fetch("sig", false)
100+
sig = context.params.fetch("sig").to_s
101+
counter = Plusone::Counter.new(context.params.fetch("repo").to_s)
102+
103+
json = JSON.parse(context.request.body.to_s)
104+
if counter.injest_signature == sig
105+
if json["action"].to_s == "created" && json["comment"]["body"].to_s.includes?("+1")
106+
counter.incr(json["comment"]["user"]["id"])
107+
elsif json["action"].to_s == "created"
108+
logger.write("Comment doesn't have +1: #{json["comment"]["body"]}")
109+
else
110+
logger.write("Ignoring useless events: #{json.inspect}")
111+
end
112+
else
113+
logger.write("Invalid signature, please copy the URL again.")
114+
end
115+
else
116+
logger.write("Error missing parameters, please copy the URL again.")
117+
end
118+
end
119+
120+
get "/test.svg" do |context|
121+
set_headers(context)
122+
count = context.params.fetch("count") as String
123+
get_svg(count)
124+
end
125+
126+
get "/count.svg" do |context|
127+
set_headers(context)
128+
129+
if context.params.fetch("repo", false) && context.params.fetch("issue", false) && context.params.fetch("sig", false)
130+
counter = Plusone::Counter.new(context.params.fetch("repo").to_s, context.params.fetch("issue").to_s)
131+
132+
if counter.badge_signature == context.params.fetch("sig", "")
133+
get_svg(counter.count)
134+
else
135+
get_svg("Bad sig")
136+
end
137+
else
138+
get_svg("Bad url")
139+
end
140+
end
141+
end

0 commit comments

Comments
 (0)