diff options
author | Kazuki Yamaguchi <k@rhe.jp> | 2016-03-02 03:18:59 +0900 |
---|---|---|
committer | Kazuki Yamaguchi <k@rhe.jp> | 2016-03-02 03:18:59 +0900 |
commit | 635df09819ba928ff79c18cdb5eb7b81bf2a68f4 (patch) | |
tree | de474bfbcf2f42d51dc92f1d8b422c8902072698 | |
download | icon-635df09819ba928ff79c18cdb5eb7b81bf2a68f4.tar.gz |
initial commit
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | Gemfile | 5 | ||||
-rw-r--r-- | Gemfile.lock | 25 | ||||
-rw-r--r-- | app.rb | 82 | ||||
-rw-r--r-- | config.json.example | 8 | ||||
-rw-r--r-- | config.ru | 2 | ||||
-rw-r--r-- | views/index.erb | 65 |
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* @@ -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 @@ -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> + |