diff --git a/Gemfile b/Gemfile index 5533ad5..ff7a0a9 100644 --- a/Gemfile +++ b/Gemfile @@ -6,10 +6,11 @@ gem "rails-api" gem "faraday" gem "figaro" gem "jwt" -gem 'rack-cors', require: 'rack/cors' -gem 'active_model_serializers', '~> 0.10.0' +gem "rack-cors", require: "rack/cors" +gem "active_model_serializers" gem "cancancan", "~> 1.10" gem "faker" +gem "facebook-account-kit" gem 'globalize', '~> 5.0.0' group :production do @@ -27,6 +28,6 @@ group :development, :test do gem "shoulda-matchers", "~> 3.1" gem "simplecov" gem "coveralls", require: false - gem "vcr" gem "webmock" + gem "rubocop" end diff --git a/Gemfile.lock b/Gemfile.lock index 151d12a..99c548f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -43,6 +43,7 @@ GEM tzinfo (~> 1.1) addressable (2.4.0) arel (6.0.3) + ast (2.3.0) builder (3.2.2) cancancan (1.15.0) coderay (1.1.1) @@ -59,12 +60,13 @@ GEM diff-lcs (1.2.5) docile (1.1.5) erubis (2.7.0) - factory_girl (4.5.0) + facebook-account-kit (1.0.0) + factory_girl (4.7.0) activesupport (>= 3.0.0) - factory_girl_rails (4.6.0) - factory_girl (~> 4.5.0) + factory_girl_rails (4.7.0) + factory_girl (~> 4.7.0) railties (>= 3.0.0) - faker (1.6.3) + faker (1.6.6) i18n (~> 0.5) faraday (0.9.2) multipart-post (>= 1.2, < 3) @@ -97,7 +99,10 @@ GEM multipart-post (2.0.0) nokogiri (1.6.8.1) mini_portile2 (~> 2.1.0) + parser (2.3.1.4) + ast (~> 2.2) pg (0.19.0) + powerpack (0.1.1) pry (0.10.4) coderay (~> 1.1.0) method_source (~> 0.8.1) @@ -140,24 +145,32 @@ GEM activesupport (= 4.2.5) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) + rainbow (2.1.0) rake (11.3.0) - rspec-core (3.4.4) - rspec-support (~> 3.4.0) - rspec-expectations (3.4.0) + rspec-core (3.5.4) + rspec-support (~> 3.5.0) + rspec-expectations (3.5.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.4.0) - rspec-mocks (3.4.1) + rspec-support (~> 3.5.0) + rspec-mocks (3.5.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.4.0) - rspec-rails (3.4.2) - actionpack (>= 3.0, < 4.3) - activesupport (>= 3.0, < 4.3) - railties (>= 3.0, < 4.3) - rspec-core (~> 3.4.0) - rspec-expectations (~> 3.4.0) - rspec-mocks (~> 3.4.0) - rspec-support (~> 3.4.0) - rspec-support (3.4.1) + rspec-support (~> 3.5.0) + rspec-rails (3.5.2) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 3.5.0) + rspec-expectations (~> 3.5.0) + rspec-mocks (~> 3.5.0) + rspec-support (~> 3.5.0) + rspec-support (3.5.0) + rubocop (0.44.1) + parser (>= 2.3.1.1, < 3.0) + powerpack (~> 0.1) + rainbow (>= 1.99.1, < 3.0) + ruby-progressbar (~> 1.7) + unicode-display_width (~> 1.0, >= 1.0.1) + ruby-progressbar (1.8.1) safe_yaml (1.0.4) shoulda-matchers (3.1.1) activesupport (>= 4.0.0) @@ -167,7 +180,8 @@ GEM simplecov-html (~> 0.10.0) simplecov-html (0.10.0) slop (3.6.0) - spring (1.7.2) + spring (2.0.0) + activesupport (>= 4.2) sprockets (3.7.0) concurrent-ruby (~> 1.0) rack (> 1, < 3) @@ -175,7 +189,7 @@ GEM actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) - sqlite3 (1.3.11) + sqlite3 (1.3.12) term-ansicolor (1.4.0) tins (~> 1.0) thor (0.19.1) @@ -183,7 +197,7 @@ GEM tins (1.12.0) tzinfo (1.2.2) thread_safe (~> 0.1) - vcr (3.0.3) + unicode-display_width (1.1.1) webmock (2.1.0) addressable (>= 2.3.6) crack (>= 0.3.2) @@ -193,10 +207,11 @@ PLATFORMS ruby DEPENDENCIES - active_model_serializers (~> 0.10.0) + active_model_serializers cancancan (~> 1.10) coveralls database_cleaner + facebook-account-kit factory_girl_rails faker faraday @@ -210,15 +225,15 @@ DEPENDENCIES rails-api rails_12factor rspec-rails + rubocop shoulda-matchers (~> 3.1) simplecov spring sqlite3 - vcr webmock RUBY VERSION ruby 2.2.3p173 BUNDLED WITH - 1.12.5 + 1.13.2 diff --git a/app/controllers/api/v1/auth_controller.rb b/app/controllers/api/v1/auth_controller.rb index 4c50e53..b2b1987 100644 --- a/app/controllers/api/v1/auth_controller.rb +++ b/app/controllers/api/v1/auth_controller.rb @@ -4,14 +4,8 @@ class AuthController < ApplicationController before_action :authenticate, only: :logout def login - parameters = { - fields: FIELDS, - access_token: auth_params[:access_token] - } - - http_client = Http.new(FB_URL) - response, response_status = http_client.get_request(parameters) - message, status = authenticate_user(response, response_status) + account_kit = AccountKit.new(params[:access_token]) + message, status = account_kit.get_message_and_status render json: message, status: status end @@ -19,21 +13,6 @@ def logout ExpiredToken.create(token: token) render json: { Status: "Logged out" }, status: 200 end - - private - - def auth_params - params.permit(:access_token) - end - - def authenticate_user(response, status) - return( - [{ error: response["error"]["message"] }, 401] - ) unless status == "200" - user = User.find_or_create_user(response) - token = Authenticate.create_token(fb_id: user.fb_id, email: user.email) - [{ token: token, user: user }, 200] - end end end end diff --git a/app/controllers/api/v1/http.rb b/app/controllers/api/v1/http.rb deleted file mode 100644 index 9454704..0000000 --- a/app/controllers/api/v1/http.rb +++ /dev/null @@ -1,17 +0,0 @@ -require "net/http" -module Api - module V1 - class Http - attr_reader :uri - def initialize(uri) - @uri = URI(uri) - end - - def get_request(params = {}) - uri.query = URI.encode_www_form(params) if params.present? - response = Net::HTTP.get_response(uri) - [JSON.parse(response.body), response.code] - end - end - end -end diff --git a/app/controllers/api/v1/proverbs_controller.rb b/app/controllers/api/v1/proverbs_controller.rb index 9985114..2519a2c 100644 --- a/app/controllers/api/v1/proverbs_controller.rb +++ b/app/controllers/api/v1/proverbs_controller.rb @@ -52,6 +52,37 @@ def proverb_params params.require(:proverb).permit(:body, :locale, all_tags: []) end + def valid_translation? + translations = params[:proverb][:translations] + if translations + return true if translations[0] == "" + translations.all? do |translation| + Proverb.new(translation.symbolize_keys.merge( + user_id: current_user.id + )).valid? + end + else + true + end + end + + def create_translations + translations = params[:proverb][:translations] + tags = @proverb.tags.map(&:name) + if translations + return true if translations[0] == "" + translations.each do |translation| + Proverb.create(translation.symbolize_keys.merge( + root_id: @proverb.id, + all_tags: tags, + user_id: current_user.id + )) + end + else + true + end + end + def check_tags unless proverb_params["all_tags"] && proverb_params["all_tags"].is_a?(Array) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index cd62c78..0cd8b8a 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -39,7 +39,7 @@ def token_has_expired(token) def set_payload(status, payload) if status user = payload - @current_user = User.find_by(fb_id: user["fb_id"]) + @current_user = User.find_by(kit_id: user["kit_id"]) activate(@current_user) else render json: payload, status: 401 diff --git a/app/models/user.rb b/app/models/user.rb index dd99635..cf28bfd 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,16 +1,14 @@ class User < ActiveRecord::Base has_many :proverbs - validates :email, :fb_id, :first_name, :last_name, presence: true - validates :email, uniqueness: true - enum user_type: { regular: 0, moderator: 1, admin: 2 } - def self.find_or_create_user(auth_params) - find_or_create_by(fb_id: auth_params["id"]) do |user| - user.first_name = auth_params["first_name"] - user.last_name = auth_params["last_name"] - user.email = auth_params["email"] + def self.find_or_create_user(user_info) + user_info = HashWithIndifferentAccess.new(user_info) + + find_or_create_by(kit_id: user_info["id"]) do |user| + user.phone_number = user_info["phone"]["number"] if user_info["phone"] + user.email = user_info["email"]["address"] if user_info["email"] end end end diff --git a/app/services/api/v1/account_kit.rb b/app/services/api/v1/account_kit.rb new file mode 100644 index 0000000..88eb0be --- /dev/null +++ b/app/services/api/v1/account_kit.rb @@ -0,0 +1,30 @@ +module Api + module V1 + class AccountKit + attr_reader :access_token + + def initialize(access_token) + @access_token = access_token + end + + def get_message_and_status + begin + user_account = Facebook::AccountKit::UserAccount.new(access_token) + user = User.find_or_create_user(user_account.fetch_user_info) + return [{ token: get_token(user), user: user }, 200] + rescue + return [{ error: "Invalid Access Token" }, "400"] + end + end + + private + + def get_token(user_info) + user_params = {} + user_params[:email] = user_info.email if user_info.email + user_params[:phone_number] = user_info.phone_number if user_info.phone_number + Authenticate.create_token(user_params.merge(kit_id: user_info.kit_id)) + end + end + end +end diff --git a/config/application.rb b/config/application.rb index 5f07051..7f46dbf 100644 --- a/config/application.rb +++ b/config/application.rb @@ -23,9 +23,9 @@ class Application < Rails::Application config.i18n.fallbacks = true config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '*.{rb,yml}').to_s] config.middleware.insert_before 0, "Rack::Cors" do - allow do - origins '*' - resource '*', :headers => :any, :methods => [:get, :post, :put, :delete, :options] + allow do + origins "*" + resource "*", headers: :any, methods: [:get, :post, :put, :delete, :options] end end # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. @@ -39,8 +39,8 @@ class Application < Rails::Application # Do not swallow errors in after_commit/after_rollback callbacks. config.middleware.insert_before 0, "Rack::Cors" do allow do - origins '*' - resource '*', headers: :any, methods: [:get, :post, :options] + origins "*" + resource "*", headers: :any, methods: [:get, :post, :options] end end config.active_record.raise_in_transactional_callbacks = true diff --git a/config/initializers/account_kit.rb b/config/initializers/account_kit.rb new file mode 100644 index 0000000..a47bf5d --- /dev/null +++ b/config/initializers/account_kit.rb @@ -0,0 +1,7 @@ +require "facebook/account_kit" + +Facebook::AccountKit.config do |c| + c.account_kit_version = "v1.0" + c.account_kit_app_secret = ENV["kit_app_secret"] + c.facebook_app_id = ENV["kit_app_id"] +end diff --git a/db/migrate/20161009114624_add_kit_details_to_users.rb b/db/migrate/20161009114624_add_kit_details_to_users.rb new file mode 100644 index 0000000..ee112a0 --- /dev/null +++ b/db/migrate/20161009114624_add_kit_details_to_users.rb @@ -0,0 +1,6 @@ +class AddKitDetailsToUsers < ActiveRecord::Migration + def change + add_column :users, :kit_id, :string + add_column :users, :phone_number, :string + end +end diff --git a/db/migrate/20161018111235_remove_face_book_details_from_users.rb b/db/migrate/20161018111235_remove_face_book_details_from_users.rb new file mode 100644 index 0000000..7519f21 --- /dev/null +++ b/db/migrate/20161018111235_remove_face_book_details_from_users.rb @@ -0,0 +1,8 @@ +class RemoveFaceBookDetailsFromUsers < ActiveRecord::Migration + def change + remove_column :users, :username, :string + remove_column :users, :first_name, :string + remove_column :users, :last_name, :string + remove_column :users, :fb_id, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index 3fc691d..7a597c0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20161015103413) do +ActiveRecord::Schema.define(version: 20161018111235) do create_table "expired_tokens", force: :cascade do |t| t.string "token" @@ -56,13 +56,11 @@ create_table "users", force: :cascade do |t| t.string "email" - t.string "username" - t.string "first_name" - t.string "last_name" - t.string "fb_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.integer "user_type", default: 0 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "user_type", default: 0 + t.string "kit_id" + t.string "phone_number" end end diff --git a/spec/factories/taggings.rb b/spec/factories/taggings.rb index abf64a7..0d98d9b 100644 --- a/spec/factories/taggings.rb +++ b/spec/factories/taggings.rb @@ -3,5 +3,4 @@ # proverb tag end - end diff --git a/spec/factories/tags.rb b/spec/factories/tags.rb index 1cda84a..c50df25 100644 --- a/spec/factories/tags.rb +++ b/spec/factories/tags.rb @@ -2,5 +2,4 @@ factory :tag do name "MyString" end - end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index f71312e..1ffc31a 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -1,9 +1,7 @@ FactoryGirl.define do factory :user do email { Faker::Internet.free_email } - username { Faker::Name.name } - first_name { Faker::Name.first_name } - last_name { Faker::Name.last_name } - fb_id Faker::Number.digit + phone_number { Faker::PhoneNumber.phone_number } + kit_id { Faker::Number.digit } end end diff --git a/spec/fixtures/vcr_cassettes/synopsis.yml b/spec/fixtures/vcr_cassettes/synopsis.yml deleted file mode 100644 index 8ffe61c..0000000 --- a/spec/fixtures/vcr_cassettes/synopsis.yml +++ /dev/null @@ -1,56 +0,0 @@ ---- -http_interactions: -- request: - method: get - uri: https://graph.facebook.com/me?access_token=EAAH6msXVZCB0BAHqwjgc829cZAZAg6Ymua77S9rkmkLDvr701mavIxjZBsGnihhJ5roGcY2vTCWb8nmi78LNk4NmNkgAuSK660oHmWkKNdXRAIIPy7qDEugpt78VvGvzzpFeOxc2t9xsZBN4viopXh2utRfIZB1WEZD&fields=id,email,first_name,last_name - body: - encoding: US-ASCII - string: '' - headers: - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - Accept: - - "*/*" - User-Agent: - - Ruby - Host: - - graph.facebook.com - response: - status: - code: 200 - message: OK - headers: - Access-Control-Allow-Origin: - - "*" - Etag: - - '"599dda6ff42d02ded9d194d9b7212cfe1550461c"' - Pragma: - - no-cache - Cache-Control: - - private, no-cache, no-store, must-revalidate - Facebook-Api-Version: - - v2.1 - Expires: - - Sat, 01 Jan 2000 00:00:00 GMT - Content-Type: - - application/json; charset=UTF-8 - X-Fb-Trace-Id: - - HaGQTUKfWB2 - X-Fb-Rev: - - '2516044' - Vary: - - Accept-Encoding - X-Fb-Debug: - - ZMPZAQENZxFhwHbPpR66udOR6xY9M+3VdYMLxOINwp6H8HQLCR5b4YCNoNddtrifNQy3Xzv7vRobzEXlmTmHbA== - Date: - - Fri, 19 Aug 2016 10:45:47 GMT - Connection: - - keep-alive - Content-Length: - - '110' - body: - encoding: ASCII-8BIT - string: '{"id":"10205588454088320","email":"tijesunimipeters\u0040gmail.com","first_name":"Tijesunimi","last_name":"Peters"}' - http_version: - recorded_at: Fri, 19 Aug 2016 10:45:47 GMT -recorded_with: VCR 3.0.3 diff --git a/spec/fixtures/vcr_cassettes/token_invalid.yml b/spec/fixtures/vcr_cassettes/token_invalid.yml deleted file mode 100644 index a0f2f75..0000000 --- a/spec/fixtures/vcr_cassettes/token_invalid.yml +++ /dev/null @@ -1,52 +0,0 @@ ---- -http_interactions: -- request: - method: get - uri: https://graph.facebook.com/me?access_token=giberrish&fields=id,email,first_name,last_name - body: - encoding: US-ASCII - string: '' - headers: - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - Accept: - - "*/*" - User-Agent: - - Ruby - Host: - - graph.facebook.com - response: - status: - code: 400 - message: Bad Request - headers: - Www-Authenticate: - - OAuth "Facebook Platform" "invalid_token" "Invalid OAuth access token." - Access-Control-Allow-Origin: - - "*" - Pragma: - - no-cache - Cache-Control: - - no-store - Expires: - - Sat, 01 Jan 2000 00:00:00 GMT - Content-Type: - - application/json; charset=UTF-8 - X-Fb-Trace-Id: - - BmXUehE3uug - X-Fb-Rev: - - '2520541' - X-Fb-Debug: - - yT3Sc3o3YxcVTB5v7BD17b8mKPz5APwKFR1fztiF4Qq7ILYEpbBcc0ThLB5u9zoHrdvdvoBI+hONHXfW5SJSaw== - Date: - - Tue, 23 Aug 2016 13:21:01 GMT - Connection: - - keep-alive - Content-Length: - - '113' - body: - encoding: UTF-8 - string: '{"error":{"message":"Invalid OAuth access token.","type":"OAuthException","code":190,"fbtrace_id":"BmXUehE3uug"}}' - http_version: - recorded_at: Tue, 23 Aug 2016 13:21:01 GMT -recorded_with: VCR 3.0.3 diff --git a/spec/fixtures/vcr_cassettes/token_undecryptable.yml b/spec/fixtures/vcr_cassettes/token_undecryptable.yml deleted file mode 100644 index 8cd5e0f..0000000 --- a/spec/fixtures/vcr_cassettes/token_undecryptable.yml +++ /dev/null @@ -1,52 +0,0 @@ ---- -http_interactions: -- request: - method: get - uri: https://graph.facebook.com/me?access_token=EAAH6msXVZCB0BAHqwjgc829cZAZAgw6Ymua77S9rkmkLDvr701mavIxjZBsGnihhJ5roGcY2vTCWb8nmi78LNk4NmNkgAuSK660oHmWkKNdXRAIIPy7qDEugpt78VvGvzzpFeOxc2t9xsZBN4viopXh2utRfIZB1WEZD&fields=id,email,first_name,last_name - body: - encoding: US-ASCII - string: '' - headers: - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - Accept: - - "*/*" - User-Agent: - - Ruby - Host: - - graph.facebook.com - response: - status: - code: 400 - message: Bad Request - headers: - Www-Authenticate: - - OAuth "Facebook Platform" "invalid_token" "The access token could not be decrypted" - Access-Control-Allow-Origin: - - "*" - Pragma: - - no-cache - Cache-Control: - - no-store - Expires: - - Sat, 01 Jan 2000 00:00:00 GMT - Content-Type: - - application/json; charset=UTF-8 - X-Fb-Trace-Id: - - ApNC3imcukJ - X-Fb-Rev: - - '2520541' - X-Fb-Debug: - - LHYp8HjkAtgC19B7+SgMGRBJrPAyI7sUrg6vBjQvS86SOqRDTkUBWOG9rrXf7HtAKnlorD2V5JS8ey3GPcNJbg== - Date: - - Tue, 23 Aug 2016 13:21:01 GMT - Connection: - - keep-alive - Content-Length: - - '125' - body: - encoding: UTF-8 - string: '{"error":{"message":"The access token could not be decrypted","type":"OAuthException","code":190,"fbtrace_id":"ApNC3imcukJ"}}' - http_version: - recorded_at: Tue, 23 Aug 2016 13:21:02 GMT -recorded_with: VCR 3.0.3 diff --git a/spec/models/tag_spec.rb b/spec/models/tag_spec.rb index c3b7671..047bda8 100644 --- a/spec/models/tag_spec.rb +++ b/spec/models/tag_spec.rb @@ -1,8 +1,8 @@ -require 'rails_helper' +require "rails_helper" RSpec.describe Tag, type: :model do describe "instance methods" do - it { is_expected.to respond_to :name} + it { is_expected.to respond_to :name } end describe "associations" do diff --git a/spec/models/tagging_spec.rb b/spec/models/tagging_spec.rb index f6be95d..98a0bb4 100644 --- a/spec/models/tagging_spec.rb +++ b/spec/models/tagging_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" RSpec.describe Tagging, type: :model do describe "instance methods" do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index b50f024..3d0be11 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -2,35 +2,40 @@ RSpec.describe User, type: :model do describe ".find_or_create_user" do - let(:user_attributes) { HashWithIndifferentAccess.new(user.attributes) } - let(:user) { build(:user) } + let(:user_info) do + { + kit_id: Faker::Number.digit, + phone: { number: Faker::PhoneNumber.phone_number }, + email: { address: Faker::Internet.email } + } + end context "when a new user is being created" do it "increases user record by 1" do expect do - User.create(user_attributes) + User.find_or_create_user(user_info) end.to change(User, :count).by 1 end it "returns the newly created user" do - expect(User.find_or_create_user(user_attributes)).to be_a User + expect(User.find_or_create_user(user_info)).to be_a User end end context "when an existing user attributes is supplied" do before(:each) do - user.save + @user = User.find_or_create_user(user_info) end it "doesn't change the count of the User records" do expect do - User.find_or_create_user(user_attributes) + User.find_or_create_user(user_info) end.to change(User, :count).by 0 end it "returns the existing user" do - returned_user = User.find_or_create_user(user_attributes) - expect(returned_user.email).to eq user.email + returned_user = User.find_or_create_user(user_info) + expect(returned_user.email).to eq @user.email end end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index e56bfe3..54aef1b 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -8,7 +8,6 @@ require "factory_girl" require "factory_girl_rails" require "support/helpers" -require "vcr" ActiveRecord::Migration.maintain_test_schema! RSpec.configure do |config| @@ -38,8 +37,3 @@ with.library :rails end end - -VCR.configure do |config| - config.cassette_library_dir = "spec/fixtures/vcr_cassettes" - config.hook_into :webmock -end diff --git a/spec/requests/user_authentication_spec.rb b/spec/requests/user_authentication_spec.rb index df55acc..a3c3da1 100644 --- a/spec/requests/user_authentication_spec.rb +++ b/spec/requests/user_authentication_spec.rb @@ -1,40 +1,25 @@ require "rails_helper" +require "support/shared_examples/account_kit_authentication" RSpec.describe "User Authentication", type: :request do - context "when trying to create a user" do - it "returns an auth token" do - VCR.use_cassette("synopsis") do - token = "EAAH6msXVZCB0BAHqwjgc829cZAZAg6Ymua77S9rkmkLDvr701mavIxjZBsGnihhJ5roGcY2vTCWb8nmi78LNk4NmNkgAuSK660oHmWkKNdXRAIIPy7qDEugpt78VvGvzzpFeOxc2t9xsZBN4viopXh2utRfIZB1WEZD" - post "/api/v1/auth/login", access_token: token - expect(json["token"]).to be_truthy - returned_user = json["user"] - user = User.find_by id: returned_user["id"] - expect(json["user"]).to be_truthy - expect(user.first_name).to eql returned_user["first_name"] + context "using account_kit" do + let(:valid_code) { "35df78934565" } + let(:invalid_code) { "54324ty5633" } + + context "when access_code is valid" do + context "and authentication_type is phone" do + it_behaves_like "a valid account_kit_authentication_with", :phone end - end - end - context "when token is invalid" do - it "returns an 401 error" do - VCR.use_cassette("token_invalid") do - token = "giberrish" - post "/api/v1/auth/login", access_token: token - expect(response).to have_http_status(401) - expect(json["token"]).to be_nil - expect(json["error"]).to eql("Invalid OAuth access token.") + context "and authentication_type is email" do + it_behaves_like "a valid account_kit_authentication_with", :email end end - end - context "when token can't be decrypted" do - it "returns an auth token" do - VCR.use_cassette("token_undecryptable") do - token = "EAAH6msXVZCB0BAHqwjgc829cZAZAgw6Ymua77S9rkmkLDvr701mavIxjZBsGnihhJ5roGcY2vTCWb8nmi78LNk4NmNkgAuSK660oHmWkKNdXRAIIPy7qDEugpt78VvGvzzpFeOxc2t9xsZBN4viopXh2utRfIZB1WEZD" - post "/api/v1/auth/login", access_token: token - expect(response).to have_http_status(401) - expect(json["token"]).to be_nil - expect(json["error"]).to eql("The access token could not be decrypted") + context "when access_code is invalid" do + it "responds with a 400 http status code" do + post api_v1_auth_login_path, access_token: invalid_code + expect(response).to have_http_status(400) end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 19ca005..059f4db 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,93 +1,15 @@ require "coveralls" Coveralls.wear! +require "support/mocks/account_kit_mock.rb" -# This file was generated by the `rails generate rspec:install` command. Conventionally, all -# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. -# The generated `.rspec` file contains `--require spec_helper` which will cause -# this file to always be loaded, without a need to explicitly require it in any -# files. -# -# Given that it is always loaded, you are encouraged to keep this file as -# light-weight as possible. Requiring heavyweight dependencies from this file -# will add to the boot time of your test suite on EVERY test run, even for an -# individual file that may not need all of that loaded. Instead, consider making -# a separate helper file that requires the additional dependencies and performs -# the additional setup, and require it from the spec files that actually need -# it. -# -# The `.rspec` file also contains a few flags that are not defaults but that -# users commonly want. -# -# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration RSpec.configure do |config| - # rspec-expectations config goes here. You can use an alternate - # assertion/expectation library such as wrong or the stdlib/minitest - # assertions if you prefer. config.expect_with :rspec do |expectations| - # This option will default to `true` in RSpec 4. It makes the `description` - # and `failure_message` of custom matchers include text for helper methods - # defined using `chain`, e.g.: - # be_bigger_than(2).and_smaller_than(4).description - # # => "be bigger than 2 and smaller than 4" - # ...rather than: - # # => "be bigger than 2" expectations.include_chain_clauses_in_custom_matcher_descriptions = true end - # rspec-mocks config goes here. You can use an alternate test double - # library (such as bogus or mocha) by changing the `mock_with` option here. config.mock_with :rspec do |mocks| - # Prevents you from mocking or stubbing a method that does not exist on - # a real object. This is generally recommended, and will default to - # `true` in RSpec 4. mocks.verify_partial_doubles = true end - # The settings below are suggested to provide a good initial experience - # with RSpec, but feel free to customize to your heart's content. - # # These two settings work together to allow you to limit a spec run - # # to individual examples or groups you care about by tagging them with - # # `:focus` metadata. When nothing is tagged with `:focus`, all examples - # # get run. - # config.filter_run :focus - # config.run_all_when_everything_filtered = true - # - # # Allows RSpec to persist some state between runs in order to support - # # the `--only-failures` and `--next-failure` CLI options. We recommend - # # you configure your source control system to ignore this file. - # config.example_status_persistence_file_path = "spec/examples.txt" - # - # # Limits the available syntax to the non-monkey patched syntax that is - # # recommended. For more details, see: - # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ - # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ - # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode - # config.disable_monkey_patching! - # - # # Many RSpec users commonly either run the entire suite or an individual - # # file, and it's useful to allow more verbose output when running an - # # individual spec file. - # if config.files_to_run.one? - # # Use the documentation formatter for detailed output, - # # unless a formatter has already been configured - # # (e.g. via a command-line flag). - # config.default_formatter = 'doc' - # end - # - # # Print the 10 slowest examples and example groups at the - # # end of the spec run, to help surface which specs are running - # # particularly slow. - # config.profile_examples = 10 - # - # # Run specs in random order to surface order dependencies. If you find an - # # order dependency and want to debug it, you can fix the order by providing - # # the seed, which is printed after each run. - # # --seed 1234 - # config.order = :random - # - # # Seed global randomization in this process using the `--seed` CLI option. - # # Setting this allows you to use `--seed` to deterministically reproduce - # # test failures related to randomization by passing the same `--seed` value - # # as the one that triggered the failure. - # Kernel.srand config.seed + config.include Mocks::AccountKit, type: :request end diff --git a/spec/support/helpers.rb b/spec/support/helpers.rb index 6c6b99e..3787cf0 100644 --- a/spec/support/helpers.rb +++ b/spec/support/helpers.rb @@ -4,7 +4,7 @@ def json end def token_generator(user) - user_info = { fb_id: user.fb_id, email: user.email } + user_info = { kit_id: user.kit_id, email: user.email } exp = Time.zone.now.to_i + 1 * 3600 Api::V1::Authenticate.create_token(user_info, exp) end diff --git a/spec/support/mocks/account_kit_mock.rb b/spec/support/mocks/account_kit_mock.rb new file mode 100644 index 0000000..63bb9b4 --- /dev/null +++ b/spec/support/mocks/account_kit_mock.rb @@ -0,0 +1,28 @@ +module Mocks + module AccountKit + def phone + { + id: "175649852839525", + phone: { + number: "+234736847989", + country_prefix: "234", + national_number: "736847989" + } + } + end + + def email + { + id: "175649852839525", + email: { + address: "email@email.com" + } + } + end + + def mock_account_kit_info(type) + allow_any_instance_of(Facebook::AccountKit::UserAccount). + to receive(:fetch_user_info).and_return(send(type)) + end + end +end diff --git a/spec/support/shared_examples/account_kit_authentication.rb b/spec/support/shared_examples/account_kit_authentication.rb new file mode 100644 index 0000000..4f0554c --- /dev/null +++ b/spec/support/shared_examples/account_kit_authentication.rb @@ -0,0 +1,31 @@ +shared_examples_for "a valid account_kit_authentication_with" do |type| + before { mock_account_kit_info(type) } + + context "when user is already created" do + before do + create(:user, kit_id: "175649852839525") + end + + it "does not create user" do + expect { post api_v1_auth_login_path, access_token: valid_code }. + to_not change(User, :count) + end + + it "responds with a 200 http status code" do + post api_v1_auth_login_path, access_token: valid_code + expect(response).to have_http_status(200) + end + end + + context "when user is not created" do + it "responds with a 200 http_status code" do + post api_v1_auth_login_path, access_token: valid_code + expect(response).to have_http_status(200) + end + + it "creates the user" do + expect { post api_v1_auth_login_path, access_token: valid_code }. + to change(User, :count).by(1) + end + end +end