Skip to content

Commit

Permalink
added repository-prefixes api endpoint. #363
Browse files Browse the repository at this point in the history
  • Loading branch information
Martin Fenner committed Nov 25, 2019
1 parent d3a9b58 commit 2957ca5
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 1 deletion.
140 changes: 140 additions & 0 deletions app/controllers/repository_prefixes_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
require 'base32/url'
require 'uri'

class RepositoryPrefixesController < ApplicationController
before_action :set_client_prefix, only: [:show, :update, :destroy]
before_action :authenticate_user!
before_action :set_include

def index
# support nested routes
if params[:id].present?
collection = ClientPrefix.where(id: params[:id])
elsif params[:client_id].present? && params[:prefix_id].present?
collection = ClientPrefix.joins(:client, :prefix).where('datacentre.symbol = ?', params[:client_id]).where('prefix.prefix = ?', params[:prefix_id])
elsif params[:client_id].present?
client = Client.where('datacentre.symbol = ?', params[:client_id]).first
collection = client.present? ? client.client_prefixes.joins(:prefix) : ClientPrefix.none
elsif params[:prefix_id].present?
prefix = Prefix.where('prefix.prefix = ?', params[:prefix_id]).first
collection = prefix.present? ? prefix.client_prefixes.joins(:client) : ClientPrefix.none
else
collection = ClientPrefix.joins(:client, :prefix)
end

collection = collection.query(params[:query]) if params[:query].present?
collection = collection.where('YEAR(datacentre_prefixes.created_at) = ?', params[:year]) if params[:year].present?

if params[:year].present?
years = [{ id: params[:year],
title: params[:year],
count: collection.where('YEAR(datacentre_prefixes.created_at) = ?', params[:year]).count }]
else
years = collection.where.not(prefixes: nil).order("YEAR(datacentre_prefixes.created_at) DESC").group("YEAR(datacentre_prefixes.created_at)").count
years = years.map { |k,v| { id: k.to_s, title: k.to_s, count: v } }
end

page = page_from_params(params)
total = collection.count

order = case params[:sort]
when "name" then "prefix.prefix"
when "-name" then "prefix.prefix DESC"
when "created" then "datacentre_prefixes.created_at"
else "datacentre_prefixes.created_at DESC"
end

@client_prefixes = collection.order(order).page(page[:number]).per(page[:size])

options = {}
options[:meta] = {
total: total,
"totalPages" => @client_prefixes.total_pages,
page: page[:number].to_i,
years: years
}.compact

options[:links] = {
self: request.original_url,
next: @client_prefixes.blank? ? nil : request.base_url + "/client-prefixes?" + {
query: params[:query],
year: params[:year],
"page[number]" => params.dig(:page, :number).to_i + 1,
"page[size]" => params.dig(:page, :size),
sort: params[:sort] }.compact.to_query
}.compact
options[:include] = @include
options[:is_collection] = true

render json: RepositoryPrefixSerializer.new(@client_prefixes, options).serialized_json, status: :ok
end

def show
authorize! :show, @client_prefix
options = {}
options[:include] = @include
options[:is_collection] = false

render json: RepositoryPrefixSerializer.new(@client_prefix, options).serialized_json, status: :ok
end

def create
logger = Logger.new(STDOUT)
@client_prefix = ClientPrefix.new(safe_params)
authorize! :create, @client_prefix

if @client_prefix.save
options = {}
options[:include] = @include
options[:is_collection] = false

render json: RepositoryPrefixSerializer.new(@client_prefix, options).serialized_json, status: :created
else
logger.warn @client_prefix.errors.inspect
render json: serialize_errors(@client_prefix.errors), status: :unprocessable_entity
end
end

def update
authorize! :update, @client_prefix
response.headers["Allow"] = "HEAD, GET, POST, DELETE, OPTIONS"
render json: { errors: [{ status: "405", title: "Method not allowed" }] }.to_json, status: :method_not_allowed
end

def destroy
authorize! :destroy, @client_prefix
@client_prefix.destroy
head :no_content
end

protected

def set_include
if params[:include].present?
@include = params[:include].split(",").map { |i| i.downcase.underscore.to_sym }
@include = @include & [:repository, :prefix, :provider_prefix, :provider]
else
# always include because Ember pagination doesn't (yet) understand include parameter
@include = [:repository, :prefix, :provider_prefix, :provider]
end
end

private

# Use callbacks to share common setup or constraints between actions.
def set_client_prefix
id = Base32::URL.decode(URI.decode(params[:id]))
fail ActiveRecord::RecordNotFound unless id.present?

@client_prefix = ClientPrefix.where(id: id.to_i).first

fail ActiveRecord::RecordNotFound unless @client_prefix.present?
end

def safe_params
ActiveModelSerializers::Deserialization.jsonapi_parse!(
params, only: [:id, :repository, :prefix, :providerPrefix],
keys: { repository: :client, "providerPrefix" => :provider_prefix }
)
end
end
12 changes: 12 additions & 0 deletions app/models/client_prefix.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ def client_id=(value)
self.datacentre = r.id
end

def repository_id
client_symbol.downcase
end

# workaround for non-standard database column names and association
def repository_id=(value)
r = ::Client.where(symbol: value).first
fail ActiveRecord::RecordNotFound unless r.present?

self.datacentre = r.id
end

def prefix_id
prefix.prefix
end
Expand Down
14 changes: 14 additions & 0 deletions app/serializers/repository_prefix_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class RepositoryPrefixSerializer
include FastJsonapi::ObjectSerializer
set_key_transform :camel_lower
set_type "repository-prefixes"
set_id :uid
cache_options enabled: true, cache_length: 24.hours

attributes :created, :updated

belongs_to :repository, object_method_name: :client, id_method_name: :client_id, record_type: :repositories
belongs_to :provider, record_type: :providers
belongs_to :provider_prefix, record_type: :provider_prefixes
belongs_to :prefix, record_type: :prefixes
end
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
resources :prefixes, constraints: { :id => /.+/ }
end
resources :providers, constraints: { :id => /.+/ }
resources :repository_prefixes, path: "repository-prefixes"
resources :resource_types, path: 'resource-types', only: [:show, :index]

# custom routes for maintenance tasks
Expand Down
2 changes: 1 addition & 1 deletion spec/requests/client_prefixes_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
let(:valid_attributes) do
{
"data" => {
"type" => "provider-prefixes",
"type" => "client-prefixes",
"relationships": {
"client": {
"data":{
Expand Down
107 changes: 107 additions & 0 deletions spec/requests/repository_prefixes_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
require 'rails_helper'

describe "Repository Prefixes", type: :request do
let!(:client_prefixes) { create_list(:client_prefix, 5) }
let(:client_prefix) { create(:client_prefix) }
let(:bearer) { User.generate_token(role_id: "staff_admin") }
let(:headers) { {'HTTP_ACCEPT'=>'application/vnd.api+json', 'HTTP_AUTHORIZATION' => 'Bearer ' + bearer }}

describe 'GET /repository-prefixes' do
it 'returns repository-prefixes' do
get '/repository-prefixes', nil, headers

expect(last_response.status).to eq(200)
expect(json['data'].size).to eq(5)
end
end

describe 'GET /repository-prefixes/:uid' do
context 'when the record exists' do
it 'returns the repository-prefix' do
get "/repository-prefixes/#{client_prefix.uid}", nil, headers

expect(last_response.status).to eq(200)
expect(json.dig("data", "id")).to eq(client_prefix.uid)
end
end

context 'when the record does not exist' do
it 'returns status code 404' do
get "/repository-prefixes/xxx", nil, headers

expect(last_response.status).to eq(404)
expect(json["errors"].first).to eq("status"=>"404", "title"=>"The resource you are looking for doesn't exist.")
end
end
end

describe 'PATCH /repository-prefixes/:uid' do
it 'returns method not supported error' do
patch "/repository-prefixes/#{client_prefix.uid}", nil, headers

expect(last_response.status).to eq(405)
expect(json.dig("errors")).to eq([{"status"=>"405", "title"=>"Method not allowed"}])
end
end

describe 'POST /repository-prefixes' do
context 'when the request is valid' do
let(:provider) { create(:provider) }
let(:client) { create(:client, provider: provider) }
let(:prefix) { create(:prefix) }
let(:provider_prefix) { create(:provider_prefix, provider: provider, prefix: prefix) }
let(:valid_attributes) do
{
"data" => {
"type" => "repository-prefixes",
"relationships": {
"repository": {
"data":{
"type": "repositories",
"id": client.symbol.downcase
}
},
"provider-prefix": {
"data":{
"type": "provider-prefixes",
"id": provider_prefix.prefix
}
},
"prefix": {
"data":{
"type": "prefixes",
"id": prefix.prefix
}
}
}
}
}
end

it 'creates a repository-prefix' do
post '/repository-prefixes', valid_attributes, headers

expect(last_response.status).to eq(201)
expect(json.dig('data', 'id')).not_to be_nil
end
end

context 'when the request is invalid' do
let!(:client) { create(:client) }
let(:not_valid_attributes) do
{
"data" => {
"type" => "repository-prefixes"
}
}
end

it 'returns status code 422' do
post '/repository-prefixes', not_valid_attributes, headers

expect(last_response.status).to eq(422)
expect(json["errors"].first).to eq("source"=>"client", "title"=>"Must exist")
end
end
end
end

0 comments on commit 2957ca5

Please sign in to comment.