From 56c916ba5a32b8d98b40d30341687246f44d2c9b Mon Sep 17 00:00:00 2001 From: Oreoluwa Akinniranye Date: Mon, 1 Feb 2016 11:20:31 +0100 Subject: [PATCH 1/6] added ownership_concern which ensures that resource is only deleted by resource owner --- app/controllers/answers_controller.rb | 4 +++ app/controllers/concerns/ownership_concern.rb | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 app/controllers/concerns/ownership_concern.rb diff --git a/app/controllers/answers_controller.rb b/app/controllers/answers_controller.rb index c72174d..8c0f886 100644 --- a/app/controllers/answers_controller.rb +++ b/app/controllers/answers_controller.rb @@ -1,6 +1,8 @@ class AnswersController < ApplicationController + include OwnershipConcern before_action :set_question before_action :set_answer, only: [:show, :update, :destroy] + before_action :check_user_owns_answer, only: [:update, :destroy] def index @answers = @question.answers.all @@ -9,11 +11,13 @@ def index end def show + require 'pry' ; binding.pry render json: @answer end def create @answer = @question.answers.new(answer_params) + @answer.user = current_user if @answer.save render json: @answer, status: :created, location: question_answer_path(@question, @answer) diff --git a/app/controllers/concerns/ownership_concern.rb b/app/controllers/concerns/ownership_concern.rb new file mode 100644 index 0000000..9dbd18c --- /dev/null +++ b/app/controllers/concerns/ownership_concern.rb @@ -0,0 +1,27 @@ + +require 'forwardable' +module OwnershipConcern + + def self.included(base) + base.class_eval do + base.extend Forwardable + base.def_delegator self, :resource_name + + def self.resource_name + controller_name.singularize + end + + define_method "check_user_owns_#{resource_name}" do + resource = instance_variable_get("@#{resource_name}") + if resource + unauthorized_access && return unless resource.user == current_user + end + end + end + end + + def unauthorized_access + render json: {errors: "Unauthorized/Forbidden Access: #{resource_name.capitalize} does not belong to user"}, status: :forbidden + end + +end From df468017fe3e4cbbe02ebaeb706029d4c3081643 Mon Sep 17 00:00:00 2001 From: Oreoluwa Akinniranye Date: Mon, 1 Feb 2016 20:22:31 +0100 Subject: [PATCH 2/6] added module to check if user owns the resource --- app/controllers/answers_controller.rb | 11 +++++++---- app/controllers/application_controller.rb | 5 +++++ app/controllers/questions_controller.rb | 6 +----- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/app/controllers/answers_controller.rb b/app/controllers/answers_controller.rb index 8c0f886..28dd1a0 100644 --- a/app/controllers/answers_controller.rb +++ b/app/controllers/answers_controller.rb @@ -22,7 +22,7 @@ def create if @answer.save render json: @answer, status: :created, location: question_answer_path(@question, @answer) else - render json: @answer.errors, status: :unprocessable_entity + invalid_request(error_msg) end end @@ -30,13 +30,16 @@ def update if @answer.update(answer_params) head :no_content else - render json: @answer.errors, status: :unprocessable_entity + invalid_request(error_msg) end end def destroy - @answer.destroy - head :no_content + if @answer.try(:destroy) + head :no_content + else + invalid_request(error_msg) + end end private diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c597c78..a2ea850 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -34,6 +34,11 @@ def unauthorized_token render json: {errors: "Request was made with invalid token"}, status: 401 end + def error_msg + "The operation could not be performed."\ + " Please check your request or try again later" + end + def set_attrs_in_session(hash={}) hash.each do |key, val| diff --git a/app/controllers/questions_controller.rb b/app/controllers/questions_controller.rb index f50174a..313cf38 100644 --- a/app/controllers/questions_controller.rb +++ b/app/controllers/questions_controller.rb @@ -1,6 +1,7 @@ class QuestionsController < ApplicationController before_action :set_question, only: [:show, :update, :destroy] before_action :authenticate_user + def index questions = Question.all render json: questions, status: 200 @@ -46,11 +47,6 @@ def set_question resource_not_found && return unless @question end - def error_msg - "The operation could not be performed."\ - " Please check your request or try again later" - end - def questions_params params.permit(:id, :title, :content, :votes) end From 84b1eb201c761da0ba7bf56df7d6acdc18c3b68e Mon Sep 17 00:00:00 2001 From: Oreoluwa Akinniranye Date: Mon, 1 Feb 2016 20:43:31 +0100 Subject: [PATCH 3/6] used ActiveSupport::Concern to manage the module inclusion --- app/controllers/answers_controller.rb | 4 +--- app/controllers/concerns/ownership_concern.rb | 24 +++++++++---------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/app/controllers/answers_controller.rb b/app/controllers/answers_controller.rb index 28dd1a0..83f4e62 100644 --- a/app/controllers/answers_controller.rb +++ b/app/controllers/answers_controller.rb @@ -1,8 +1,7 @@ class AnswersController < ApplicationController - include OwnershipConcern before_action :set_question before_action :set_answer, only: [:show, :update, :destroy] - before_action :check_user_owns_answer, only: [:update, :destroy] + include OwnershipConcern def index @answers = @question.answers.all @@ -11,7 +10,6 @@ def index end def show - require 'pry' ; binding.pry render json: @answer end diff --git a/app/controllers/concerns/ownership_concern.rb b/app/controllers/concerns/ownership_concern.rb index 9dbd18c..537e116 100644 --- a/app/controllers/concerns/ownership_concern.rb +++ b/app/controllers/concerns/ownership_concern.rb @@ -1,21 +1,21 @@ require 'forwardable' module OwnershipConcern + extend ActiveSupport::Concern - def self.included(base) - base.class_eval do - base.extend Forwardable - base.def_delegator self, :resource_name + included do + extend Forwardable + def_delegator self, :resource_name + def self.resource_name + controller_name.singularize + end - def self.resource_name - controller_name.singularize - end + before_action "check_user_owns_#{resource_name}", only: [:update, :destroy] - define_method "check_user_owns_#{resource_name}" do - resource = instance_variable_get("@#{resource_name}") - if resource - unauthorized_access && return unless resource.user == current_user - end + define_method "check_user_owns_#{resource_name}" do + resource = instance_variable_get("@#{resource_name}") + if resource + unauthorized_access && return unless resource.user == current_user end end end From 1c2a31114b5b5fc429a9caf472f4b15406389311 Mon Sep 17 00:00:00 2001 From: Oreoluwa Akinniranye Date: Tue, 2 Feb 2016 12:46:03 +0100 Subject: [PATCH 4/6] handled error that would have occured if invalid token is sent by delegating destroy to the method --- app/controllers/tokens_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/tokens_controller.rb b/app/controllers/tokens_controller.rb index 631310a..67f8d3b 100644 --- a/app/controllers/tokens_controller.rb +++ b/app/controllers/tokens_controller.rb @@ -9,7 +9,7 @@ def validate private def set_token - @token = Token.active.find_by(temp: params[:temp_token]).destroy + @token = Token.active.find_by(temp: params[:temp_token]).try(:destroy) resource_not_found unless @token end end From d39b54420af2c3d60825b736c46a580afe84a445 Mon Sep 17 00:00:00 2001 From: Oreoluwa Akinniranye Date: Wed, 3 Feb 2016 16:31:38 +0100 Subject: [PATCH 5/6] validating email addresses --- app/models/concerns/andela_validator.rb | 9 +++++++++ app/models/user.rb | 6 +++++- db/schema.rb | 7 ++----- 3 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 app/models/concerns/andela_validator.rb diff --git a/app/models/concerns/andela_validator.rb b/app/models/concerns/andela_validator.rb new file mode 100644 index 0000000..29c1758 --- /dev/null +++ b/app/models/concerns/andela_validator.rb @@ -0,0 +1,9 @@ +module AndelaValidator + extend ActiveSupport::Concern + + ANDELA_EMAIL_REGEX = /@andela.co[m]?\z/ + included do + validates :email, presence: true, format: {with: ANDELA_EMAIL_REGEX} + end + +end diff --git a/app/models/user.rb b/app/models/user.rb index fb5060b..cccd6f4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -5,9 +5,13 @@ class User < ActiveRecord::Base has_many :answers has_many :social_providers has_many :tokens + EMAIL_FORMAT= /(?[.\w]+@andela).co[m]?\z/ def self.from_omniauth(auth, user=nil) - user = where(email: auth.info.email).first_or_create do |u| + email_address = auth.info.email + grabbed = EMAIL_FORMAT.match(email_address).try(:[], :email) || email_address + to_check = "#{grabbed}%" + user = where(email: to_check).first_or_create do |u| u.name= auth.info.name u.email= auth.info.email end diff --git a/db/schema.rb b/db/schema.rb index b411eb8..022b094 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,14 +11,12 @@ # # It's strongly recommended that you check this file into your version control system. - ActiveRecord::Schema.define(version: 20160201170223) do create_table "answers", force: :cascade do |t| t.integer "user_id" t.integer "question_id" t.string "content" - t.integer "votes" t.datetime "created_at", null: false t.datetime "updated_at", null: false end @@ -26,7 +24,6 @@ create_table "comments", force: :cascade do |t| t.integer "user_id" t.string "content" - t.integer "votes" t.integer "comment_on_id" t.string "comment_on_type" t.datetime "created_at", null: false @@ -39,7 +36,6 @@ t.integer "user_id" t.string "title" t.string "content" - t.integer "votes" t.datetime "created_at", null: false t.datetime "updated_at", null: false end @@ -55,7 +51,7 @@ t.string "token" t.string "profile_picture" t.string "profile_url" - t.string "profile_email" + t.string "email" end add_index "social_providers", ["user_id"], name: "index_social_providers_on_user_id" @@ -103,4 +99,5 @@ add_index "votes", ["user_id"], name: "index_votes_on_user_id" add_index "votes", ["voteable_type", "voteable_id"], name: "index_votes_on_voteable_type_and_voteable_id" + end From b6996879f52c20e50ef874b7ca6dce176f12a6d9 Mon Sep 17 00:00:00 2001 From: Oreoluwa Akinniranye Date: Wed, 3 Feb 2016 17:09:16 +0100 Subject: [PATCH 6/6] added validator for email address to only permit Andelans --- app/models/concerns/andela_validator.rb | 4 ++-- app/models/social_provider.rb | 1 + app/models/user.rb | 7 ++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/models/concerns/andela_validator.rb b/app/models/concerns/andela_validator.rb index 29c1758..957823c 100644 --- a/app/models/concerns/andela_validator.rb +++ b/app/models/concerns/andela_validator.rb @@ -1,9 +1,9 @@ module AndelaValidator extend ActiveSupport::Concern - ANDELA_EMAIL_REGEX = /@andela.co[m]?\z/ + ANDELA_EMAIL_REGEX = /[\w.]+@andela.co[m]?\z/ included do - validates :email, presence: true, format: {with: ANDELA_EMAIL_REGEX} + validates :email, presence: true, format: {with: ANDELA_EMAIL_REGEX, message: "Sign in with an Andela email address"} end end diff --git a/app/models/social_provider.rb b/app/models/social_provider.rb index a074195..bb9c98a 100644 --- a/app/models/social_provider.rb +++ b/app/models/social_provider.rb @@ -1,4 +1,5 @@ class SocialProvider < ActiveRecord::Base + include AndelaValidator belongs_to :user validates :uuid, presence: true validates :provider, presence: true diff --git a/app/models/user.rb b/app/models/user.rb index cccd6f4..4f6aa2c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,4 +1,5 @@ class User < ActiveRecord::Base + include AndelaValidator has_many :comments, as: :comment_on has_many :tags, as: :subscriber has_many :questions @@ -9,9 +10,9 @@ class User < ActiveRecord::Base def self.from_omniauth(auth, user=nil) email_address = auth.info.email - grabbed = EMAIL_FORMAT.match(email_address).try(:[], :email) || email_address - to_check = "#{grabbed}%" - user = where(email: to_check).first_or_create do |u| + grabbed = EMAIL_FORMAT.match(email_address).try(:[], :email) + grabbed = grabbed ? "#{grabbed}%" : email_address + user = where("email LIKE :email", email: grabbed).first_or_create do |u| u.name= auth.info.name u.email= auth.info.email end