forked from mastodon/mastodon
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added admin api for managing tags (mastodon#26872)
- Loading branch information
Showing
5 changed files
with
219 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
# frozen_string_literal: true | ||
|
||
class Api::V1::Admin::TagsController < Api::BaseController | ||
include Authorization | ||
before_action -> { authorize_if_got_token! :'admin:read' }, only: [:index, :show] | ||
before_action -> { authorize_if_got_token! :'admin:write' }, only: :update | ||
|
||
before_action :set_tags, only: :index | ||
before_action :set_tag, except: :index | ||
|
||
after_action :insert_pagination_headers, only: :index | ||
after_action :verify_authorized | ||
|
||
LIMIT = 100 | ||
PAGINATION_PARAMS = %i(limit).freeze | ||
|
||
def index | ||
authorize :tag, :index? | ||
render json: @tags, each_serializer: REST::Admin::TagSerializer | ||
end | ||
|
||
def show | ||
authorize @tag, :show? | ||
render json: @tag, serializer: REST::Admin::TagSerializer | ||
end | ||
|
||
def update | ||
authorize @tag, :update? | ||
@tag.update!(tag_params.merge(reviewed_at: Time.now.utc)) | ||
render json: @tag, serializer: REST::Admin::TagSerializer | ||
end | ||
|
||
private | ||
|
||
def set_tag | ||
@tag = Tag.find(params[:id]) | ||
end | ||
|
||
def set_tags | ||
@tags = Tag.all.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id)) | ||
end | ||
|
||
def tag_params | ||
params.permit(:display_name, :trendable, :usable, :listable) | ||
end | ||
|
||
def insert_pagination_headers | ||
set_pagination_headers(next_path, prev_path) | ||
end | ||
|
||
def next_path | ||
api_v1_admin_tags_url(pagination_params(max_id: pagination_max_id)) if records_continue? | ||
end | ||
|
||
def prev_path | ||
api_v1_admin_tags_url(pagination_params(min_id: pagination_since_id)) unless @tags.empty? | ||
end | ||
|
||
def pagination_max_id | ||
@tags.last.id | ||
end | ||
|
||
def pagination_since_id | ||
@tags.first.id | ||
end | ||
|
||
def records_continue? | ||
@tags.size == limit_param(LIMIT) | ||
end | ||
|
||
def pagination_params(core_params) | ||
params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -280,6 +280,8 @@ | |
post :test | ||
end | ||
end | ||
|
||
resources :tags, only: [:index, :show, :update] | ||
end | ||
end | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'rails_helper' | ||
|
||
RSpec.describe 'Tags' do | ||
let(:role) { UserRole.find_by(name: 'Admin') } | ||
let(:user) { Fabricate(:user, role: role) } | ||
let(:scopes) { 'admin:read admin:write' } | ||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } | ||
let(:tag) { Fabricate(:tag) } | ||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } | ||
|
||
describe 'GET /api/v1/admin/tags' do | ||
subject do | ||
get '/api/v1/admin/tags', headers: headers, params: params | ||
end | ||
|
||
let(:params) { {} } | ||
|
||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' | ||
it_behaves_like 'forbidden for wrong role', '' | ||
|
||
it 'returns http success' do | ||
subject | ||
|
||
expect(response).to have_http_status(200) | ||
end | ||
|
||
context 'when there are no tags' do | ||
it 'returns an empty list' do | ||
subject | ||
|
||
expect(body_as_json).to be_empty | ||
end | ||
end | ||
|
||
context 'when there are tagss' do | ||
let!(:tags) do | ||
[ | ||
Fabricate(:tag), | ||
Fabricate(:tag), | ||
Fabricate(:tag), | ||
Fabricate(:tag), | ||
] | ||
end | ||
|
||
it 'returns the expected tags' do | ||
subject | ||
tags.each do |tag| | ||
expect(body_as_json.find { |item| item[:id] == tag.id.to_s && item[:name] == tag.name }).to_not be_nil | ||
end | ||
end | ||
|
||
context 'with limit param' do | ||
let(:params) { { limit: 2 } } | ||
|
||
it 'returns only the requested number of tags' do | ||
subject | ||
|
||
expect(body_as_json.size).to eq(params[:limit]) | ||
end | ||
end | ||
end | ||
end | ||
|
||
describe 'GET /api/v1/admin/tags/:id' do | ||
subject do | ||
get "/api/v1/admin/tags/#{tag.id}", headers: headers | ||
end | ||
|
||
let!(:tag) { Fabricate(:tag) } | ||
|
||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' | ||
it_behaves_like 'forbidden for wrong role', '' | ||
|
||
it 'returns http success' do | ||
subject | ||
|
||
expect(response).to have_http_status(200) | ||
end | ||
|
||
it 'returns expected tag content' do | ||
subject | ||
|
||
expect(body_as_json[:id].to_i).to eq(tag.id) | ||
expect(body_as_json[:name]).to eq(tag.name) | ||
end | ||
|
||
context 'when the requested tag does not exist' do | ||
it 'returns http not found' do | ||
get '/api/v1/admin/tags/-1', headers: headers | ||
|
||
expect(response).to have_http_status(404) | ||
end | ||
end | ||
end | ||
|
||
describe 'PUT /api/v1/admin/tags/:id' do | ||
subject do | ||
put "/api/v1/admin/tags/#{tag.id}", headers: headers, params: params | ||
end | ||
|
||
let!(:tag) { Fabricate(:tag) } | ||
let(:params) { { display_name: tag.name.upcase } } | ||
|
||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' | ||
it_behaves_like 'forbidden for wrong scope', 'admin:read' | ||
it_behaves_like 'forbidden for wrong role', '' | ||
|
||
it 'returns http success' do | ||
subject | ||
|
||
expect(response).to have_http_status(200) | ||
end | ||
|
||
it 'returns updated tag' do | ||
subject | ||
|
||
expect(body_as_json[:id].to_i).to eq(tag.id) | ||
expect(body_as_json[:name]).to eq(tag.name.upcase) | ||
end | ||
|
||
context 'when the updated display name is invalid' do | ||
let(:params) { { display_name: tag.name + tag.id.to_s } } | ||
|
||
it 'returns http unprocessable content' do | ||
subject | ||
|
||
expect(response).to have_http_status(422) | ||
end | ||
end | ||
|
||
context 'when the requested tag does not exist' do | ||
it 'returns http not found' do | ||
get '/api/v1/admin/tags/-1', headers: headers | ||
|
||
expect(response).to have_http_status(404) | ||
end | ||
end | ||
end | ||
end |