diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1b6c14f..064ce93 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -10,7 +10,7 @@ def resource_not_found render json: {errors: not_found}, status: 404 end - def invalid_request(message) + def invalid_request(message = error_msg) render json: {errors: message}, status: 400 end diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 38f9fa4..a5b0a31 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -1,76 +1,56 @@ class CommentsController < ApplicationController - before_action :custom_initializer - attr_reader :user_id, :question_id, :answer_id, :id, :content - - include Common + before_action :set_resource + before_action :set_comment, only: [:show, :update, :destroy] + include OwnershipConcern def index - question = Question.find_by(id: question_id) if action_on_question - answer = Answer.find_by(id: answer_id) if action_on_answer - comments = question.comments if question - comments = answer.comments if answer - render json: comments, status: 200 unless comments.nil? - render json: { error: false }, status: 404 if comments.nil? + render json: @resource_comments, status: 200 end def show - comments = Question.find_question_comment(question_id, id) if action_on_question - comments = Answer.find_answer_comment(answer_id, id) if action_on_answer - render json: comments , status: 200 - rescue - render json: { error: false }, status: 404 + render json: @comment, status: 200 end def create - unless content.nil? || content == "" - if action_on_question - comments = Question.add_comment_to_question(question_id, user_id, content) - elsif action_on_answer - comments = Answer.add_comment_to_answer(answer_id, user_id, content) - end - render json: comments, root: false + comment = @resource_comments.new(content: comment_params[:content]) + comment.user = current_user + if comment.save + render json: comment, status: 201 else - render json: { error: "Comment body can not be empty!" }, status: 403 + invalid_request("Comment body can not be empty!") end end def update - status = update_subject(id, user_id, "content", content) if content && content != "" - message = { response: status ? true : false } - render json: message - rescue - render json: { error: false }, status: 403 + if @comment.update(content: comment_params[:content]) + render json: @comment, status: 200 + else + invalid_request("Comment body can not be empty!") + end end def destroy - if action_on_question - deleted if Question.delete_question_comment(id, user_id, question_id) - elsif action_on_answer - deleted if Answer.delete_answer_comment(id, user_id, answer_id) + if @comment.try(:destroy) + render json: :head, status: 204 + else + invalid_request end - rescue - render json: { error: false }, status: 403 end private def comment_params - params.permit(:question_id, :answer_id, :id, :content, :downvote, :upvote) + params.permit(:resource_name, :resource_id, :content, :id) end - def custom_initializer - set_vars(comment_params) + def set_resource + resource = comment_params[:resource_name].singularize.camelize.constantize.find_by(id: comment_params[:resource_id]) + resource_not_found && return unless resource + @resource_comments = resource.comments end - def deleted - render json: { response: "Comment deleted." }, status: 410 - end - - def update_subject(id, user_id, attribute, value = nil) - if action_on_question - comments = Question.update_question_comment(id, user_id, question_id, attribute, value) - elsif action_on_answer - comments = Answer.update_answer_comment(id, user_id, answer_id, attribute, value) - end + def set_comment + @comment = @resource_comments.find_by(id: comment_params[:id]) + resource_not_found && return unless @comment end end diff --git a/app/controllers/concerns/common.rb b/app/controllers/concerns/common.rb deleted file mode 100644 index ea39785..0000000 --- a/app/controllers/concerns/common.rb +++ /dev/null @@ -1,22 +0,0 @@ -module Common - def set_vars(allowed = {}) - @question_id = allowed[:question_id] - @answer_id = allowed[:answer_id] - @comment_id = allowed[:comment_id] - @id = allowed[:id] - @content = allowed[:content] - @user_id = current_user.id if current_user - end - - def action_on_question - question_id && answer_id.nil? - end - - def action_on_answer - answer_id && question_id.nil? - end - - def action_on_comment - comment_id.present? - end -end diff --git a/app/controllers/votes_controller.rb b/app/controllers/votes_controller.rb index 918b852..6643c15 100644 --- a/app/controllers/votes_controller.rb +++ b/app/controllers/votes_controller.rb @@ -1,20 +1,20 @@ class VotesController < ApplicationController def upvote resource_to_upvote = vote_params[:resource_name].singularize.camelize.constantize - vote = Vote.act_on_vote('plus', resource_to_upvote, vote_params[:id], current_user) + vote = Vote.act_on_vote('plus', resource_to_upvote, vote_params[:resource_id], current_user) render json: { response: vote }, status: 200 unless vote.nil? render json: { error: "Invalid vote!" }, status: 403 if vote.nil? end def downvote resource_to_upvote = vote_params[:resource_name].singularize.camelize.constantize - vote = Vote.act_on_vote('minus', resource_to_upvote, vote_params[:id], current_user) + vote = Vote.act_on_vote('minus', resource_to_upvote, vote_params[:resource_id], current_user) render json: { response: vote }, status: 200 unless vote.nil? render json: { error: "Invalid vote!" }, status: 403 if vote.nil? end private def vote_params - params.permit(:resource_name, :id) + params.permit(:resource_name, :resource_id) end end diff --git a/app/models/answer.rb b/app/models/answer.rb index f8112f2..25d9ca8 100644 --- a/app/models/answer.rb +++ b/app/models/answer.rb @@ -7,31 +7,4 @@ class Answer < ActiveRecord::Base belongs_to :question, counter_cache: true validates :content, presence: true - - include Modify - - class << self - def add_comment_to_answer(answer_id, user_id, content) - answer = find_by(id: answer_id) - if answer - answer.comments.create(user_id: user_id, content: content) - end - end - - def find_answer_comment(answer_id, id) - answer = find_by(id: answer_id) - if answer - answer.comments.where(id: id) - end - end - - def delete_answer_comment(id, user_id, answer_id) - Modify::Updater.affected_record(answer_id, self, user_id).destroy(id) - end - - def update_answer_comment(id, user_id, answer_id, attribute, value) - Modify::Updater.update_subject_comment(id, user_id, answer_id, self, attribute, value) - end - end - end diff --git a/app/models/concerns/modify.rb b/app/models/concerns/modify.rb deleted file mode 100644 index bbf895b..0000000 --- a/app/models/concerns/modify.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Modify - class Updater - class << self - def update_subject_comment(id, user_id, subject_id, subject_name, attribute, value) - affected_record(subject_id, subject_name, user_id).update(id, content: value) - end - - def affected_record(subject_id, subject_name, user_id) - subject = subject_name.find_by(id: subject_id) - if subject - subject.comments.where(user_id: user_id) - end - end - end - end -end \ No newline at end of file diff --git a/app/models/question.rb b/app/models/question.rb index 24d8042..0636637 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -9,7 +9,6 @@ class Question < ActiveRecord::Base validates :content, presence: true validates :user, presence: true - include Modify include ActionView::Helpers::DateHelper def time_updated @@ -27,32 +26,7 @@ def increment_views update(views: views + 1) end - class << self - def with_answers - includes(:answers) - end - - - def add_comment_to_question(question_id, user_id, content) - question = find_by(id: question_id) - if question - question.comments.create(user_id: user_id, content: content) - end - end - - def find_question_comment(question_id, id) - question = find_by(id: question_id) - if question - question.comments.where(id: id) - end - end - - def delete_question_comment(id, user_id, question_id) - Modify::Updater.affected_record(question_id, self, user_id).destroy(id) - end - - def update_question_comment(id, user_id, question_id, attribute, value) - Modify::Updater.update_subject_comment(id, user_id, question_id, self, attribute, value) - end + def self.with_answers + includes(:answers) end end diff --git a/app/serializers/comment_serializer.rb b/app/serializers/comment_serializer.rb index 1e8cbe9..9df92e7 100644 --- a/app/serializers/comment_serializer.rb +++ b/app/serializers/comment_serializer.rb @@ -1,3 +1,4 @@ class CommentSerializer < MainSerializer - + attributes :user + belongs_to :user end diff --git a/config/routes.rb b/config/routes.rb index 25c4727..8347f19 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,8 @@ Rails.application.routes.draw do - scope '/:resource_name/:id', constraints: { resource_name: /(questions|answers|comments)/ } do + scope '/:resource_name/:resource_id', constraints: { resource_name: /(questions|answers|comments)/ } do post '/upvote', to: 'votes#upvote' post '/downvote', to: 'votes#downvote' + resources :comments, except: [:new, :edit], resource_name: /(?!comments).*/ end post '/validate_token', to: 'tokens#validate' @@ -10,18 +11,11 @@ get "recent_answers" get "popular_answers" - resources :comments, except: [:new, :edit] resources :answers, except: [:new, :edit] end get "top_questions" => "questions#top_questions" - resources :answers, except: [:index, :show, :create, :destroy, :update, :new, :edit] do - resources :comments, except: [:new, :edit] - end - - resources :comments, only: [:update, :delete] - post "users/logout" => "user#logout" get 'users/renew_token' => 'users#renew_token' get "users" => "users#index" diff --git a/docs/comments_endpoints.md b/docs/comments_endpoints.md index facc286..1674912 100644 --- a/docs/comments_endpoints.md +++ b/docs/comments_endpoints.md @@ -4,8 +4,12 @@ Endpoints | Usage | Public Access --------- | ----- | ------------- GET /answers/:id/comments | Returns all the comments for a particular answer | True POST /answers/:id/comments/ | Creates a new comment for the specified answer | False -PUT /comments/:id | Updates the comment with certain attributes | False -DELETE /comments/:id | Deletes an comment | False +PATCH /answers/:answer_id/comments/:id | Updates the specified comment of the specified answer | False +DELETE /answers/:answer_id/comments/:id | Deletes the specified comment of the specified answer | False +GET /questions/:id/comments | Returns all the comments for a particular question | True +POST /questions/:id/comments/ | Creates a new comment for the specified question | False +PATCH /questions/:question_id/comments/:id | Updates the specified comment of the specified question | False +DELETE /questions/:question_id/comments/:id | Deletes the specified comment of the specified question | False ### GET /answers/:id/comments @@ -49,11 +53,63 @@ Status: 200 } } ``` + Or ```ruby Status: 404 { - message: "Answer not found" + error: "The resource you tried to access was not found" +} +``` + +### GET /questions/:id/comments + +Request +```ruby + { + auth_token: "90ioji0j0i0i0ik0k0jmj0090jknieu93833r335" + } +``` + +Response +```ruby +Status: 200 + { + answer: { + id: 1, + comments: [ + { + id: 2, + text: 'What do you really want to do?', + date_created: 'Wed, 24TH Nov, 2017 10:00AM', + updated: false, + score: 8, + user: { + id: 2, + name: 'Oscar Laide' + } + }, + { + id: 4, + text: 'This is such a scam', + date_created: 'Wed, 25TH Nov, 2017 12:00PM', + updated: true, + score: 9, + user: { + id: 3, + name: 'Bayo Owoade' + } + } + ] + } + } +``` + Or + +```ruby +Status: 404 +{ + error: "The resource you tried to access was not found" } ``` @@ -72,11 +128,52 @@ Response ```ruby Status: 201 { - message: "Successfully added" + id: 4, + text: 'This is such a scam', + date_created: 'Wed, 25TH Nov, 2017 12:00PM', + updated: true, + score: 9, + user: { + id: 3, + name: 'Bayo Owoade' + } } ``` -### PUT /comments/:id +### POST /questions/:id/comments/ + +Request +```ruby + { + auth_token: "90ioji0j0i0i0ik0k0jmj0090jknieu93833r335", + content: "Why in the world do I have to do this?" + } +``` + +Response +```ruby +Status: 201 +{ + id: 4, + text: 'This is such a scam', + date_created: 'Wed, 25TH Nov, 2017 12:00PM', + updated: true, + score: 9, + user: { + id: 3, + name: 'Bayo Owoade' + } +} +``` +OR +```ruby +Status: 404 +{ + error: "Comment body can not be empty!" +} +``` + +### PATCH /answers/:answer_id/comments/:id Request ```ruby @@ -86,12 +183,68 @@ Request } ``` +Response +```ruby + Status: 200 + { + id: 4, + text: 'This is such a scam', + date_created: 'Wed, 25TH Nov, 2017 12:00PM', + updated: true, + score: 9, + user: { + id: 3, + name: 'Bayo Owoade' + } + } +``` +### PATCH /questions/:question_id/comments/:id + +Request +```ruby + { + auth_token: "90ioji0j0i0i0ik0k0jmj0090jknieu93833r335", + content: "What in the world does this mean?" + } +``` + +Response +```ruby + Status: 200 + { + id: 4, + text: 'This is such a scam', + date_created: 'Wed, 25TH Nov, 2017 12:00PM', + updated: true, + score: 9, + user: { + id: 3, + name: 'Bayo Owoade' + } + } +``` +OR +```ruby +Status: 404 +{ + error: "Comment body can not be empty!" +} +``` +### DELETE /answers/:answer_id/comments/:id + +Request +```ruby + { + auth_token: "90ioji0j0i0i0ik0k0jmj0090jknieu93833r335" + } +``` + Response ```ruby Status: 204 ``` -### DELETE /comments/:id +### DELETE /questions/:answer_id/comments/:id Request ```ruby @@ -104,3 +257,11 @@ Response ```ruby Status: 204 ``` + +OR +```ruby +Status: 404 +{ + error: "The operation could not be performed. Please check your request or try again later" +} +``` diff --git a/docs/vote_endpoints.md b/docs/vote_endpoints.md new file mode 100644 index 0000000..b9442cd --- /dev/null +++ b/docs/vote_endpoints.md @@ -0,0 +1,107 @@ +#Votes Resources + +Endpoints | Usage | Public Access +--------- | ----- | ------------- +POST /questions/:question_id/upvote | Increase the upvotes of the given question by one unit | False +POST /questions/:question_id/downvote | Increase the downvotes of the given question by one unit | False +POST /answers/:answer_id/upvote | Increase the upvotes of the given answer by one unit | False +POST /answers/:answer_id/downvote | Increase the downvotes of the given answers by one unit | False +POST /comments/:question_id/upvote | Increase the upvotes of the given comment by one unit | False +POST /comments/:question_id/downvote | Increase the downvotes of the given comments by one unit | False + +### POST /questions/:question_id/upvote/ + +Response +```ruby +Status: 200 +{ + response: 11 +} +``` +#### OR +```ruby +Status: 403 + { + error: "Invalid vote!" + } +``` +### POST /comments/:comment_id/upvote/ + +Response +```ruby +Status: 200 +{ + response: 23 +} +``` +#### OR +```ruby +Status: 403 + { + error: "Invalid vote!" + } +``` +### POST /answers/:answer_id/upvote/ + +Response +```ruby +Status: 200 +{ + response: 0 +} +``` +#### OR +```ruby +Status: 403 + { + error: "Invalid vote!" + } +``` +### POST /questions/:question_id/downvote/ + +Response +```ruby +Status: 200 +{ + response: 2 +} +``` +#### OR +```ruby +Status: 403 + { + error: "Invalid vote!" + } +``` +### POST /comments/:comment_id/downvote/ + +Response +```ruby +Status: 200 +{ + response: -12 +} +``` +#### OR +```ruby +Status: 403 + { + error: "Invalid vote!" + } +``` +### POST /answers/:answer_id/downvote/ + +Response +```ruby +Status: 200 +{ + response: 34 +} +``` +#### OR +```ruby +Status: 403 + { + error: "Invalid vote!" + } +```