Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API proof of concept: forums#show #665

Open
wants to merge 33 commits into
base: rails4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
780197a
API proof of concept: forums#show
eostrom Jul 2, 2015
2df1654
Fixed bug when no API version is specified.
eostrom Jul 7, 2015
f0520c1
Include topics in /forum/:id API.
eostrom Jul 7, 2015
6080de5
JSON API compliance: relationships go inside data.
eostrom Jul 8, 2015
676b2f6
Added posts count and views count.
eostrom Jul 8, 2015
1d8d680
topics#show API: include last post.
eostrom Jul 9, 2015
7e8ad68
Allow topics to be created without first posts.
eostrom Jul 12, 2015
c5a78c3
Give API routes priority.
eostrom Jul 12, 2015
88ca5e7
Create Topic happy path.
eostrom Jul 12, 2015
aa614d9
Create Topic error handling.
eostrom Jul 12, 2015
87019aa
Lock Jbuilder against incompatible upgrades.
eostrom Jul 13, 2015
3b2ebb7
API: Added topics#show.
eostrom Jul 14, 2015
30d7dce
API: Include posts in topics#show.
eostrom Jul 15, 2015
a60d5d5
Removed accidentally duplicated specs.
eostrom Jul 15, 2015
3c867db
API: added posts#show.
eostrom Jul 15, 2015
95c9abf
API: include forum ID in post JSON.
eostrom Jul 17, 2015
dc751a3
API: Added posts#update.
eostrom Jul 17, 2015
054991a
Spec refactor: started abstracting API behavior.
eostrom Jul 17, 2015
bafbee5
Spec refactor: matchers for JSON API references.
eostrom Jul 19, 2015
b2684a8
API: Inherit from ForumsController.
eostrom Jul 19, 2015
5efb90f
API: Extracted JsonApiController module.
eostrom Jul 19, 2015
fe776c5
API: Added forum relationship to posts and topics.
eostrom Jul 20, 2015
b97d486
API: send user relationships, not ID attributes.
eostrom Jul 20, 2015
45b8ef9
API: Render included posts with a partial.
eostrom Jul 20, 2015
da075e8
Add topic slugs to JSON output.
eostrom Aug 18, 2015
70e0ffe
API: Don't list unmoderated topics.
eostrom Aug 25, 2015
92db379
Merged from rails4 into api branch.
eostrom Sep 8, 2015
0543130
Added created_at field to topics list.
eostrom Sep 16, 2015
21fa728
API: Added topic author ID to forums/show response.
eostrom Sep 17, 2015
6617ae2
API: Include latest post author in topic list.
eostrom Sep 17, 2015
fbb1e72
API: Reduced code duplication in topic views.
eostrom Sep 17, 2015
5991286
API: Hide unapproved posts from non-moderators.
eostrom Sep 17, 2015
b354f5b
Set last_post_at for topics with no posts.
eostrom Sep 29, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ gemspec
gem 'pry-rails'
gem 'pry-nav'
gem 'select2-rails', '~> 3.5.4'
gem 'jbuilder'

platforms :jruby do
gem "activerecord-jdbc-adapter", :require => false
Expand Down
11 changes: 11 additions & 0 deletions app/controllers/forem/api/v1/forums_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require_dependency "forem/application_controller"

module Forem
module Api
module V1
class ForumsController < Forem::ForumsController
include JsonApiController
end
end
end
end
66 changes: 66 additions & 0 deletions app/controllers/forem/api/v1/json_api_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
module Forem
module Api
module V1
module JsonApiController
extend ActiveSupport::Concern

included do
before_action { request.format = :json }

before_action :client_generated_ids_are_unsupported, only: :create
before_action :ids_cannot_be_updated, only: :update

rescue_from ActionController::ParameterMissing, with: :bad_request,
only: :create
rescue_from CanCan::AccessDenied, with: :forbidden
end

private

def authenticate_forem_user
render nothing: true, status: :forbidden if !forem_user
end

def required_params
params.require(:data).require(:attributes)
end

def create_successful
render 'show', status: :created,
location: resource_url
end

def create_failed
render 'member_errors', status: :bad_request
end
alias_method :create_unsuccessful, :create_failed

def update_successful
render 'show', status: :ok
end

def update_failed
render 'member_errors', status: :bad_request
end

def bad_request
render nothing: true, status: :bad_request
end

def forbidden
render nothing: true, status: :forbidden
end

def client_generated_ids_are_unsupported
render nothing: true, status: :forbidden if params[:data][:id]
end

def ids_cannot_be_updated
if params[:data][:id] != @post.id
render nothing: true, status: :conflict if params[:data][:id]
end
end
end
end
end
end
21 changes: 21 additions & 0 deletions app/controllers/forem/api/v1/posts_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
require_dependency "forem/application_controller"

module Forem
module Api
module V1
class PostsController < Forem::PostsController
include JsonApiController

protected

def post_params
required_params.permit(:text)
end

def resource_url
api_forum_topic_post_url(@topic.forum, @topic, @post)
end
end
end
end
end
25 changes: 25 additions & 0 deletions app/controllers/forem/api/v1/topics_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require_dependency "forem/application_controller"

module Forem
module Api
module V1
class TopicsController < Forem::TopicsController
include JsonApiController

private

def topic_params
required_params.permit(:subject)
end

def resource_url
api_forum_topic_url(@forum, @topic)
end

def topic_not_found
render nothing: true, status: :not_found
end
end
end
end
end
5 changes: 0 additions & 5 deletions app/controllers/forem/forums_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@ def show

# Kaminari allows to configure the method and param used
@topics = @topics.send(pagination_method, params[pagination_param]).per(Forem.per_page)

respond_to do |format|
format.html
format.atom { render :layout => false }
end
end

private
Expand Down
12 changes: 4 additions & 8 deletions app/controllers/forem/posts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ class PostsController < Forem::ApplicationController
before_filter :authenticate_forem_user, except: :show
before_filter :find_topic
before_filter :reject_locked_topic!, only: [:new, :create]
before_filter :authorize_edit_post_for_forum!, only: [:edit, :update]
before_filter :authorize_destroy_post_for_forum!, only: [:destroy]
before_filter :find_post, except: [:new, :create]

def show
find_post
page = (@topic.posts.count.to_f / Forem.per_page.to_f).ceil

redirect_to forum_topic_url(@topic.forum, @topic, pagination_param => page, anchor: "post-#{@post.id}")
Expand Down Expand Up @@ -39,13 +41,9 @@ def create
end

def edit
authorize_edit_post_for_forum!
find_post
end

def update
authorize_edit_post_for_forum!
find_post
if @post.owner_or_admin?(forem_user) && @post.update_attributes(post_params)
update_successful
else
Expand All @@ -54,8 +52,6 @@ def update
end

def destroy
authorize_destroy_post_for_forum!
find_post
unless @post.owner_or_admin? forem_user
flash[:alert] = t("forem.post.cannot_delete")
redirect_to [@topic.forum, @topic] and return
Expand Down Expand Up @@ -88,7 +84,7 @@ def create_successful
end

def create_failed
params[:reply_to_id] = params[:post][:reply_to_id]
params[:reply_to_id] = params[:post][:reply_to_id] if params[:post]
flash.now.alert = t("forem.post.not_created")
render :action => "new"
end
Expand Down
39 changes: 18 additions & 21 deletions app/controllers/forem/topics_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ class TopicsController < Forem::ApplicationController
helper 'forem/posts'
before_filter :authenticate_forem_user, :except => [:show]
before_filter :find_forum
before_filter :find_topic, :only => [:show, :subscribe, :unsubscribe]
before_filter :block_spammers, :only => [:new, :create]

def show
if find_topic
register_view(@topic, forem_user)
@posts = find_posts(@topic)
register_view(@topic, forem_user)
@posts = find_posts(@topic)

# Kaminari allows to configure the method and param used
@posts = @posts.send(pagination_method, params[pagination_param]).per(Forem.per_page)
end
# Kaminari allows to configure the method and param used
@posts = @posts.send(pagination_method, params[pagination_param]).per(Forem.per_page)
end

def new
Expand Down Expand Up @@ -43,17 +42,13 @@ def destroy
end

def subscribe
if find_topic
@topic.subscribe_user(forem_user.id)
subscribe_successful
end
@topic.subscribe_user(forem_user.id)
subscribe_successful
end

def unsubscribe
if find_topic
@topic.unsubscribe_user(forem_user.id)
unsubscribe_successful
end
@topic.unsubscribe_user(forem_user.id)
unsubscribe_successful
end

protected
Expand Down Expand Up @@ -108,13 +103,15 @@ def find_posts(topic)
end

def find_topic
begin
@topic = forum_topics(@forum, forem_user).friendly.find(params[:id])
authorize! :read, @topic
rescue ActiveRecord::RecordNotFound
flash.alert = t("forem.topic.not_found")
redirect_to @forum and return
end
@topic = forum_topics(@forum, forem_user).friendly.find(params[:id])
authorize! :read, @topic
rescue ActiveRecord::RecordNotFound
topic_not_found
end

def topic_not_found
flash.alert = t("forem.topic.not_found")
redirect_to @forum
end

def register_view(topic, user)
Expand Down
29 changes: 29 additions & 0 deletions app/helpers/forem/api/api_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module Forem
module Api
module ApiHelper
def api_id(model)
model.respond_to?(:id) ? model.id : model
end

def api_has_one(json, relationship, type, model)
json.set! relationship do
json.data do
json.type type
json.id api_id(model)
end
end
end

def api_has_many(json, relationship, type, models)
json.set! relationship do
json.data models do |model|
json.type type
json.id api_id(model)

yield model if block_given?
end
end
end
end
end
end
9 changes: 7 additions & 2 deletions app/models/forem/topic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class Topic < ActiveRecord::Base
validates :user, :presence => true

before_save :set_first_post_user
before_create :set_last_post_at
after_create :subscribe_poster
after_create :skip_pending_review, :unless => :moderated?

Expand Down Expand Up @@ -129,7 +130,11 @@ def last_page
protected
def set_first_post_user
post = posts.first
post.user = user
post.user = user if post
end

def set_last_post_at
self.last_post_at ||= created_at
end

def skip_pending_review
Expand All @@ -138,7 +143,7 @@ def skip_pending_review

def approve
first_post = posts.by_created_at.first
first_post.approve! unless first_post.approved?
first_post.approve! unless !first_post || first_post.approved?
end

def moderated?
Expand Down
42 changes: 42 additions & 0 deletions app/views/forem/api/v1/forums/show.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
included = []

json.data do
json.type "forums"
json.id @forum.id
json.attributes do
json.(@forum, :title, :slug)
end

json.relationships do
included += @topics

api_has_many(json, :topics, 'topics', @topics) do |topic|
last_post = relevant_posts(topic).last

if last_post
included << last_post

json.relationships do
json.last_post do
json.data do
json.type 'posts'
json.(last_post, :id)
end
end
end
end
end
end
end

json.included included do |object|
json.type object.class.name.demodulize.downcase.pluralize
json.(object, :id)

case object
when Forem::Topic
json.partial! 'forem/api/v1/topics/topic', topic: object
when Forem::Post
json.partial! 'forem/api/v1/posts/post', post: object
end
end
11 changes: 11 additions & 0 deletions app/views/forem/api/v1/posts/_post.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
json.type "posts"
json.(post, :id)
json.attributes do
json.(post, :text, :created_at)
end

json.relationships do
api_has_one(json, :user, 'users', post.user_id)
api_has_one(json, :topic, 'topics', post.topic_id)
api_has_one(json, :forum, 'forums', post.forum.id)
end
3 changes: 3 additions & 0 deletions app/views/forem/api/v1/posts/member_errors.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
json.errors @post.errors.full_messages do |message|
json.title message
end
3 changes: 3 additions & 0 deletions app/views/forem/api/v1/posts/show.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
json.data do
json.partial! 'forem/api/v1/posts/post', post: @post
end
11 changes: 11 additions & 0 deletions app/views/forem/api/v1/topics/_topic.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
json.type "topics"
json.(topic, :id)
json.attributes do
json.(topic, :slug, :subject, :views_count, :created_at)
json.posts_count relevant_posts(topic).count
end

json.relationships do
api_has_one(json, :user, 'users', topic.user_id)
api_has_one(json, :forum, 'forums', topic.forum_id)
end
3 changes: 3 additions & 0 deletions app/views/forem/api/v1/topics/member_errors.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
json.errors @topic.errors.full_messages do |message|
json.title message
end
Loading