Skip to content

Commit

Permalink
Added admin api for managing tags (#26872)
Browse files Browse the repository at this point in the history
  • Loading branch information
rrgeorge committed Sep 13, 2023
1 parent 97e4011 commit 2066648
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 1 deletion.
74 changes: 74 additions & 0 deletions app/controllers/api/v1/admin/tags_controller.rb
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
1 change: 1 addition & 0 deletions app/models/tag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#

class Tag < ApplicationRecord
include Paginable
has_and_belongs_to_many :statuses
has_and_belongs_to_many :accounts

Expand Down
2 changes: 1 addition & 1 deletion app/serializers/rest/admin/tag_serializer.rb
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 2 additions & 0 deletions config/routes/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@
post :test
end
end

resources :tags, only: [:index, :show, :update]
end
end

Expand Down
141 changes: 141 additions & 0 deletions spec/requests/api/v1/admin/tags_spec.rb
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

0 comments on commit 2066648

Please sign in to comment.