diff options
author | re4k <re4k@re4k.info> | 2013-03-26 17:54:34 +0900 |
---|---|---|
committer | re4k <re4k@re4k.info> | 2013-03-26 17:55:13 +0900 |
commit | 9e05ce53b550ab05d06268bd0c2ae26ad294d0ab (patch) | |
tree | a431e3e1811e32e465a872c3ea9481106b83b2f7 | |
parent | 22b478cd66a419c30ab28471fbd495019810469e (diff) | |
download | aclog-9e05ce53b550ab05d06268bd0c2ae26ad294d0ab.tar.gz |
Add favs_from/rts_from
24 files changed, 293 insertions, 133 deletions
@@ -24,4 +24,5 @@ gem 'jbuilder' gem 'msgpack' gem 'omniauth-twitter', :github => "re4k/omniauth-twitter" gem 'em-twitter' +gem 'twitter' diff --git a/Gemfile.lock b/Gemfile.lock index 5638adf..0f0d824 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -55,6 +55,8 @@ GEM eventmachine (1.0.3) execjs (1.4.0) multi_json (~> 1.0) + faraday (0.8.6) + multipart-post (~> 1.1) haml (4.0.1) tilt haml-rails (0.4) @@ -81,6 +83,7 @@ GEM minitest (4.7.0) msgpack (0.5.4) multi_json (1.7.2) + multipart-post (1.2.0) mysql2 (0.3.11) oauth (0.4.7) omniauth (1.1.3) @@ -136,6 +139,10 @@ GEM treetop (1.4.12) polyglot polyglot (>= 0.3.1) + twitter (4.6.2) + faraday (~> 0.8, < 0.10) + multi_json (~> 1.0) + simple_oauth (~> 0.2) tzinfo (0.3.37) uglifier (1.3.0) execjs (>= 0.3.0) @@ -163,5 +170,6 @@ DEPENDENCIES rails (= 4.0.0.beta1) rails_config sass-rails (~> 4.0.0.beta1) + twitter uglifier (>= 1.0.3) unicorn diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b6320a7..3edb6f0 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -7,24 +7,4 @@ class ApplicationController < ActionController::Base response.content_type = "application/xhtml+xml" end end - - def get_page_number(params) - if params[:page] - i = params[:page].to_i - if i > 0 - return i - end - end - return 1 - end - - def get_page_count(params) - if params[:count] - i = params[:count].to_i - if i && i > 0 && i <= 100 - return i - end - end - return Settings.page_per - end end diff --git a/app/controllers/i_controller.rb b/app/controllers/i_controller.rb index d1409de..a27f4d7 100644 --- a/app/controllers/i_controller.rb +++ b/app/controllers/i_controller.rb @@ -3,7 +3,7 @@ class IController < ApplicationController @items = Tweet .reacted .order_by_reactions - .limit(get_page_count(params)) + .limit(Settings.page_per) end def recent @@ -11,7 +11,14 @@ class IController < ApplicationController .recent .reacted .order_by_reactions - .limit(get_page_count(params)) + .limit(Settings.page_per) + end + + def timeline + @items = Tweet + .reacted + .order_by_id + .limit(Settings.page_per) end def show @@ -26,7 +33,7 @@ class IController < ApplicationController format.html format.json do - @include_user = params[:include_user] == "true" + @include_user = params[:include_user] == "true" end end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index cc11c2e..171280b 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,74 +1,151 @@ class UsersController < ApplicationController + before_filter :get_user + def best - user = render_timeline(params) do |tweets, user| - tweets.of(user).reacted.order_by_reactions + @title = "@#{@user.screen_name}'s Best Tweets" + render_page do + case params[:order] + when /^fav/ + @user.tweets.reacted.order_by_favorites + when /^re?t/ + @user.tweets.reacted.order_by_retweets + else + @user.tweets.reacted.order_by_reactions + end end - @title = "@#{user.screen_name}'s Best Tweets" end def recent - user = render_timeline(params) do |tweets, user| - tweets.of(user).recent.reacted.order_by_reactions + @title = "@#{@user.screen_name}'s Recent Best Tweets" + render_page do + case params[:order] + when /^fav/ + @user.tweets.recent.reacted.order_by_favorites + when /^re?t/ + @user.tweets.recent.reacted.order_by_retweets + else + @user.tweets.recent.reacted.order_by_reactions + end end - @title = "@#{user.screen_name}'s Recent Best Tweets" end def timeline - user = render_timeline(params) do |tweets, user| - if params[:tweets] == "all" - tweets.of(user).order_by_id + raise Exception.new if @user.protected #FIXME + + @title = "@#{@user.screen_name}'s Newest Tweets" + render_page do + case params[:tweets] + when /^all/ + @user.tweets.order_by_id else - tweets.of(user).reacted.order_by_id + @user.tweets.reacted.order_by_id end end - @title = "@#{user.screen_name}'s Newest Tweets" - - if user.protected - raise Exception # FIXME - end end def discovered - user = render_timeline(params) do |tweets, user| + @title = "@#{@user.screen_name}'s Recent Discoveries" + render_page do case params[:tweets] - when "favorite" - tweets.favorited_by(user).order_by_id - when "retweet" - tweets.retweeted_by(user).order_by_id + when /^fav/ + Tweet.favorited_by(@user).order_by_id + when /^re?t/ + Tweet.retweeted_by(@user).order_by_id else - tweets.discovered_by(user).order_by_id + Tweet.discovered_by(@user).order_by_id end end - @title = "@#{user.screen_name}'s Recent Discoveries" end - private - def render_timeline(params, &g) - page = get_page_number(params) - count = get_page_count(params) - screen_name = params[:screen_name] - user_id = params[:user_id] + def info + account = Account.where(:user_id => @user.id).first + unless account + raise ActiveRecord::RecordNotFound.new("Account not found: #{@user}") + end - @user = User.where(:screen_name => screen_name).first - unless @user - @user = User.where(:id => user_id).first - unless @user - raise ActiveRecord::RecordNotFound.new("screen_name=#{screen_name}&user_id=#{user_id}") + @title = "@#{@user.screen_name} (#{@user.name})'s Profile" + + @twitter_user = account.twitter_user + + respond_to do |format| + format.html + format.json + end + end + + def from + hash = {} + @user.tweets.order_by_id.limit(100).each do |tweet| + case params[:event] + when /^fav/ + events = tweet.favorites + when /^re?t/ + events = tweet.retweets + else + raise Exception.new("Invalid event type") + end + + events.each do |event| + hash[event.user_id] ||= 0 + hash[event.user_id] += 1 end end - @items = g.call(Tweet, @user) - .page(page) - .per(count) + @usermap = hash.sort_by{|id, count| -count} + .take(50) + .map{|user, count| [User.cached(user), count]} + end + + private + def render_page(&blk) + @items = blk.call.page(page).per(count) respond_to do |format| format.html + format.json + end + end + + def get_user + if params[:user_id] + @user = User.cached(params[:user_id].to_i) + end + + if !@user || params[:screen_name] + @user = User.where(:screen_name => params[:screen_name]).first + end - format.json do - @include_user = params[:include_user] == "true" + unless @user + raise ActiveRecord::RecordNotFound.new( + "User not found: #{{:user_id => params[:user_id], :screen_name => params[:screen_name]}.inspect}") + end + end + + def page + if params[:page] + i = params[:page].to_i + if i > 0 + ret = i + end + end + ret || 1 + end + + def count + if params[:count] + i = params[:count].to_i + if (1..100) === i + ret = i end end + ret || Settings.page_per + end - return @user + def include_user + case params[:include_user] + when /^t/ + ret = true + end + ret || false end end diff --git a/app/models/account.rb b/app/models/account.rb index 31fe26d..14b9da9 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -2,4 +2,18 @@ class Account < ActiveRecord::Base def user User.cached(user_id) end + + def twitter_user + Rails.cache.fetch("twitter_user/#{user_id}", :expires_in => 1.hour) do + client.user(user_id) + end + end + + def client + Twitter::Client.new( + :consumer_key => Settings.consumer[consumer_version.to_i].key, + :consumer_secret => Settings.consumer[consumer_version.to_i].secret, + :oauth_token => oauth_token, + :oauth_token_secret => oauth_token_secret) + end end diff --git a/app/models/tweet.rb b/app/models/tweet.rb index d20377b..d30ff4e 100644 --- a/app/models/tweet.rb +++ b/app/models/tweet.rb @@ -15,6 +15,14 @@ class Tweet < ActiveRecord::Base order("id DESC") end + scope :order_by_favorites, -> do + order("favorites_count DESC") + end + + scope :order_by_retweets, -> do + order("retweets_count DESC") + end + scope :order_by_reactions, -> do order("COALESCE(favorites_count, 0) + COALESCE(retweets_count, 0) DESC") end @@ -35,10 +43,6 @@ class Tweet < ActiveRecord::Base ")", user.id, user.id) end - scope :of, -> user do - where("user_id = ?", user.id) - end - def self.cached(id) Rails.cache.fetch("tweet/#{id}", :expires_in => 3.hour) do where(:id => id).first diff --git a/app/models/user.rb b/app/models/user.rb index b93eac9..46acd47 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -22,4 +22,8 @@ class User < ActiveRecord::Base def registered? Account.exists?(:user_id => id) end + + def profile_image_url_original + profile_image_url.sub(/_normal((\.(png|jpeg|gif))?)/, "\\1") + end end diff --git a/app/views/errors/error_404.html.haml b/app/views/errors/error_404.html.haml index 4f574e3..2c9b7ac 100644 --- a/app/views/errors/error_404.html.haml +++ b/app/views/errors/error_404.html.haml @@ -1 +1,2 @@ %h2 404 +%p= @exception diff --git a/app/views/i/show.html.haml b/app/views/i/show.html.haml index f56e0c0..672b7e9 100644 --- a/app/views/i/show.html.haml +++ b/app/views/i/show.html.haml @@ -1,4 +1,3 @@ = render :partial => "shared/user_nav", :locals => {:user => @user} .items = render :partial => "shared/tweet", :locals => {:item => @item} -= render :partial => "shared/user_info", :locals => {:user => @user} diff --git a/app/views/i/timeline.html.haml b/app/views/i/timeline.html.haml new file mode 100644 index 0000000..1410df9 --- /dev/null +++ b/app/views/i/timeline.html.haml @@ -0,0 +1 @@ += render :partial => "list" diff --git a/app/views/main/index.html.haml b/app/views/main/index.html.haml index 6580d77..7870c5e 100644 --- a/app/views/main/index.html.haml +++ b/app/views/main/index.html.haml @@ -14,19 +14,25 @@ URLとかについて %div best: - = link_to "/cat", "/cat" + = link_to "/sg4k", "/sg4k" %div recent(最新3日のbest): - = link_to "/cat/recent", "/cat/recent" + = link_to "/sg4k/recent", "/sg4k/recent" %div timeline(Favstar の Recent): - = link_to "/cat/timeline", "/cat/timeline" + = link_to "/sg4k/timeline", "/sg4k/timeline" %div timeline(ユーザータイムライン): - = link_to "/cat/timeline/all", "/cat/timeline/all" + = link_to "/sg4k/timeline/all", "/sg4k/timeline/all" %div discovery: - = link_to "/cat/discovered(/{favorite|retweet})", "/cat/discovered" + = link_to "/sg4k/discovered(/{favorite|retweet})", "/sg4k/discovered" + %div + favs_from: + = link_to "/sg4k/favs_from", "/sg4k/favs_from" + %div + rts_from: + = link_to "/sg4k/rts_from", "/sg4k/rts_from" %div %div 全体のbest: @@ -35,28 +41,35 @@ 全体の最新3日のbest = link_to "/i/recent", "/i/recent" %div + 全体の最新反応あり + = link_to "/i/timeline", "/i/timeline" + %div URL 変えちゃうかもしれないです %div API っていえるのかな…? %div %p - \/i/show.json?id=[tweet_id] - %p - \/users/{best|recent|timeline|discovered}.json - %p - screen_name - %p - user_id - %p - count - %p - include_user=true|false ← fav/RTしたユーザーを取得するか(false で ID のみ - %p - tweets={*tweet*|all} ← /users/timeline - %p - tweets={favorite|retweet|*all*} ← discovered + URL + %p + \/i/show.json?id=[tweet_id] + %p + \/users/{best|recent|timeline|discovered}.json %p - page + params + %p + screen_name or user_id 必須 + %p + count デフォルト10、100以下 + %p + page ページ。1から + %p + include_user={true|} fav/RTしたユーザーを取得するか + %p + tweets={all|} timeline + %p + tweets={favorite|retweet|} discovered + %p + order={favorite|retweet|} best/recent %div - = link_to "@cat", "https://twitter.com/cat" + = link_to "@sg4k", "https://twitter.com/sg4k" diff --git a/app/views/shared/_tweet.html.haml b/app/views/shared/_tweet.html.haml index 4d40f69..2f7adb2 100644 --- a/app/views/shared/_tweet.html.haml +++ b/app/views/shared/_tweet.html.haml @@ -26,7 +26,7 @@ %span.type= type .height_fix %ul.favoriters.clearfix - - actions.take(params[:controller] == "users" && params[:action] == "show" ? actions.size : 20).each do |a| | + - actions.take(params[:controller] == "i" && params[:action] == "show" ? actions.size : 20).each do |a| | - m = a.user || User.new %li - if m.screen_name diff --git a/app/views/shared/_user_info.html.haml b/app/views/shared/_user_info.html.haml deleted file mode 100644 index 6188bdc..0000000 --- a/app/views/shared/_user_info.html.haml +++ /dev/null @@ -1,17 +0,0 @@ -- if user.registered? - %ul - %li - Tweets: - = user.tweets.length - %li - Favorites: - = user.favorites.length - %li - Retweets: - = user.retweets.length - %li - Favorited: - = user.tweets.inject(0){|s, m| s + m.favorites_count} - %li - Retweeted: - = user.tweets.inject(0){|s, m| s + m.retweets_count} diff --git a/app/views/shared/_user_nav.html.haml b/app/views/shared/_user_nav.html.haml index f7a3c7b..2332d24 100644 --- a/app/views/shared/_user_nav.html.haml +++ b/app/views/shared/_user_nav.html.haml @@ -1,11 +1,28 @@ -- if user - .links +.links + %ul + %li + = link_to "Best", :controller => "users", :action => "best", :screen_name => user.screen_name + %li + = link_to "Recent", :controller => "users", :action => "recent", :screen_name => user.screen_name + %li + = link_to "Timeline", :controller => "users", :action => "timeline", :screen_name => user.screen_name + %li + = link_to "Discovered", :controller => "users", :action => "discovered", :screen_name => user.screen_name +- if user.registered? + .records %ul %li - = link_to "Best", :controller => "users", :action => "best", :screen_name => user.screen_name + Tweets: + = user.tweets.length %li - = link_to "Recent", :controller => "users", :action => "recent", :screen_name => user.screen_name + Favorites: + = user.favorites.length %li - = link_to "Timeline", :controller => "users", :action => "timeline", :screen_name => user.screen_name + Retweets: + = user.retweets.length %li - = link_to "Discovered", :controller => "users", :action => "discovered", :screen_name => user.screen_name + Favorited: + = user.tweets.inject(0){|s, m| s + m.favorites_count} + %li + Retweeted: + = user.tweets.inject(0){|s, m| s + m.retweets_count} diff --git a/app/views/users/_list.html.haml b/app/views/users/_list.html.haml index 3147f1b..7819075 100644 --- a/app/views/users/_list.html.haml +++ b/app/views/users/_list.html.haml @@ -3,4 +3,3 @@ = render :partial => "shared/tweet", :collection => @items, :as => :item - if @items = paginate @items -= render :partial => "shared/user_info", :locals => {:user => @user} diff --git a/app/views/users/from.html.haml b/app/views/users/from.html.haml new file mode 100644 index 0000000..c992c59 --- /dev/null +++ b/app/views/users/from.html.haml @@ -0,0 +1,8 @@ += render :partial => "shared/user_nav", :locals => {:user => @user} +.items + .item + - @usermap.each do |user, count| + %div + = image_tag user.profile_image_url, :alt => user.screen_name + %div + = count diff --git a/app/views/users/info.html.haml b/app/views/users/info.html.haml new file mode 100644 index 0000000..8d6e326 --- /dev/null +++ b/app/views/users/info.html.haml @@ -0,0 +1,21 @@ += render :partial => "shared/user_nav", :locals => {:user => @user} +.items + .item + %h2= "@#{@user.screen_name}" + %div + = image_tag @user.profile_image_url_original, :alt => @user.screen_name + %div + %h3 Username + %p= @user.screen_name + %h3 Name + %p= raw @twitter_user.name + %h3 Tweets + %p= @twitter_user.statuses_count + %h3 Following + %p= @twitter_user.friends_count + %h3 Followers + %p= @twitter_user.followers_count + %h3 Favorites + %p= @twitter_user.favourites_count + %h3 Bio + %p= raw @twitter_user.description diff --git a/client/worker.rb b/client/worker.rb index 1ed3414..eeb7bf9 100644 --- a/client/worker.rb +++ b/client/worker.rb @@ -52,19 +52,25 @@ class Worker def receive_account(msg) user_id = msg["user_id"] account_id = msg["id"] + + conopts = {:host => "userstream.twitter.com", + :path => "/1.1/user.json", + :oauth => { + :consumer_key => Settings.consumer[msg["consumer_version"].to_i].key, + :consumer_secret => Settings.consumer[msg["consumer_version"].to_i].secret, + :token => msg["oauth_token"], + :token_secret => msg["oauth_token_secret"]}, + :method => "GET"} if @clients[account_id] - @clients[account_id].connection.stop - @clients.delete(account_id) + unless @clients[account_id].options[:oauth][:token] == conopts[:oauth][:token] + @clients.connection.update(conopts) + $logger.info("Updated(##{account_id}/#{user_id}/#{msg["consumer_version"].to_i})") + else + $logger.info("Not Updated(##{account_id}/#{user_id}/#{msg["consumer_version"].to_i})") + end + return end - @clients[account_id] = client = EM::Twitter::Client.new({ - :host => "userstream.twitter.com", - :path => "/1.1/user.json", - :oauth => { - :consumer_key => Settings.consumer[msg["consumer_version"].to_i].key, - :consumer_secret => Settings.consumer[msg["consumer_version"].to_i].secret, - :token => msg["oauth_token"], - :token_secret => msg["oauth_token_secret"]}, - :method => "GET"}) + @clients[account_id] = client = EM::Twitter::Client.new(conopts) send_user = -> user do out = {:type => "user", @@ -206,7 +212,7 @@ class Worker end client.connect - $logger.info("Connected(##{account_id}/#{user_id})") + $logger.info("Connected(##{account_id}/#{user_id}/#{msg["consumer_version"].to_i})") end def post_init diff --git a/config/application.rb b/config/application.rb index 68cbb89..00a77a1 100644 --- a/config/application.rb +++ b/config/application.rb @@ -25,5 +25,7 @@ module Aclog config.exceptions_app = -> env do ErrorsController.action(:render_error).call(env) end + + config.assets.precompile += %w(*.png *.jpg *.jpeg *.gif) end end diff --git a/config/environments/development.rb b/config/environments/development.rb index 5089ff4..4d9bb15 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -10,7 +10,7 @@ Aclog::Application.configure do config.eager_load = false # Show full error reports and disable caching. - config.consider_all_requests_local = false#true + config.consider_all_requests_local = true config.action_controller.perform_caching = false # Don't care if the mailer can't send. @@ -25,5 +25,5 @@ Aclog::Application.configure do # Expands the lines which load the assets. config.assets.debug = true - # config.cache_store = :dalli_store + config.cache_store = :dalli_store end diff --git a/config/routes.rb b/config/routes.rb index 3b65357..1d697db 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -5,29 +5,36 @@ Aclog::Application.routes.draw do :screen_name => /[a-zA-Z0-9_]{1,20}/, :page => /[0-9]+/, :count => /[0-9]+/, - :tweets => /(all|favorite|retweet)/ + :tweets => /(all|fav(orite[sd]?|(or)?ed|s)?|re?t(weet(s|ed)?|s)?)/, + :order => /(fav(orite[sd]?|(or)?ed|s)?|re?t(weet(s|ed)?|s)?)/, } root :to => "main#index" + # internals + get "/i" => redirect("/") get "/i/callback" => "sessions#callback" get "/i/logout" => "sessions#destroy" + # other + get "/i/show" => "i#show", :constraints => constraints + get "/i/best" => "i#best" get "/i/recent" => "i#recent" + get "/i/timeline" => "i#timeline" + get "/i/:id" => "i#show", :constraints => constraints - get "/i/show" => "i#show", :constraints => constraints + # user get "/users/best" => "users#best", :constraints => constraints get "/users/recent" => "users#recent", :constraints => constraints get "/users/timeline" => "users#timeline", :constraints => constraints get "/users/discovered" => "users#discovered", :constraints => constraints - get "/i/:id" => "i#show", :constraints => constraints - get "/:screen_name(/:page)" => "users#best", :constraints => constraints - get "/:screen_name/best" => redirect("/%{screen_name}") + get "/:screen_name/:order(/:page)" => "users#best", :constraints => constraints get "/:screen_name/recent(/:page)" => "users#recent", :constraints => constraints + get "/:screen_name/recent/:order(/:page)" => "users#recent", :constraints => constraints get "/:screen_name/timeline(/:page)" => "users#timeline", :constraints => constraints get "/:screen_name/timeline/:tweets(/:page)" => "users#timeline", :constraints => constraints @@ -35,6 +42,11 @@ Aclog::Application.routes.draw do get "/:screen_name/discovered(/:page)" => "users#discovered", :constraints => constraints get "/:screen_name/discovered/:tweets(/:page)" => "users#discovered", :constraints => constraints + get "/:screen_name/info" => "users#info", :constraints => constraints + get "/:screen_name/favs_from" => "users#from", :constraints => constraints, :defaults => {:event => "favorite"} + get "/:screen_name/rts_from" => "users#from", :constraints => constraints, :defaults => {:event => "retweet"} + + # redirects get "/(users)/:screen_name/status(es)/:id" => redirect("/i/%{id}") get "/users/:screen_name" => redirect("/%{screen_name}") get "/users/:screen_name/discovered" => redirect("/%{screen_name}/discovered") diff --git a/db/schema.rb b/db/schema.rb index d8b9299..0efc468 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -38,6 +38,7 @@ ActiveRecord::Schema.define(version: 20130323045606) do t.integer "user_id", limit: 8, null: false end + add_index "retweets", ["tweet_id", "user_id"], name: "index_retweets_on_tweet_id_and_user_id", unique: true add_index "retweets", ["tweet_id"], name: "index_retweets_on_tweet_id" add_index "retweets", ["user_id"], name: "index_retweets_on_user_id" @@ -50,6 +51,8 @@ ActiveRecord::Schema.define(version: 20130323045606) do t.integer "retweets_count", default: 0 end + add_index "tweets", ["user_id"], name: "index_tweets_on_user_id" + create_table "users", force: true do |t| t.string "screen_name" t.string "name" diff --git a/public/assets/manifest-197176d2ea77846e2a59c4ba04910ece.json b/public/assets/manifest-b0844b10c48f9860d6b42a7d1918ff80.json index db1f481..db1f481 100644 --- a/public/assets/manifest-197176d2ea77846e2a59c4ba04910ece.json +++ b/public/assets/manifest-b0844b10c48f9860d6b42a7d1918ff80.json |