diff options
| author | Marc Florisson | 2012-12-10 18:07:12 +0100 |
|---|---|---|
| committer | Marc Florisson | 2012-12-10 18:07:12 +0100 |
| commit | ffbe6d39c8050a63280566d8a4163bc4e7389809 (patch) | |
| tree | 53e30929c66f7dd44bb0b32b7e4752e3c5959624 | |
| parent | 4a0e5fe475fd7f852f67803a83c80238538bdb8f (diff) | |
| parent | 65f9199029841f1d0f97d9aabdc733d49b37032f (diff) | |
| download | chouette-core-ffbe6d39c8050a63280566d8a4163bc4e7389809.tar.bz2 | |
Merge branch 'api'
38 files changed, 535 insertions, 0 deletions
@@ -55,6 +55,8 @@ gem 'coffee-script-source' gem 'therubyrhino', :platform => :jruby gem 'therubyracer', :platform => :ruby +gem 'rabl' + # Gems used only for assets and not required # in production environments by default. group :assets do diff --git a/Gemfile.lock b/Gemfile.lock index 1fdad9d93..4d244381e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -238,6 +238,9 @@ GEM polyamorous (0.5.0) activerecord (~> 3.0) polyglot (0.3.3) + rabl (0.7.8) + activesupport (>= 2.3.14) + multi_json (~> 1.0) rack (1.4.1) rack-cache (1.2) rack (>= 0.4) @@ -385,6 +388,7 @@ DEPENDENCIES modernizr-rails (~> 2.0.6) ninoxe! pg (~> 0.11.0) + rabl rails (= 3.2.6) ransack rb-inotify diff --git a/app/controllers/api/v1/chouette_controller.rb b/app/controllers/api/v1/chouette_controller.rb new file mode 100644 index 000000000..1264e3484 --- /dev/null +++ b/app/controllers/api/v1/chouette_controller.rb @@ -0,0 +1,24 @@ +module Api + module V1 + class ChouetteController < ActionController::Base + respond_to :json, :xml + layout false + before_filter :authenticate + + def referential + @referential ||= @api_key.referential + end +private + def authenticate + authenticate_or_request_with_http_token do |token, options| + @api_key = ApiKey.new(token) + switch_referential if @api_key.exists? + end + end + def switch_referential + Apartment::Database.switch(referential.slug) + end + + end + end +end diff --git a/app/controllers/api/v1/companies_controller.rb b/app/controllers/api/v1/companies_controller.rb new file mode 100644 index 000000000..5e71d2eb5 --- /dev/null +++ b/app/controllers/api/v1/companies_controller.rb @@ -0,0 +1,13 @@ +class Api::V1::CompaniesController < Api::V1::ChouetteController + inherit_resources + + defaults :resource_class => Chouette::Company, :finder => :find_by_objectid! + +protected + + def collection + @companies ||= referential.companies.search(params[:q]).result(:distinct => true) + end + +end + diff --git a/app/controllers/api/v1/connection_links_controller.rb b/app/controllers/api/v1/connection_links_controller.rb new file mode 100644 index 000000000..b1e23d413 --- /dev/null +++ b/app/controllers/api/v1/connection_links_controller.rb @@ -0,0 +1,13 @@ +class Api::V1::ConnectionLinksController < Api::V1::ChouetteController + inherit_resources + + defaults :resource_class => Chouette::ConnectionLink, :finder => :find_by_objectid! + +protected + + def collection + @connection_links ||= referential.connection_links.search(params[:q]).result(:distinct => true) + end + +end + diff --git a/app/controllers/api/v1/journey_patterns_controller.rb b/app/controllers/api/v1/journey_patterns_controller.rb new file mode 100644 index 000000000..deab88af8 --- /dev/null +++ b/app/controllers/api/v1/journey_patterns_controller.rb @@ -0,0 +1,17 @@ +class Api::V1::JourneyPatternsController < Api::V1::ChouetteController + inherit_resources + + defaults :resource_class => Chouette::JourneyPattern, :finder => :find_by_objectid! + + belongs_to :line, :parent_class => Chouette::Line, :optional => true, :finder => :find_by_objectid!, :param => :line_id do + belongs_to :route, :parent_class => Chouette::Route, :optional => true, :finder => :find_by_objectid!, :param => :route_id + end + +protected + + def collection + @journey_patterns ||= parent.journey_patterns + end + +end + diff --git a/app/controllers/api/v1/lines_controller.rb b/app/controllers/api/v1/lines_controller.rb new file mode 100644 index 000000000..1df8a6618 --- /dev/null +++ b/app/controllers/api/v1/lines_controller.rb @@ -0,0 +1,17 @@ +module Api + module V1 + class LinesController < ChouetteController + inherit_resources + + defaults :resource_class => Chouette::Line, :finder => :find_by_objectid! + + protected + + def collection + @lines ||= referential.lines.search(params[:q]).result(:distinct => true) + end + end + end +end + + diff --git a/app/controllers/api/v1/networks_controller.rb b/app/controllers/api/v1/networks_controller.rb new file mode 100644 index 000000000..0b014e27b --- /dev/null +++ b/app/controllers/api/v1/networks_controller.rb @@ -0,0 +1,16 @@ +module Api + module V1 + class NetworksController < ChouetteController + inherit_resources + + defaults :resource_class => Chouette::Network, :finder => :find_by_objectid! + + protected + + def collection + @networks ||= referential.networks.search(params[:q]).result(:distinct => true) + end + end + end +end + diff --git a/app/controllers/api/v1/routes_controller.rb b/app/controllers/api/v1/routes_controller.rb new file mode 100644 index 000000000..e7a6ae0cf --- /dev/null +++ b/app/controllers/api/v1/routes_controller.rb @@ -0,0 +1,14 @@ +class Api::V1::RoutesController < Api::V1::ChouetteController + inherit_resources + + defaults :resource_class => Chouette::Route, :finder => :find_by_objectid! + + belongs_to :line, :parent_class => Chouette::Line, :optional => true, :finder => :find_by_objectid!, :param => :line_id + +protected + + def collection + @routes ||= parent.routes + end +end + diff --git a/app/controllers/api/v1/stop_areas_controller.rb b/app/controllers/api/v1/stop_areas_controller.rb new file mode 100644 index 000000000..2d5a176ae --- /dev/null +++ b/app/controllers/api/v1/stop_areas_controller.rb @@ -0,0 +1,21 @@ +class Api::V1::StopAreasController < Api::V1::ChouetteController + inherit_resources + + defaults :resource_class => Chouette::StopArea, :finder => :find_by_objectid! + + belongs_to :line, :parent_class => Chouette::Line, :optional => true, :finder => :find_by_objectid!, :param => :line_id do + belongs_to :route, :parent_class => Chouette::Route, :optional => true, :finder => :find_by_objectid!, :param => :route_id + end + +protected + + def collection + if parent + @stop_areas ||= parent.stop_areas.search(params[:q]).result(:distinct => true) + else + @stop_areas ||= referential.stop_areas.search(params[:q]).result(:distinct => true) + end + end + +end + diff --git a/app/controllers/api/v1/time_tables_controller.rb b/app/controllers/api/v1/time_tables_controller.rb new file mode 100644 index 000000000..eb54b5444 --- /dev/null +++ b/app/controllers/api/v1/time_tables_controller.rb @@ -0,0 +1,13 @@ +class Api::V1::TimeTablesController < Api::V1::ChouetteController + inherit_resources + + defaults :resource_class => Chouette::TimeTable, :finder => :find_by_objectid! + +protected + + def collection + @time_tables ||= referential.time_tables.search(params[:q]).result(:distinct => true) + end + +end + diff --git a/app/controllers/api/v1/vehicle_journeys_controller.rb b/app/controllers/api/v1/vehicle_journeys_controller.rb new file mode 100644 index 000000000..2dd78cc19 --- /dev/null +++ b/app/controllers/api/v1/vehicle_journeys_controller.rb @@ -0,0 +1,17 @@ +class Api::V1::VehicleJourneysController < Api::V1::ChouetteController + inherit_resources + + defaults :resource_class => Chouette::VehicleJourney, :finder => :find_by_objectid! + + belongs_to :line, :parent_class => Chouette::Line, :optional => true, :finder => :find_by_objectid!, :param => :line_id do + belongs_to :route, :parent_class => Chouette::Route, :optional => true, :finder => :find_by_objectid!, :param => :route_id + end + +protected + + def collection + @vehicle_journeys ||= parent.vehicle_journeys + end + +end + diff --git a/app/models/api/v1/api_key.rb b/app/models/api/v1/api_key.rb new file mode 100644 index 000000000..af029e5f7 --- /dev/null +++ b/app/models/api/v1/api_key.rb @@ -0,0 +1,32 @@ +module Api + module V1 + class ApiKey + def initialize(token) + @organisation_id, @referential_id = token.split('-') + end + def self.create( organisation, referential) + ApiKey.new( "#{organisation.id}-#{referential.id}") + end + def token + "#{@organisation_id}-#{@referential_id}" + end + def exists? + organisation && referential + end + def referential_slug + referential.slug + end + def referential + @referential ||= organisation.referentials.find_by_id @referential_id + end + def eql?(other) + other.token == self.token + end + private + def organisation + @organisation ||= Organisation.find_by_id @organisation_id + end + end + end +end + diff --git a/app/views/api/v1/companies/index.rabl b/app/views/api/v1/companies/index.rabl new file mode 100644 index 000000000..ff94da999 --- /dev/null +++ b/app/views/api/v1/companies/index.rabl @@ -0,0 +1,4 @@ +collection @companies + +extends "api/v1/companies/show" + diff --git a/app/views/api/v1/companies/show.rabl b/app/views/api/v1/companies/show.rabl new file mode 100644 index 000000000..b7234081c --- /dev/null +++ b/app/views/api/v1/companies/show.rabl @@ -0,0 +1,5 @@ +object @company +extends "api/v1/trident_objects/show" +attributes :name, :short_name, :organizational_unit, :operating_department_name +attributes :code, :phone, :fax, :email, :registration_number + diff --git a/app/views/api/v1/connection_links/index.rabl b/app/views/api/v1/connection_links/index.rabl new file mode 100644 index 000000000..d17d2c149 --- /dev/null +++ b/app/views/api/v1/connection_links/index.rabl @@ -0,0 +1,4 @@ +collection @connection_links + +extends "api/v1/connection_links/show" + diff --git a/app/views/api/v1/connection_links/show.rabl b/app/views/api/v1/connection_links/show.rabl new file mode 100644 index 000000000..ad3fae7dd --- /dev/null +++ b/app/views/api/v1/connection_links/show.rabl @@ -0,0 +1,13 @@ +object @connection_link +extends "api/v1/trident_objects/show" + +attributes :connection_link_type, :name, :comment +attributes :link_distance, :link_type, :default_duration, :frequent_traveller_duration, :occasional_traveller_duration +attributes :mobility_restricted_traveller_duration, :mobility_restricted_suitability, :stairs_availability, :lift_availability, :int_user_needs + +child :departure => :departure do + attributes :objectid, :name, :area_type, :longitude, :latitude, :long_lat_type +end +child :arrival => :arrival do + attributes :objectid, :name, :area_type, :longitude, :latitude, :long_lat_type +end diff --git a/app/views/api/v1/journey_patterns/index.rabl b/app/views/api/v1/journey_patterns/index.rabl new file mode 100644 index 000000000..4eb394669 --- /dev/null +++ b/app/views/api/v1/journey_patterns/index.rabl @@ -0,0 +1,4 @@ +collection @journey_patterns + +extends "api/v1/journey_patterns/show" + diff --git a/app/views/api/v1/journey_patterns/show.rabl b/app/views/api/v1/journey_patterns/show.rabl new file mode 100644 index 000000000..60eed951c --- /dev/null +++ b/app/views/api/v1/journey_patterns/show.rabl @@ -0,0 +1,22 @@ +object @journey_pattern +extends "api/v1/trident_objects/show" + +attributes :name, :comment, :registration_number +attributes :published_name + +child :route do + attributes :objectid, :name, :published_name, :number, :direction, :wayback +end +child :vehicle_journeys do |vj| + attributes :objectid +end +child :stop_points => :stop_areas do |stop_point| + node(:stop_area) do |n| + { :objectid => n.stop_area.objectid, :name => n.stop_area.name, + :parent => n.stop_area.parent.objectid, + :area_type => n.stop_area.area_type, + :longitude => n.stop_area.longitude, :latitude => n.stop_area.latitude, + :long_lat_type => n.stop_area.long_lat_type} + end +end + diff --git a/app/views/api/v1/lines/index.rabl b/app/views/api/v1/lines/index.rabl new file mode 100644 index 000000000..6c3f73022 --- /dev/null +++ b/app/views/api/v1/lines/index.rabl @@ -0,0 +1,4 @@ +collection @lines + +extends "api/v1/lines/show" + diff --git a/app/views/api/v1/lines/show.rabl b/app/views/api/v1/lines/show.rabl new file mode 100644 index 000000000..9c36d13b1 --- /dev/null +++ b/app/views/api/v1/lines/show.rabl @@ -0,0 +1,12 @@ +object @line +extends "api/v1/trident_objects/show" +attributes :name, :number, :published_name, :transport_mode_name +attributes :registration_number, :comment, :mobility_restricted_suitability, :int_user_needs + +child :network do + attributes :objectid, :name, :description, :registration_number +end + +child :company do + attributes :objectid, :name, :short_name, :registration_number +end diff --git a/app/views/api/v1/networks/index.rabl b/app/views/api/v1/networks/index.rabl new file mode 100644 index 000000000..124a65bee --- /dev/null +++ b/app/views/api/v1/networks/index.rabl @@ -0,0 +1,4 @@ +collection @networks + +extends "api/v1/networks/show" + diff --git a/app/views/api/v1/networks/show.rabl b/app/views/api/v1/networks/show.rabl new file mode 100644 index 000000000..7869ef7ec --- /dev/null +++ b/app/views/api/v1/networks/show.rabl @@ -0,0 +1,4 @@ +object @network +extends "api/v1/trident_objects/show" +attributes :version_date, :description, :name, :registration_number, :source_name +attributes :source_type, :source_identifier, :comment diff --git a/app/views/api/v1/routes/index.rabl b/app/views/api/v1/routes/index.rabl new file mode 100644 index 000000000..8f0eab32c --- /dev/null +++ b/app/views/api/v1/routes/index.rabl @@ -0,0 +1,3 @@ +collection @routes + +extends "api/v1/routes/show" diff --git a/app/views/api/v1/routes/show.rabl b/app/views/api/v1/routes/show.rabl new file mode 100644 index 000000000..2e481432d --- /dev/null +++ b/app/views/api/v1/routes/show.rabl @@ -0,0 +1,24 @@ +object @route +extends "api/v1/trident_objects/show" + +attributes :direction_code, :wayback_code, :name +attributes :comment, :opposite_route_id, :published_name, :number, :direction, :wayback + +child :line do + attributes :objectid, :name, :published_name, :number, :registration_number +end + +child :journey_patterns do |journey_pattern| + attributes :objectid, :name, :published_name, :registration_number +end + +child :vehicle_journeys do |vj| + attributes :objectid +end + +child :stop_areas do |stop_area| + attributes :objectid, :name, :area_type, :longitude, :latitude, :long_lat_type + glue stop_area.parent do + attributes :objectid => :parent + end +end diff --git a/app/views/api/v1/stop_areas/index.rabl b/app/views/api/v1/stop_areas/index.rabl new file mode 100644 index 000000000..0e253266e --- /dev/null +++ b/app/views/api/v1/stop_areas/index.rabl @@ -0,0 +1,3 @@ +collection @stop_areas + +extends "api/v1/stop_areas/show" diff --git a/app/views/api/v1/stop_areas/show.rabl b/app/views/api/v1/stop_areas/show.rabl new file mode 100644 index 000000000..db0f628bb --- /dev/null +++ b/app/views/api/v1/stop_areas/show.rabl @@ -0,0 +1,11 @@ +object @stop_area +extends "api/v1/trident_objects/show" + +attributes :routing_stop_ids, :routing_line_ids +attributes :name, :comment, :area_type, :registration_number +attributes :nearest_topic_name, :fare_code, :longitude, :latitude, :long_lat_type, :x, :y, :projection_type +attributes :country_code, :street_name + +child :parent => :parent do + attributes :objectid, :name, :area_type, :longitude, :latitude, :long_lat_type +end diff --git a/app/views/api/v1/time_tables/index.rabl b/app/views/api/v1/time_tables/index.rabl new file mode 100644 index 000000000..7f6371c88 --- /dev/null +++ b/app/views/api/v1/time_tables/index.rabl @@ -0,0 +1,3 @@ +collection @time_tables + +extends "api/v1/time_tables/show" diff --git a/app/views/api/v1/time_tables/show.rabl b/app/views/api/v1/time_tables/show.rabl new file mode 100644 index 000000000..90c5bc12c --- /dev/null +++ b/app/views/api/v1/time_tables/show.rabl @@ -0,0 +1,14 @@ +object @time_table +extends "api/v1/trident_objects/show" + +attributes :version, :comment +attributes :monday,:tuesday,:wednesday,:thursday,:friday,:saturday,:sunday + +child :dates => :dates do |date| + attributes :date, :position +end + +child :periods => :periods do |period| + attributes :period_start, :period_end +end + diff --git a/app/views/api/v1/trident_objects/show.rabl b/app/views/api/v1/trident_objects/show.rabl new file mode 100644 index 000000000..4f28ac822 --- /dev/null +++ b/app/views/api/v1/trident_objects/show.rabl @@ -0,0 +1,2 @@ +attributes :objectid, :object_version, :creation_time, :creator_id + diff --git a/app/views/api/v1/vehicle_journeys/index.rabl b/app/views/api/v1/vehicle_journeys/index.rabl new file mode 100644 index 000000000..f7d25f3b9 --- /dev/null +++ b/app/views/api/v1/vehicle_journeys/index.rabl @@ -0,0 +1,3 @@ +collection @vehicle_journeys + +extends "api/v1/vehicle_journeys/show" diff --git a/app/views/api/v1/vehicle_journeys/show.rabl b/app/views/api/v1/vehicle_journeys/show.rabl new file mode 100644 index 000000000..488fb4766 --- /dev/null +++ b/app/views/api/v1/vehicle_journeys/show.rabl @@ -0,0 +1,24 @@ +object @vehicle_journey +extends "api/v1/trident_objects/show" + +attributes :comment, :status_value +attributes :transport_mode, :published_journey_name, :published_journey_identifier, :facility, :vehicle_type_identifier, :number + +child :route do + attributes :objectid, :name, :published_name, :number, :direction, :wayback +end + +child :journey_pattern do + attributes :objectid, :name, :published_name, :registration_number +end + +child :time_tables do + attributes :objectid +end + +child :vehicle_journey_at_stops do |vjas| + attributes :position, :connecting_service_id, :boarding_alighting_possibility, :arrival_time, :departure_time, :waiting_time, :elapse_duration, :headway_frequency + node(:stop_area) do |vjas| + {:objectid => vjas.stop_point.stop_area.objectid} + end +end diff --git a/config/initializers/rabl_config.rb b/config/initializers/rabl_config.rb new file mode 100644 index 000000000..5e878de29 --- /dev/null +++ b/config/initializers/rabl_config.rb @@ -0,0 +1,4 @@ +Rabl.configure do |config| + config.include_json_root = false +end + diff --git a/config/routes.rb b/config/routes.rb index 9452c07d5..c4238a8a0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,7 +4,29 @@ ChouetteIhm::Application.routes.draw do match "/users/sign_up" => "subscriptions#new" end devise_for :users + + namespace :api do + namespace :v1 do + resources :time_tables, :only => [:index, :show] + resources :connection_links, :only => [:index, :show] + resources :companies, :only => [:index, :show] + resources :networks, :only => [:index, :show] + resources :stop_areas, :only => [:index, :show] + resources :lines, :only => [:index, :show] do + resources :journey_patterns, :only => [:index, :show] + resources :routes, :only => [:index, :show] do + resources :vehicle_journeys, :only => [:index, :show] + resources :journey_patterns, :only => [:index, :show] + resources :stop_areas, :only => [:index, :show] + end + end + resources :routes, :only => :show + resources :journey_patterns, :only => :show + resources :vehicle_journeys, :only => :show + end + end + resource :subscription resource :organisation do diff --git a/spec/controllers/api/v1/lines_controller_spec.rb b/spec/controllers/api/v1/lines_controller_spec.rb new file mode 100644 index 000000000..5bd8cac57 --- /dev/null +++ b/spec/controllers/api/v1/lines_controller_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +describe Api::V1::LinesController do + let!(:line) { referential.lines.first || create(:line) } + + it_behaves_like "api key protected controller" do + let(:data){line} + end + describe "GET #index" do + it "test" do + puts referential.inspect + puts "in spec api_key=#{api_key.inspect}" + end + end +end diff --git a/spec/controllers/api/v1/networks_controller_spec.rb b/spec/controllers/api/v1/networks_controller_spec.rb new file mode 100644 index 000000000..01e3ee35d --- /dev/null +++ b/spec/controllers/api/v1/networks_controller_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe Api::V1::NetworksController do + let!(:network) { referential.networks.first || create(:network) } + + it_behaves_like "api key protected controller" do + let(:data){network} + end + + describe "GET #show" do + context "when authorization provided and request.accept is json" do + before :each do + config_formatted_request_with_authorization( "application/json") + get :show, :id => network.objectid + end + + it "should assign expected network" do + assigns[:network].should == network + end + end + end + describe "GET #index" do + context "when authorization provided and request.accept is json" do + before :each do + config_formatted_request_with_authorization( "application/json") + get :index + end + + it "should assign expected networks" do + assigns[:networks].should == [network] + end + end + end + +end diff --git a/spec/support/api_key.rb b/spec/support/api_key.rb new file mode 100644 index 000000000..8c025bbad --- /dev/null +++ b/spec/support/api_key.rb @@ -0,0 +1,42 @@ +module ApiKeyHelper + + def get_api_key + Api::V1::ApiKey.create( referential.organisation, referential) + end + def config_formatted_request_with_authorization( format) + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Token.encode_credentials( get_api_key.token) + request.accept = format + end + def config_formatted_request_with_dummy_authorization( format) + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Token.encode_credentials( "dummy") + request.accept = format + end + def config_formatted_request_without_authorization( format) + request.env['HTTP_AUTHORIZATION'] = nil + request.accept = format + end + def json_xml_format? + request.accept == "application/json" || request.accept == "application/xml" + end + + def self.included(base) + base.class_eval do + extend ClassMethods + alias_method :api_key, :get_api_key + end + end + + module ClassMethods + def assign_api_key + before(:each) do + assign :api_key, api_key + end + end + end + +end + +RSpec.configure do |config| + config.include ApiKeyHelper +end + diff --git a/spec/support/api_key_protected.rb b/spec/support/api_key_protected.rb new file mode 100644 index 000000000..43256716d --- /dev/null +++ b/spec/support/api_key_protected.rb @@ -0,0 +1,51 @@ +shared_examples "api key protected controller" do + + let(:h) { { :index => (Proc.new { get :index }), + :show => (Proc.new { get :show, :id => data.objectid })}} + [:index, :show].each do |http_verb| + + describe "GET ##{http_verb}" do + ["application/json","application/xml","application/html"].each do |format| + context "when an invalid authorization is provided" do + before :each do + config_formatted_request_with_dummy_authorization( format) + h[http_verb].call + end + it "should return HTTP 401" do + response.response_code.should == 401 + end + end + context "when no authorization is provided" do + before :each do + config_formatted_request_without_authorization( format) + h[http_verb].call + end + it "should return HTTP 401" do + response.response_code.should == 401 + end + end + context "when authorization provided and request.accept is #{format}," do + before :each do + config_formatted_request_with_authorization( format) + h[http_verb].call + end + + it "should assign expected api_key" do + assigns[:api_key].should eql(api_key) if json_xml_format? + end + it "should assign expected referential" do + assigns[:referential].should == api_key.referential if json_xml_format? + end + + it "should return #{(format == "application/json" || format == "application/xml") ? "success" : "failure"} response" do + if json_xml_format? + response.should be_success + else + response.should_not be_success + end + end + end + end + end + end +end |
