Added admin api for managing tags (#26872)

pull/2406/head
Robert R George 2023-09-13 02:22:53 -07:00 committed by GitHub
parent 97e4011c3c
commit 20666482ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 219 additions and 1 deletions

View File

@ -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

View File

@ -20,6 +20,7 @@
#
class Tag < ApplicationRecord
include Paginable
has_and_belongs_to_many :statuses
has_and_belongs_to_many :accounts

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
class REST::Admin::TagSerializer < REST::TagSerializer
attributes :id, :trendable, :usable, :requires_review
attributes :id, :trendable, :usable, :requires_review, :listable
def id
object.id.to_s

View File

@ -280,6 +280,8 @@ namespace :api, format: false do
post :test
end
end
resources :tags, only: [:index, :show, :update]
end
end

View File

@ -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