Skip to content

Commit

Permalink
Lists (mastodon#5703)
Browse files Browse the repository at this point in the history
* Add structure for lists

* Add list timeline streaming API

* Add list APIs, bind list-account relation to follow relation

* Add API for adding/removing accounts from lists

* Add pagination to lists API

* Add pagination to list accounts API

* Adjust scopes for new APIs

- Creating and modifying lists merely requires "write" scope
- Fetching information about lists merely requires "read" scope

* Add test for wrong user context on list timeline

* Clean up tests
  • Loading branch information
Gargron authored and cobodo committed Dec 6, 2017
1 parent 0543b4f commit 0791334
Show file tree
Hide file tree
Showing 67 changed files with 856 additions and 225 deletions.
81 changes: 81 additions & 0 deletions app/controllers/api/v1/lists/accounts_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# frozen_string_literal: true

class Api::V1::Lists::AccountsController < Api::BaseController
before_action -> { doorkeeper_authorize! :read }, only: [:show]
before_action -> { doorkeeper_authorize! :write }, except: [:show]

before_action :require_user!
before_action :set_list

after_action :insert_pagination_headers, only: :show

def show
@accounts = @list.accounts.paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id])
render json: @accounts, each_serializer: REST::AccountSerializer
end

def create
ApplicationRecord.transaction do
list_accounts.each do |account|
@list.accounts << account
end
end

render_empty
end

def destroy
ListAccount.where(list: @list, account_id: account_ids).destroy_all
render_empty
end

private

def set_list
@list = List.where(account: current_account).find(params[:list_id])
end

def list_accounts
Account.find(account_ids)
end

def account_ids
Array(resource_params[:account_ids])
end

def resource_params
params.permit(account_ids: [])
end

def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end

def next_path
if records_continue?
api_v1_list_accounts_url pagination_params(max_id: pagination_max_id)
end
end

def prev_path
unless @accounts.empty?
api_v1_list_accounts_url pagination_params(since_id: pagination_since_id)
end
end

def pagination_max_id
@accounts.last.id
end

def pagination_since_id
@accounts.first.id
end

def records_continue?
@accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)
end

def pagination_params(core_params)
params.permit(:limit).merge(core_params)
end
end
79 changes: 79 additions & 0 deletions app/controllers/api/v1/lists_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# frozen_string_literal: true

class Api::V1::ListsController < Api::BaseController
LISTS_LIMIT = 50

before_action -> { doorkeeper_authorize! :read }, only: [:index, :show]
before_action -> { doorkeeper_authorize! :write }, except: [:index, :show]

before_action :require_user!
before_action :set_list, except: [:index, :create]

after_action :insert_pagination_headers, only: :index

def index
@lists = List.where(account: current_account).paginate_by_max_id(limit_param(LISTS_LIMIT), params[:max_id], params[:since_id])
render json: @lists, each_serializer: REST::ListSerializer
end

def show
render json: @list, serializer: REST::ListSerializer
end

def create
@list = List.create!(list_params.merge(account: current_account))
render json: @list, serializer: REST::ListSerializer
end

def update
@list.update!(list_params)
render json: @list, serializer: REST::ListSerializer
end

def destroy
@list.destroy!
render_empty
end

private

def set_list
@list = List.where(account: current_account).find(params[:id])
end

def list_params
params.permit(:title)
end

def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end

def next_path
if records_continue?
api_v1_lists_url pagination_params(max_id: pagination_max_id)
end
end

def prev_path
unless @lists.empty?
api_v1_lists_url pagination_params(since_id: pagination_since_id)
end
end

def pagination_max_id
@lists.last.id
end

def pagination_since_id
@lists.first.id
end

def records_continue?
@lists.size == limit_param(LISTS_LIMIT)
end

def pagination_params(core_params)
params.permit(:limit).merge(core_params)
end
end
2 changes: 1 addition & 1 deletion app/controllers/api/v1/timelines/home_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def home_statuses
end

def account_home_feed
Feed.new(:home, current_account)
HomeFeed.new(current_account)
end

def insert_pagination_headers
Expand Down
66 changes: 66 additions & 0 deletions app/controllers/api/v1/timelines/list_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# frozen_string_literal: true

class Api::V1::Timelines::ListController < Api::BaseController
before_action -> { doorkeeper_authorize! :read }
before_action :require_user!
before_action :set_list
before_action :set_statuses

after_action :insert_pagination_headers, unless: -> { @statuses.empty? }

def show
render json: @statuses,
each_serializer: REST::StatusSerializer,
relationships: StatusRelationshipsPresenter.new(@statuses, current_user.account_id)
end

private

def set_list
@list = List.where(account: current_account).find(params[:id])
end

def set_statuses
@statuses = cached_list_statuses
end

def cached_list_statuses
cache_collection list_statuses, Status
end

def list_statuses
list_feed.get(
limit_param(DEFAULT_STATUSES_LIMIT),
params[:max_id],
params[:since_id]
)
end

def list_feed
ListFeed.new(@list)
end

def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end

def pagination_params(core_params)
params.permit(:limit).merge(core_params)
end

def next_path
api_v1_timelines_list_url params[:id], pagination_params(max_id: pagination_max_id)
end

def prev_path
api_v1_timelines_list_url params[:id], pagination_params(since_id: pagination_since_id)
end

def pagination_max_id
@statuses.last.id
end

def pagination_since_id
@statuses.first.id
end
end
Loading

0 comments on commit 0791334

Please sign in to comment.