diff --git a/.env b/.env
deleted file mode 100644
index e69de29..0000000
diff --git a/.gitignore b/.gitignore
index d219437..58f0e2a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,4 @@
coverage
.DS_Store
+.env
diff --git a/Gemfile b/Gemfile
index 96a7ed5..4422102 100644
--- a/Gemfile
+++ b/Gemfile
@@ -30,6 +30,10 @@ gem 'httparty'
# OmniAuth Gems
gem 'omniauth'
+gem 'omniauth-instagram'
+
+# OAuth
+gem 'twitter'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
@@ -73,4 +77,3 @@ end
group :production do
gem 'pg'
end
-
diff --git a/Gemfile.lock b/Gemfile.lock
index f9a54cc..f49a0fa 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -36,6 +36,7 @@ GEM
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
+ addressable (2.3.8)
arel (6.0.2)
autoprefixer-rails (5.2.1.1)
execjs
@@ -49,6 +50,7 @@ GEM
bootstrap-sass (3.3.5.1)
autoprefixer-rails (>= 5.0.0.1)
sass (>= 3.3.0)
+ buftok (0.2.0)
builder (3.2.2)
byebug (5.0.0)
columnize (= 0.9.0)
@@ -68,6 +70,7 @@ GEM
dotenv-rails (2.0.2)
dotenv (= 2.0.2)
railties (~> 4.0)
+ equalizer (0.0.11)
erubis (2.7.0)
execjs (2.5.2)
factory_girl (4.5.0)
@@ -75,9 +78,14 @@ GEM
factory_girl_rails (4.5.0)
factory_girl (~> 4.5.0)
railties (>= 3.0.0)
+ faraday (0.9.1)
+ multipart-post (>= 1.2, < 3)
globalid (0.3.5)
activesupport (>= 4.1.0)
hashie (3.4.2)
+ http (0.6.4)
+ http_parser.rb (~> 0.6.0)
+ http_parser.rb (0.6.0)
httparty (0.13.5)
json (~> 1.8)
multi_xml (>= 0.5.2)
@@ -90,21 +98,38 @@ GEM
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
json (1.8.3)
+ jwt (1.5.1)
loofah (2.0.2)
nokogiri (>= 1.5.9)
mail (2.6.3)
mime-types (>= 1.16, < 3)
+ memoizable (0.4.2)
+ thread_safe (~> 0.3, >= 0.3.1)
method_source (0.8.2)
mime-types (2.6.1)
mini_portile (0.6.2)
minitest (5.7.0)
multi_json (1.11.2)
multi_xml (0.5.5)
+ multipart-post (2.0.0)
+ naught (1.0.0)
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
+ oauth2 (1.0.0)
+ faraday (>= 0.8, < 0.10)
+ jwt (~> 1.0)
+ multi_json (~> 1.3)
+ multi_xml (~> 0.5)
+ rack (~> 1.2)
omniauth (1.2.2)
hashie (>= 1.2, < 4)
rack (~> 1.0)
+ omniauth-instagram (1.0.1)
+ omniauth (~> 1.0)
+ omniauth-oauth2 (~> 1.0)
+ omniauth-oauth2 (1.3.1)
+ oauth2 (~> 1.0)
+ omniauth (~> 1.2)
pg (0.18.2)
pry (0.10.1)
coderay (~> 1.1.0)
@@ -168,6 +193,7 @@ GEM
sdoc (0.4.1)
json (~> 1.7, >= 1.7.7)
rdoc (~> 4.0)
+ simple_oauth (0.3.1)
simplecov (0.10.0)
docile (~> 1.1.0)
json (~> 1.8)
@@ -187,6 +213,17 @@ GEM
tilt (1.4.1)
turbolinks (2.5.3)
coffee-rails
+ twitter (5.14.0)
+ addressable (~> 2.3)
+ buftok (~> 0.2.0)
+ equalizer (~> 0.0.9)
+ faraday (~> 0.9.0)
+ http (~> 0.6.0)
+ http_parser.rb (~> 0.6.0)
+ json (~> 1.8)
+ memoizable (~> 0.4.0)
+ naught (~> 1.0)
+ simple_oauth (~> 0.3.0)
tzinfo (1.2.2)
thread_safe (~> 0.1)
uglifier (2.7.1)
@@ -213,6 +250,7 @@ DEPENDENCIES
jbuilder (~> 2.0)
jquery-rails
omniauth
+ omniauth-instagram
pg
pry-rails
rails (= 4.2.3)
@@ -223,6 +261,7 @@ DEPENDENCIES
spring
sqlite3
turbolinks
+ twitter
uglifier (>= 1.3.0)
web-console (~> 2.0)
diff --git a/app/assets/images/notso-2.png b/app/assets/images/notso-2.png
new file mode 100644
index 0000000..867f4dc
Binary files /dev/null and b/app/assets/images/notso-2.png differ
diff --git a/app/assets/javascripts/instagram_posts.coffee b/app/assets/javascripts/instagram_posts.coffee
new file mode 100644
index 0000000..24f83d1
--- /dev/null
+++ b/app/assets/javascripts/instagram_posts.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/javascripts/instagrams.coffee b/app/assets/javascripts/instagrams.coffee
new file mode 100644
index 0000000..24f83d1
--- /dev/null
+++ b/app/assets/javascripts/instagrams.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/javascripts/tweets.coffee b/app/assets/javascripts/tweets.coffee
new file mode 100644
index 0000000..24f83d1
--- /dev/null
+++ b/app/assets/javascripts/tweets.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/stylesheets/custom.css.scss b/app/assets/stylesheets/custom.css.scss
index baccee2..471f7d0 100644
--- a/app/assets/stylesheets/custom.css.scss
+++ b/app/assets/stylesheets/custom.css.scss
@@ -1,2 +1,21 @@
@import "bootstrap-sprockets";
@import "bootstrap";
+
+.content {
+ padding-top: 35px;
+ // background: image-url("notso-2.png") no-repeat;
+}
+
+.center {
+ text-align: center;
+ margin: auto;
+ float: none;
+}
+
+.header {
+ font-size: 60px;
+}
+
+a:hover {
+ text-decoration: none;
+}
diff --git a/app/assets/stylesheets/instagram_posts.scss b/app/assets/stylesheets/instagram_posts.scss
new file mode 100644
index 0000000..a553731
--- /dev/null
+++ b/app/assets/stylesheets/instagram_posts.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the InstagramPosts controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/assets/stylesheets/instagrams.scss b/app/assets/stylesheets/instagrams.scss
new file mode 100644
index 0000000..deda276
--- /dev/null
+++ b/app/assets/stylesheets/instagrams.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the Instagrams controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/assets/stylesheets/tweets.scss b/app/assets/stylesheets/tweets.scss
new file mode 100644
index 0000000..5f231b3
--- /dev/null
+++ b/app/assets/stylesheets/tweets.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the twitters controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index d83690e..22a6f52 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,5 +1,27 @@
+require 'twitter'
+require 'twit'
+
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
+ before_filter :twit
+
+ INSTAGRAM_URI = "https://api.instagram.com/v1/"
+ MESSAGES = {
+ no_username: "There's no user by that name. Search again.",
+ success: "Success!",
+ follow_error: "Oops. Something went wrong.",
+ login_required: "You have to be logged in to do that!"
+ }
+
+ def twit
+ @twitter ||= Twit.new
+ end
+
+ def require_login
+ unless session[:user_id]
+ redirect_to root_path, flash: { error: MESSAGES[:login_required] }
+ end
+ end
end
diff --git a/app/controllers/feeds_controller.rb b/app/controllers/feeds_controller.rb
index b1c6e94..8569a18 100644
--- a/app/controllers/feeds_controller.rb
+++ b/app/controllers/feeds_controller.rb
@@ -1,7 +1,42 @@
+require 'httparty'
+
class FeedsController < ApplicationController
def index
@user = User.find_by(id: session[:user_id])
-
+ @posts = []
+ if @user && @user.instagrams
+ @user.instagram_posts.each do |post|
+ @posts << HTTParty.get(INSTAGRAM_URI + "media/" + post.post_id + "?access_token=#{session[:access_token]}")
+ end
+ @posts.sort_by! { |post| post["data"]["created_time"]}
+ @posts.reverse!
+ end
+
+ if @user && @user.tweets
+ @people = []
+ # @people << Instagram.find(@user.instagram_ids)
+ @people << Tweet.find(@user.tweet_ids)
+ @people.flatten!
+ @people.sort_by! { |person| person.username.downcase }
+
+ @feed = []
+ @people.each do |person|
+ username = person.username
+ @feed << @twitter.client.user_timeline(username, count: 10)
+ @feed.flatten!
+ @feed.sort_by { |tweet| tweet.created_at.strftime("%m/%d/%Y") }
+ end
+ end
+ end
+
+ def search; end
+
+ def people
+ @user = User.find_by(id: session[:user_id])
+ if @user
+ @people = Instagram.find(@user.instagram_ids) + Tweet.find(@user.tweet_ids)
+ end
end
+
end
diff --git a/app/controllers/instagram_posts_controller.rb b/app/controllers/instagram_posts_controller.rb
new file mode 100644
index 0000000..290a04b
--- /dev/null
+++ b/app/controllers/instagram_posts_controller.rb
@@ -0,0 +1,42 @@
+require 'httparty'
+
+class InstagramPostsController < ApplicationController
+ before_action :require_login, only: [:create]
+
+ def create
+ user = User.find_by(id: session[:user_id])
+ if user && user.instagrams
+ get_posts(user)
+
+ # Check if db table includes each post;
+ # if not, create new InstagramPost
+ @all_posts.each do |post|
+ params[:instagram_post] = {
+ post_id: post[:post_id],
+ instagram_id: post[:ig_id]
+ }
+ InstagramPost.find_or_create_by(instagram_post_params)
+ end
+ end
+ redirect_to root_path
+ end
+
+ private
+
+ def get_posts(user)
+ # Get an array of all recent post ids associated with
+ # all followed instagram users
+ @all_posts = []
+ user.instagrams.each do |gram|
+ ig_user_posts = HTTParty.get(INSTAGRAM_URI + "users/#{gram.provider_id}/media/recent?count=10&access_token=#{session[:access_token]}")
+ all_post_ids = ig_user_posts["data"].each do |post|
+ @all_posts << { ig_id: gram.id, post_id: post["id"]}
+ end
+ end
+ return @all_posts
+ end
+
+ def instagram_post_params
+ params.require(:instagram_post).permit(:post_id, :instagram_id)
+ end
+end
diff --git a/app/controllers/instagrams_controller.rb b/app/controllers/instagrams_controller.rb
new file mode 100644
index 0000000..6de14ce
--- /dev/null
+++ b/app/controllers/instagrams_controller.rb
@@ -0,0 +1,52 @@
+require 'httparty'
+
+class InstagramsController < ApplicationController
+ before_action :require_login, only: [:create]
+
+ CALLBACK_URL = "http://localhost:3000/auth/instagram/callback"
+
+ def search
+ if params[:instagram].present?
+ instagram_search = params[:instagram][:username]
+ response = HTTParty.get(INSTAGRAM_URI + "users/search?q=#{instagram_search}&client_id=#{ENV["INSTAGRAM_ID"]}")
+
+ @users = response["data"]
+
+ return render "feeds/search"
+ else
+ redirect_to root_path, flash: { error: MESSAGES[:no_username] }
+ end
+ end
+
+ def create
+ @instagram_person = Instagram.find_or_create_by(instagram_params)
+ @person = @instagram_person.username
+ @instagram_person.users << User.find(session[:user_id])
+
+ if @instagram_person.save
+ return redirect_to root_path, flash: { alert: MESSAGES[:success] }
+ else
+ return render "feeds/search", flash: { error: MESSAGES[:follow_error] }
+ end
+ redirect_to search_path
+ # add flash: no search results were found for 'username'
+ end
+
+ def destroy
+ user = User.find_by(id: session[:user_id])
+ instagramer = Instagram.find(params[:id])
+
+ if instagramer
+ user.instagrams.destroy(instagramer)
+ end
+
+ redirect_to people_path, flash: { alert: MESSAGES[:success] }
+ end
+
+ private
+
+ def instagram_params
+ params.require(:instagram).permit(:username, :provider_id, :image_url)
+ end
+
+end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 4fa18c1..3d89388 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -3,9 +3,12 @@ class SessionsController < ApplicationController
def create
auth_hash = request.env['omniauth.auth'] || params
- @user = User.find_or_create_from_omniauth_developer(auth_hash)
+ @user = User.find_or_create_from_omniauth(auth_hash)
session[:user_id] = @user.id
+ # NOTE: SM added. Gets the user's access_token from Instagram
+ session[:access_token] = auth_hash[:credentials][:token]
+
redirect_to root_path
end
diff --git a/app/controllers/tweets_controller.rb b/app/controllers/tweets_controller.rb
new file mode 100644
index 0000000..51dade0
--- /dev/null
+++ b/app/controllers/tweets_controller.rb
@@ -0,0 +1,47 @@
+class TweetsController < ApplicationController
+ before_action :require_login, only: [:create]
+
+ def search
+ if params[:tweet].present?
+ username = params[:tweet][:username]
+ @users = @twitter.client.user_search(username)
+ # @feed = @twitter.client.user_timeline(username, count: 1)
+ return render "feeds/search"
+ else
+ redirect_to root_path, flash: { error: MESSAGES[:no_username] }
+ end
+ end
+
+ def create
+ @twitter_person = Tweet.find_or_create_by(tweet_params)
+ @person = @twitter_person.username
+ @twitter_person.users << User.find(session[:user_id])
+
+ if @twitter_person.save
+ return redirect_to root_path, flash: { alert: MESSAGES[:success] }
+ else
+ return render "feeds/search", flash: { error: MESSAGES[:follow_error] }
+ end
+ end
+
+ def destroy
+ user = User.find_by(id: session[:user_id])
+ tweeter = Tweet.find(params[:id])
+
+ if tweeter
+ user.tweets.destroy(tweeter)
+ end
+
+ redirect_to people_path, flash: { alert: MESSAGES[:success] }
+ end
+
+ private
+
+ def tweet_params
+ params.require(:tweet).permit(
+ :username,
+ :provider_id,
+ :image_url
+ )
+ end
+end
diff --git a/app/helpers/instagram_posts_helper.rb b/app/helpers/instagram_posts_helper.rb
new file mode 100644
index 0000000..270b7fc
--- /dev/null
+++ b/app/helpers/instagram_posts_helper.rb
@@ -0,0 +1,2 @@
+module InstagramPostsHelper
+end
diff --git a/app/helpers/instagrams_helper.rb b/app/helpers/instagrams_helper.rb
new file mode 100644
index 0000000..0eb63c9
--- /dev/null
+++ b/app/helpers/instagrams_helper.rb
@@ -0,0 +1,2 @@
+module InstagramsHelper
+end
diff --git a/app/helpers/tweets_helper.rb b/app/helpers/tweets_helper.rb
new file mode 100644
index 0000000..6b7d657
--- /dev/null
+++ b/app/helpers/tweets_helper.rb
@@ -0,0 +1,2 @@
+module TweetsHelper
+end
diff --git a/app/models/instagram.rb b/app/models/instagram.rb
new file mode 100644
index 0000000..7a9b8c0
--- /dev/null
+++ b/app/models/instagram.rb
@@ -0,0 +1,9 @@
+class Instagram < ActiveRecord::Base
+ # Associations ----------------------------------------------
+ has_and_belongs_to_many :users
+ has_many :instagram_posts
+
+ # Validations ----------------------------------------------
+ validates :username, :provider_id, presence: true, uniqueness: true
+
+end
diff --git a/app/models/instagram_post.rb b/app/models/instagram_post.rb
new file mode 100644
index 0000000..396771e
--- /dev/null
+++ b/app/models/instagram_post.rb
@@ -0,0 +1,9 @@
+class InstagramPost < ActiveRecord::Base
+ belongs_to :instagram
+ has_many :users, through: :instagram
+
+ # Validations -----------
+ validates :post_id, presence: true, uniqueness: true
+ validates :instagram_id, presence: true
+
+end
diff --git a/app/models/tweet.rb b/app/models/tweet.rb
new file mode 100644
index 0000000..9543931
--- /dev/null
+++ b/app/models/tweet.rb
@@ -0,0 +1,7 @@
+class Tweet < ActiveRecord::Base
+ # Associations ----------------------------------------------
+ has_and_belongs_to_many :users
+
+ # Validations ----------------------------------------------
+ validates :username, :provider_id, presence: true, uniqueness: true
+end
diff --git a/app/models/user.rb b/app/models/user.rb
index acc1e86..54cf1ff 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1,13 +1,15 @@
class User < ActiveRecord::Base
+ # Associations ----------------------------------------------
+ has_and_belongs_to_many :instagrams
+ has_and_belongs_to_many :tweets
+ has_many :instagram_posts, through: :instagrams
- # Validations ----------------------------------------------
- # validates :email, presence: true
- # validates :username, presence: true
- validates :uid, presence: true
- validates :provider, presence: true
+ # Validations ----------------------------------------------
+ validates :username, :uid, :provider, presence: true
+ validates :username, :uid, uniqueness: true
- def self.find_or_create_from_omniauth_developer(auth_hash)
+ def self.find_or_create_from_omniauth(auth_hash)
uid = auth_hash[:uid]
provider = auth_hash[:provider]
diff --git a/app/views/feeds/index.html.erb b/app/views/feeds/index.html.erb
index 1d00cf6..a732502 100644
--- a/app/views/feeds/index.html.erb
+++ b/app/views/feeds/index.html.erb
@@ -1,7 +1,49 @@
-
I can haz feedz?
+
+
+ <% if session[:user_id].nil? %>
+
Choose Your Weapon
+ <%= link_to login_path(provider: :instagram) do %>
+
+ <% end %>
+ <%= link_to login_path(provider: :twitter) do %>
+
+ <% end %>
+ <% else %>
+ <% if @user %>
+
<%= @user.username %>
+ <% end %>
+ <%= link_to "Follow People", search_path, class: "btn btn-primary" %>
+
+ <%= link_to "Assasinate", people_path, class: "btn btn-primary" %>
-<%= link_to "Login", login_path, class: "btn btn-primary" %>
-<%= link_to "Logout", logout_path, method: :delete, class: "btn btn-danger" %>
-<% unless @user.nil? %>
- <%= @user.username %>
-<% end %>
+ <%= render partial: "instagrams/refresh_feed" %>
+
+ <% if @posts %>
+ <% @posts.each do |post| %>
+
+
+
+ <%= link_to image_tag(post["data"]["images"]["standard_resolution"]["url"]), post["data"]["link"] %>
+
+
Posted by: <%= post["data"]["user"]["username"] %>
+ <% unless post["data"]["caption"].nil? %>
+
<%= post["data"]["caption"]["text"] %>
+ <% end %>
+
<%= Time.at(post["data"]["created_time"].to_i).strftime("%m/%d/%Y at %I:%M%p") %>
+
+
+
+
+ <% end %>
+ <% end %>
+ <% end %>
+
+
+ <% if @user %>
+ <% @feed.each do |tweet| %>
+
<%= tweet.text %>
+ <%= tweet.created_at %>
+ <% end %>
+ <% end %>
+
+
diff --git a/app/views/feeds/people.html.erb b/app/views/feeds/people.html.erb
new file mode 100644
index 0000000..67834ee
--- /dev/null
+++ b/app/views/feeds/people.html.erb
@@ -0,0 +1,13 @@
+
+Assassinate
+
+<% unless session[:user_id].nil? %>
+ Targets
+ <% @people.each do |person| %>
+
+ <%= person.username %>
+ <%= image_tag(person.image_url) %>
+ <%= link_to "X", polymorphic_path(person.class.name.downcase, id: person.id), method: :delete, class: "btn btn-danger" %>
+
+ <% end %>
+<% end %>
diff --git a/app/views/feeds/search.html.erb b/app/views/feeds/search.html.erb
new file mode 100644
index 0000000..81771e4
--- /dev/null
+++ b/app/views/feeds/search.html.erb
@@ -0,0 +1,23 @@
+
+
+ <%= render partial: "shared/search_form",
+ locals: {
+ provider: :instagram,
+ url: search_instagram_url
+ } %>
+
+ <%= render partial: "shared/search_form",
+ locals: {
+ provider: :tweet,
+ url: search_twitter_url
+ } %>
+
+
+
+ <% if params[:instagram] %>
+ <%= render template: "instagrams/search", layout: false %>
+ <% elsif params[:tweet] %>
+ <%= render template: "tweets/search", layout: false %>
+ <% end %>
+
+
diff --git a/app/views/instagrams/_refresh_feed.html.erb b/app/views/instagrams/_refresh_feed.html.erb
new file mode 100644
index 0000000..421b7f8
--- /dev/null
+++ b/app/views/instagrams/_refresh_feed.html.erb
@@ -0,0 +1 @@
+<%= link_to "Refresh Instagram Feed", { controller: :instagram_posts, action: :create }, method: :post, class: "btn btn-primary" %>
diff --git a/app/views/instagrams/search.html.erb b/app/views/instagrams/search.html.erb
new file mode 100644
index 0000000..f752e0a
--- /dev/null
+++ b/app/views/instagrams/search.html.erb
@@ -0,0 +1,8 @@
+<% @users.each do |user| %>
+
+ Name: <%= user["full_name"] %>
+ Username: <%= user["username"] %>
+ <%= image_tag(user["profile_picture"]) %>
+ <%= link_to "+", { controller: :instagrams, action: :create, instagram: { username: user["username"], provider_id: user["id"], image_url: user["profile_picture"] } }, method: :post, class: "btn btn-primary" %>
+
+<% end %>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index b323c2a..698fe84 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -1,14 +1,23 @@
- C3ProjectsSeemore
+ Ninja Feed
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
+
+ <%= render "shared/nav" %>
+ <% if flash[:error] %>
+ <%= flash[:error] %>
+ <% end %>
-<%= yield %>
-
+ <% if flash[:alert] %>
+ <%= flash[:alert] %>
+ <% end %>
+
+ <%= yield %>
+
diff --git a/app/views/shared/_nav.html.erb b/app/views/shared/_nav.html.erb
new file mode 100644
index 0000000..1227da4
--- /dev/null
+++ b/app/views/shared/_nav.html.erb
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/app/views/shared/_search_form.html.erb b/app/views/shared/_search_form.html.erb
new file mode 100644
index 0000000..ff7c9c2
--- /dev/null
+++ b/app/views/shared/_search_form.html.erb
@@ -0,0 +1,7 @@
+<%= form_for provider, url: url, html: { class: "form-inline" } do |f| %>
+ <%= f.label :username, "Search #{provider.to_s.titlecase} Users" %>
+ <%= f.text_field :username, placeholder: "Search Users", class: "form-control form-group" %>
+ <%= button_tag(type: 'submit', class: "btn btn-primary search") do %>
+
+ <% end %>
+<% end %>
diff --git a/app/views/tweets/search.html.erb b/app/views/tweets/search.html.erb
new file mode 100644
index 0000000..9727d65
--- /dev/null
+++ b/app/views/tweets/search.html.erb
@@ -0,0 +1,8 @@
+<% @users.each do |user| %>
+
+ Name: <%= user.name %>
+ Username: <%= user.screen_name %>
+ <%= image_tag(user.profile_image_url(size = :bigger)) %>
+ <%= link_to "+", { controller: :tweets, action: :create, tweet: { username: user.screen_name, provider_id: user.id, image_url: user.profile_image_url(size = :bigger) } }, method: :post, class: "btn btn-primary" %>
+
+<% end %>
diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb
index 482aac0..caa7c91 100644
--- a/config/initializers/omniauth.rb
+++ b/config/initializers/omniauth.rb
@@ -1,3 +1,4 @@
Rails.application.config.middleware.use OmniAuth::Builder do
provider :developer
+ provider :instagram, ENV['INSTAGRAM_ID'], ENV['INSTAGRAM_SECRET']
end
diff --git a/config/routes.rb b/config/routes.rb
index f34dcf1..b2d55ae 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,14 +1,26 @@
Rails.application.routes.draw do
+
root "feeds#index"
- get "auth/:provider/callback" => 'sessions#create'
+ get "search/twitter" => 'tweets#search'
+ post "search/twitter", to: "tweets#search"
- # Below allows you to login with developer.
- # Will need routes for each third party you can login through?
- get "auth/developer" => 'sessions#create', as: 'login'
+ get "search/instagram" => 'instagrams#search'
+ post "search/instagram", to: "instagrams#search"
- delete "logout" => 'sessions#destroy'
+ get "/search", to: "feeds#search", as: "search"
+ get "/people", to: "feeds#people", as: "people"
+
+ get "auth/:provider/callback" => 'sessions#create'
# post is here for OmniAuth developer strategy
post "auth/:provider/callback" => 'sessions#create'
+ get "auth/:provider" => 'sessions#create', as: 'login'
+ delete "logout" => 'sessions#destroy'
+
+ resources :instagrams, only: [:create, :destroy]
+ resources :tweets, only: [:create, :destroy]
+ resources :instagram_posts, only: [:create]
+
+
end
diff --git a/db/migrate/20150805222548_create_instagrams.rb b/db/migrate/20150805222548_create_instagrams.rb
new file mode 100644
index 0000000..5a9abc5
--- /dev/null
+++ b/db/migrate/20150805222548_create_instagrams.rb
@@ -0,0 +1,8 @@
+class CreateInstagrams < ActiveRecord::Migration
+ def change
+ create_table :instagrams do |t|
+
+ t.timestamps null: false
+ end
+ end
+end
diff --git a/db/migrate/20150805222847_add_columns_to_instagrams.rb b/db/migrate/20150805222847_add_columns_to_instagrams.rb
new file mode 100644
index 0000000..cc98015
--- /dev/null
+++ b/db/migrate/20150805222847_add_columns_to_instagrams.rb
@@ -0,0 +1,9 @@
+class AddColumnsToInstagrams < ActiveRecord::Migration
+ def change
+ add_column :instagrams, :username, :string
+ add_column :instagrams, :provider_id, :string
+
+ change_column :instagrams, :username, :string, :null => false
+ change_column :instagrams, :provider_id, :string, :null => false
+ end
+end
diff --git a/db/migrate/20150806212209_create_tweets.rb b/db/migrate/20150806212209_create_tweets.rb
new file mode 100644
index 0000000..5b5da45
--- /dev/null
+++ b/db/migrate/20150806212209_create_tweets.rb
@@ -0,0 +1,10 @@
+class CreateTweets < ActiveRecord::Migration
+ def change
+ create_table :tweets do |t|
+ t.string :username, null: false
+ t.string :provider_id, null: false
+
+ t.timestamps null: false
+ end
+ end
+end
diff --git a/db/migrate/20150806213716_create_join_table.rb b/db/migrate/20150806213716_create_join_table.rb
new file mode 100644
index 0000000..bbf4f05
--- /dev/null
+++ b/db/migrate/20150806213716_create_join_table.rb
@@ -0,0 +1,8 @@
+class CreateJoinTable < ActiveRecord::Migration
+ def change
+ create_join_table :instagrams, :users do |t|
+ t.index :instagram_id
+ t.index :user_id
+ end
+ end
+end
diff --git a/db/migrate/20150806214114_create_join_table_tweets_users.rb b/db/migrate/20150806214114_create_join_table_tweets_users.rb
new file mode 100644
index 0000000..8825f87
--- /dev/null
+++ b/db/migrate/20150806214114_create_join_table_tweets_users.rb
@@ -0,0 +1,8 @@
+class CreateJoinTableTweetsUsers < ActiveRecord::Migration
+ def change
+ create_join_table :tweets, :users do |t|
+ t.index :tweet_id
+ t.index :user_id
+ end
+ end
+end
diff --git a/db/migrate/20150807203523_add_image_url_to_tweets.rb b/db/migrate/20150807203523_add_image_url_to_tweets.rb
new file mode 100644
index 0000000..97aa8bc
--- /dev/null
+++ b/db/migrate/20150807203523_add_image_url_to_tweets.rb
@@ -0,0 +1,5 @@
+class AddImageUrlToTweets < ActiveRecord::Migration
+ def change
+ add_column :tweets, :image_url, :string
+ end
+end
diff --git a/db/migrate/20150807203555_add_image_url_to_instagrams.rb b/db/migrate/20150807203555_add_image_url_to_instagrams.rb
new file mode 100644
index 0000000..bb1e0fe
--- /dev/null
+++ b/db/migrate/20150807203555_add_image_url_to_instagrams.rb
@@ -0,0 +1,5 @@
+class AddImageUrlToInstagrams < ActiveRecord::Migration
+ def change
+ add_column :instagrams, :image_url, :string
+ end
+end
diff --git a/db/migrate/20150809210224_create_instagram_posts.rb b/db/migrate/20150809210224_create_instagram_posts.rb
new file mode 100644
index 0000000..e506b0a
--- /dev/null
+++ b/db/migrate/20150809210224_create_instagram_posts.rb
@@ -0,0 +1,11 @@
+class CreateInstagramPosts < ActiveRecord::Migration
+ def change
+ create_table :instagram_posts do |t|
+ t.string :post_id, null: false
+ t.integer :instagram_id, null: false
+ t.index :instagram_id
+
+ t.timestamps null: false
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 4e0dbb4..916f203 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,48 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20150804213804) do
+ActiveRecord::Schema.define(version: 20150809210224) do
+
+ create_table "instagram_posts", force: :cascade do |t|
+ t.string "post_id", null: false
+ t.integer "instagram_id", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+ add_index "instagram_posts", ["instagram_id"], name: "index_instagram_posts_on_instagram_id"
+
+ create_table "instagrams", force: :cascade do |t|
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.string "username", null: false
+ t.string "provider_id", null: false
+ t.string "image_url"
+ end
+
+ create_table "instagrams_users", id: false, force: :cascade do |t|
+ t.integer "instagram_id", null: false
+ t.integer "user_id", null: false
+ end
+
+ add_index "instagrams_users", ["instagram_id"], name: "index_instagrams_users_on_instagram_id"
+ add_index "instagrams_users", ["user_id"], name: "index_instagrams_users_on_user_id"
+
+ create_table "tweets", force: :cascade do |t|
+ t.string "username", null: false
+ t.string "provider_id", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.string "image_url"
+ end
+
+ create_table "tweets_users", id: false, force: :cascade do |t|
+ t.integer "tweet_id", null: false
+ t.integer "user_id", null: false
+ end
+
+ add_index "tweets_users", ["tweet_id"], name: "index_tweets_users_on_tweet_id"
+ add_index "tweets_users", ["user_id"], name: "index_tweets_users_on_user_id"
create_table "users", force: :cascade do |t|
t.string "username"
diff --git a/lib/twit.rb b/lib/twit.rb
new file mode 100644
index 0000000..ff8858f
--- /dev/null
+++ b/lib/twit.rb
@@ -0,0 +1,13 @@
+class Twit
+ attr_reader :client
+
+ def initialize
+ @client = Twitter::REST::Client.new do |config|
+ config.consumer_key = ENV['TWITTER_CONSUMER_KEY']
+ config.consumer_secret = ENV['TWITTER_CONSUMER_SECRET']
+ config.access_token = ENV['TWITTER_ACCESS_TOKEN']
+ config.access_token_secret = ENV['TWITTER_ACCESS_TOKEN_SECRET']
+ end
+ end
+
+end
diff --git a/spec/controllers/instagram_posts_controller_spec.rb b/spec/controllers/instagram_posts_controller_spec.rb
new file mode 100644
index 0000000..4821df1
--- /dev/null
+++ b/spec/controllers/instagram_posts_controller_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe InstagramPostsController, type: :controller do
+
+end
diff --git a/spec/controllers/instagrams_controller_spec.rb b/spec/controllers/instagrams_controller_spec.rb
new file mode 100644
index 0000000..a3b2e17
--- /dev/null
+++ b/spec/controllers/instagrams_controller_spec.rb
@@ -0,0 +1,56 @@
+require 'rails_helper'
+require 'pry'
+
+RSpec.describe InstagramsController, type: :controller do
+
+ describe "POST #create" do
+ context "valid params" do
+ before :each do
+ @user = create :user
+ session[:user_id] = @user.id
+ post :create, instagram: attributes_for(:instagram)
+ end
+
+ it "creates an instagram record" do
+ expect(Instagram.count).to eq(1)
+ expect(Instagram.first.username).to eq("Ada")
+ end
+
+ it "associates with a user" do
+ expect(Instagram.first.user_ids).to include(@user.id)
+ end
+
+ it "redirects to root_path" do
+ expect(response).to redirect_to(root_path)
+ expect(response).to have_http_status(302)
+ end
+
+
+ end
+
+ context "invalid params" do
+ before :each do
+ user = create :user
+ session[:user_id] = user.id
+ post :create, instagram: attributes_for(:instagram, username: nil)
+ end
+
+ it "invalid attributes fail validations" do
+ bad_instagram_record = Instagram.create(attributes_for(:instagram, username: nil, user_ids: [1]))
+ expect(bad_instagram_record).to_not be_valid
+ expect(bad_instagram_record.errors).to include(:username)
+ end
+
+ it "does not create a instagram record" do
+ expect(Instagram.count).to eq 0
+ end
+
+ it "renders the feeds/search view" do
+ expect(response).to render_template("feeds/search")
+ end
+ end
+
+
+ end# post create
+
+end# controller
diff --git a/spec/controllers/tweets_controller_spec.rb b/spec/controllers/tweets_controller_spec.rb
new file mode 100644
index 0000000..fc54c22
--- /dev/null
+++ b/spec/controllers/tweets_controller_spec.rb
@@ -0,0 +1,49 @@
+require 'rails_helper'
+
+RSpec.describe TweetsController, type: :controller do
+ describe "POST #create" do
+ context "valid params" do
+ before :each do
+ @user = create :user
+ session[:user_id] = @user.id
+ post :create, tweet: attributes_for(:tweet)
+ end
+
+ it "creates a twitter record" do
+ expect(Tweet.count).to eq(1)
+ expect(Tweet.first.username).to eq("Ada")
+ end
+
+ it "associates with a user" do
+ expect(Tweet.first.user_ids).to include(@user.id)
+ end
+
+ it "redirects to root_path" do
+ expect(response).to redirect_to(root_path)
+ expect(response).to have_http_status(302)
+ end
+ end
+
+ context "invalid params" do
+ before :each do
+ user = create :user
+ session[:user_id] = user.id
+ post :create, tweet: attributes_for(:tweet, username: nil)
+ end
+
+ it "invalid attributes fail validations" do
+ bad_tweet_record = Tweet.create(attributes_for(:tweet, username: nil, user_ids: [1]))
+ expect(bad_tweet_record).to_not be_valid
+ expect(bad_tweet_record.errors).to include(:username)
+ end
+
+ it "does not create a tweet record" do
+ expect(Tweet.count).to eq 0
+ end
+
+ it "renders the feeds/search view" do
+ expect(response).to render_template("feeds/search")
+ end
+ end
+ end
+end
diff --git a/spec/factories.rb b/spec/factories.rb
index e69de29..46e2bd9 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -0,0 +1,23 @@
+FactoryGirl.define do factory :instagram_post do
+
+ end
+
+ factory :user do
+ email "a@b.com"
+ username "Ada"
+ uid "12345"
+ provider "developer"
+ end
+
+ factory :instagram do
+ username "Ada"
+ provider_id "1357"
+ user_ids [1, 2]
+ end
+
+ factory :tweet do
+ username "Ada"
+ provider_id "1357"
+ user_ids [1, 2]
+ end
+end
diff --git a/spec/helpers/feeds_helper_spec.rb b/spec/helpers/feeds_helper_spec.rb
deleted file mode 100644
index 89a42c0..0000000
--- a/spec/helpers/feeds_helper_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require 'rails_helper'
-
-# Specs in this file have access to a helper object that includes
-# the FeedsHelper. For example:
-#
-# describe FeedsHelper do
-# describe "string concat" do
-# it "concats two strings with spaces" do
-# expect(helper.concat_strings("this","that")).to eq("this that")
-# end
-# end
-# end
-RSpec.describe FeedsHelper, type: :helper do
- pending "add some examples to (or delete) #{__FILE__}"
-end
diff --git a/spec/models/instagram_post_spec.rb b/spec/models/instagram_post_spec.rb
new file mode 100644
index 0000000..7cc6155
--- /dev/null
+++ b/spec/models/instagram_post_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe InstagramPost, type: :model do
+ pending "add some examples to (or delete) #{__FILE__}"
+end
diff --git a/spec/models/instagram_spec.rb b/spec/models/instagram_spec.rb
new file mode 100644
index 0000000..5529e62
--- /dev/null
+++ b/spec/models/instagram_spec.rb
@@ -0,0 +1,7 @@
+require 'rails_helper'
+
+RSpec.describe Instagram, type: :model do
+
+ it_behaves_like "a provider"
+
+end
diff --git a/spec/models/tweet_spec.rb b/spec/models/tweet_spec.rb
new file mode 100644
index 0000000..86bed32
--- /dev/null
+++ b/spec/models/tweet_spec.rb
@@ -0,0 +1,7 @@
+require 'rails_helper'
+
+RSpec.describe Tweet, type: :model do
+
+ it_behaves_like "a provider"
+
+end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 76a5223..c578de2 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1,58 +1,94 @@
require 'rails_helper'
RSpec.describe User, type: :model do
- let(:user) {
- User.new(
- email: "a@b.com",
- username: "Ada",
- uid: "1234",
- provider: "developer"
- )
- }
-
- describe "validations" do
- it "is valid" do
- expect(user).to be_valid
- end
- # it "requires an email" do
- # user.email = nil
- # expect(user).to be_invalid
- # end
+ context "user logging in with developer 'strategy'" do
+ describe "validations" do
+ let(:dev_user) { build :user }
+
+ it "is valid" do
+ expect(dev_user).to be_valid
+ end
+
+ it "requires a username" do
+ dev_user.username = nil
+ expect(dev_user).to be_invalid
+ end
- # it "requires a username" do
- # user.username = nil
- # expect(user).to be_invalid
- # end
+ it "requires a uid" do
+ dev_user.uid = nil
+ expect(dev_user).to be_invalid
+ end
- it "requires a uid" do
- user.uid = nil
- expect(user).to be_invalid
+ it "requires a provider" do
+ dev_user.provider = nil
+ expect(dev_user).to be_invalid
+ end
end
- it "requires a provider" do
- user.provider = nil
- expect(user).to be_invalid
+
+ describe ".initialize_from_omniauth" do
+ let(:user) {
+ User.find_or_create_from_omniauth(OmniAuth.config.mock_auth[:developer])
+ }
+
+ it "creates a valid user" do
+ expect(user).to be_valid
+ end
+
+ context "when it's invalid" do
+ it "returns nil" do
+ user = User.find_or_create_from_omniauth({
+ uid: "123", info: { }
+ })
+ expect(user).to be_nil
+ end
+ end
end
end
+ context "user logging in with instagram" do
+ describe "validations" do
+ let(:ig_user) { build :user, provider: :instagram }
- describe ".initialize_from_omniauth" do
- let(:user) {
- User.find_or_create_from_omniauth(OmniAuth.config.mock_auth[:developer])
- }
+ it "is valid" do
+ expect(ig_user).to be_valid
+ end
- it "creates a valid user" do
- expect(user).to be_valid
+ it "requires a username" do
+ ig_user.username = nil
+ expect(ig_user).to be_invalid
+ end
+
+ it "requires a uid" do
+ ig_user.uid = nil
+ expect(ig_user).to be_invalid
+ end
+
+ it "requires a provider" do
+ ig_user.provider = nil
+ expect(ig_user).to be_invalid
+ end
end
- # context "when it's invalid" do
- # it "returns nil" do
- # user = User.find_or_create_from_omniauth({
- # "uid" => "123", "info" => {}
- # })
- # expect(user).to be_nil
- # end
- # end
+ describe ".initialize_from_omniauth" do
+ let(:user) {
+ User.find_or_create_from_omniauth(OmniAuth.config.mock_auth[:instagram])
+ }
+
+ it "creates a valid user" do
+ expect(user).to be_valid
+ end
+
+ context "when it's invalid" do
+ it "returns nil" do
+ user = User.find_or_create_from_omniauth({
+ uid: "123", info: { }
+ })
+ expect(user).to be_nil
+ end
+ end
+ end
end
+
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index d5992da..b24ca8c 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,5 +1,6 @@
require 'factory_girl'
require 'simplecov'
+require 'rails_helper'
SimpleCov.start 'rails'
# This file was generated by the `rails generate rspec:install` command. Conventionally, all
@@ -37,11 +38,18 @@
OmniAuth.config.mock_auth[:developer] = OmniAuth::AuthHash.new({
:provider => 'developer',
- :uid => '123545',
- info: {email: "a@b.com", nickname: "Ada"}
+ :uid => '12345',
+ info: {email: "a@b.com", name: "Ada"}
+ })
+ OmniAuth.config.mock_auth[:instagram] = OmniAuth::AuthHash.new({
+ :provider => 'instagram',
+ :uid => '12345',
+ info: {email: "a@b.com", name: "Ada"}
})
end
+ Dir["./spec/support/**/*.rb"].sort.each { |f| require f}
+
config.include FactoryGirl::Syntax::Methods
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
diff --git a/spec/support/provider_spec.rb b/spec/support/provider_spec.rb
new file mode 100644
index 0000000..c17e0d1
--- /dev/null
+++ b/spec/support/provider_spec.rb
@@ -0,0 +1,49 @@
+require 'spec_helper'
+
+RSpec.shared_examples "a provider" do
+
+ describe "model validations" do
+ before :each do
+ user1 = create :user
+ user2 = create :user, username: "Ada2", uid: "34524"
+ end
+
+ it "requires a username" do
+ provider = build described_class, username: nil
+
+ expect(provider).not_to be_valid
+ expect(provider.errors.keys).to include(:username)
+ end
+
+ it "username must be unique" do
+ create described_class
+ provider2 = build described_class
+
+ expect(provider2).not_to be_valid
+ expect(described_class.count).to be 1
+ expect(provider2.errors.keys).to include(:username)
+ end
+
+ it "requires a provider_id" do
+ provider = build described_class, provider_id: nil
+
+ expect(provider).not_to be_valid
+ expect(provider.errors.keys).to include(:provider_id)
+ end
+
+ it "provider_id must be unique" do
+ create described_class
+ provider2 = build described_class
+
+ expect(provider2).not_to be_valid
+ expect(described_class.count).to be 1
+ expect(provider2.errors.keys).to include(:provider_id)
+ end
+
+ it "validates a valid record" do
+ provider = create described_class
+ expect(described_class.count).to be 1
+ expect(described_class.all).to include(provider)
+ end
+ end
+end