aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2016-03-02 03:18:59 +0900
committerKazuki Yamaguchi <k@rhe.jp>2016-03-02 03:18:59 +0900
commit635df09819ba928ff79c18cdb5eb7b81bf2a68f4 (patch)
treede474bfbcf2f42d51dc92f1d8b422c8902072698
downloadicon-635df09819ba928ff79c18cdb5eb7b81bf2a68f4.tar.gz
initial commit
-rw-r--r--.gitignore3
-rw-r--r--Gemfile5
-rw-r--r--Gemfile.lock25
-rw-r--r--app.rb82
-rw-r--r--config.json.example8
-rw-r--r--config.ru2
-rw-r--r--views/index.erb65
7 files changed, 190 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1827958
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+config.json
+data
+.*.sw*
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..db87209
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,5 @@
+source "https://rubygems.org"
+
+gem "sinatra"
+gem "oauth"
+gem "rack-flash3"
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000..09f4a39
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,25 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ oauth (0.5.1)
+ rack (1.6.4)
+ rack-flash3 (1.0.5)
+ rack
+ rack-protection (1.5.3)
+ rack
+ sinatra (1.4.7)
+ rack (~> 1.5)
+ rack-protection (~> 1.4)
+ tilt (>= 1.3, < 3)
+ tilt (2.0.2)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ oauth
+ rack-flash3
+ sinatra
+
+BUNDLED WITH
+ 1.11.2
diff --git a/app.rb b/app.rb
new file mode 100644
index 0000000..f8c2acc
--- /dev/null
+++ b/app.rb
@@ -0,0 +1,82 @@
+require "sinatra"
+require "tilt/erb"
+require "fileutils"
+require "rack/flash"
+require "oauth"
+require "json"
+
+CONFIG = JSON.parse(File.read(File.expand_path("../config.json", __FILE__)), symbolize_names: true).freeze
+
+set :public_folder, CONFIG[:data]
+use Rack::Session::Cookie, { expire_after: (86400 * 7),
+ secret: CONFIG[:secret] }
+use Rack::Flash
+
+def logged_in?
+ !!session[:user_id]
+end
+
+def consumer
+ $consumer ||= OAuth::Consumer.new(CONFIG[:oauth][:consumer_key],
+ CONFIG[:oauth][:consumer_secret],
+ site: "https://api.twitter.com",
+ authorize_path: "/oauth/authenticate")
+end
+
+def authenticate!
+ redirect "/" unless session[:user_id]
+end
+
+get "/" do
+ if logged_in?
+ ids = Dir.glob(File.join(CONFIG[:data], session[:user_id], "*")).map { |path| path.split("/").last }
+ erb :index, locals: { ids: ids, user_id: session[:user_id] }
+ else
+ req = consumer.get_request_token(oauth_callback: request.url.sub(/\/[^\/]*\z/, "/callback"))
+ session[:req] = JSON.generate(token: req.token, secret: req.secret)
+ redirect req.authorize_url
+ end
+end
+
+get "/callback" do
+ if session[:req]
+ json = JSON.parse(session.delete(:req), symbolize_names: true)
+ if params[:oauth_token] == json[:token]
+ req = OAuth::RequestToken.new(consumer, json[:token], json[:secret])
+ acc = req.get_access_token(oauth_verifier: params[:oauth_verifier])
+ session[:user_id] = acc.params[:user_id]
+ session[:acc] = JSON.generate(token: acc.token, secret: acc.secret)
+ FileUtils.mkdir_p(File.join(CONFIG[:data], session[:user_id]))
+ end
+ end
+ redirect "/"
+end
+
+post "/update" do
+ authenticate!
+ return 400 unless /\A[0-9]+-[a-f0-9]{40}\z/ =~ params[:id].to_s
+ path = File.join(CONFIG[:data], session[:user_id], params[:id])
+ return 404 unless File.exist?(path)
+
+ encoded = [File.read(path)].pack("m0")
+
+ json = JSON.parse(session[:acc], symbolize_names: true)
+ acc = OAuth::AccessToken.new(consumer, json[:token], json[:secret])
+ acc.post("/1.1/account/update_profile_image.json", image: encoded)
+
+ flash[:notice] = "Successfully updated"
+ redirect "/"
+end
+
+post "/upload" do
+ authenticate!
+ return 400 unless (params.dig(:file, :tempfile) rescue nil)
+ tempfile = params[:file][:tempfile]
+ return 400 if tempfile.size > 5 * 1024 * 1024
+ digest = Digest::SHA1.file(tempfile).hexdigest
+ id = Time.now.to_i.to_s + "-" + digest
+ File.write(File.join(CONFIG[:data], session[:user_id], id), tempfile.read)
+
+ flash[:notice] = "Successfully uploaded"
+ redirect "/"
+end
diff --git a/config.json.example b/config.json.example
new file mode 100644
index 0000000..2b46119
--- /dev/null
+++ b/config.json.example
@@ -0,0 +1,8 @@
+{
+ "oauth": {
+ "consumer_key": ""
+ "consumer_secret": ""
+ },
+ "secret": "",
+ "data": "/work/icon-rhe/data"
+}
diff --git a/config.ru b/config.ru
new file mode 100644
index 0000000..78ed11b
--- /dev/null
+++ b/config.ru
@@ -0,0 +1,2 @@
+require "./app"
+run Sinatra::Application
diff --git a/views/index.erb b/views/index.erb
new file mode 100644
index 0000000..289adb3
--- /dev/null
+++ b/views/index.erb
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>icon</title>
+ <style>
+ img {
+ width: 128px;
+ height: 128px;
+ }
+
+ .container {
+ margin: 10px;
+ padding: 15px;
+ border: 1px solid #dddddd;
+ border-radius: 4px;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
+ }
+
+ .container.flex {
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+ .item.flex {
+ margin: 5px;
+ }
+
+ .item img {
+ vertical-align: middle;
+ }
+ </style>
+ </head>
+ <body>
+ <% if flash[:notice] %><div class="container"><%= flash[:notice] %></div><% end %>
+ <div class="container flex">
+ <% ids.each do |id| %>
+ <div class="item flex"><a href="/update" data-id="<%= id %>"><img alt="<%= id %>" src="<%= user_id %>/<%= id %>"></a></div>
+ <% end %>
+ </div>
+
+ <div class="container">
+ <form action="/upload" method="post" enctype="multipart/form-data">
+ <input type="file" name="file">
+ <input type="submit" value="Submit">
+ </form>
+ </div>
+
+ <form action="/update" method="post">
+ <input type="hidden" name="id">
+ </form>
+
+ <script>
+ var form = document.querySelector("form[action=\"/update\"]");
+ var hidden = form.querySelector("input[type=\"hidden\"]");
+ Array.prototype.forEach.call(document.querySelectorAll("a[href=\"/update\"]"), function(item) {
+ item.addEventListener("click", function(e) {
+ e.preventDefault();
+ hidden.value = e.currentTarget.dataset.id;
+ form.submit();
+ }, false);
+ });
+ </script>
+ </body>
+</html>
+