diff --git a/Gemfile b/Gemfile index 22dc057ae..8c0bf4a43 100644 --- a/Gemfile +++ b/Gemfile @@ -39,6 +39,7 @@ gem 'kramdown-parser-gfm' gem 'faraday' gem 'koala' gem 'lazy_high_charts', '1.5.8' +gem 'connpass_api_v2' # https://github.com/sue445/connpass_api_v2-ruby # Protect from attacks for Security gem 'rack-attack' diff --git a/Gemfile.lock b/Gemfile.lock index fdc6c708b..72f41a435 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -123,6 +123,9 @@ GEM logger (~> 1.5) concurrent-ruby (1.3.5) connection_pool (2.5.3) + connpass_api_v2 (0.1.0) + faraday (>= 2.0.0) + faraday-mashify crass (1.0.6) csv (3.3.4) date (3.4.1) @@ -144,6 +147,9 @@ GEM faraday-net_http (>= 2.0, < 3.5) json logger + faraday-mashify (1.0.0) + faraday (~> 2.0) + hashie faraday-multipart (1.1.0) multipart-post (~> 2.0) faraday-net_http (3.4.0) @@ -165,6 +171,7 @@ GEM globalid (1.2.1) activesupport (>= 6.1) hash-deep-merge (0.1.1) + hashie (5.0.0) i18n (1.14.7) concurrent-ruby (~> 1.0) io-console (0.8.0) @@ -483,6 +490,7 @@ DEPENDENCIES bootsnap bootstrap-sass capybara + connpass_api_v2 csv dotenv-rails factory_bot_rails diff --git a/bin/c-search b/bin/c-search index 45e6fa79e..eadc71f1f 100755 --- a/bin/c-search +++ b/bin/c-search @@ -1,22 +1,42 @@ -#!/bin/sh -ENVRC_FILE=".envrc" +#!/usr/bin/env ruby -if [ ! -f "$ENVRC_FILE" ]; then - echo "$ENVRC_FILE が見つかりません" - exit 1 -fi +require 'connpass_api_v2' +require 'uri' -source "$ENVRC_FILE" +if ENV['CONNPASS_API_KEY'].nil? + puts('CONNPASS_API_KEY が設定されていません') + exit(1) +end -if [ -z "$FIXIE_URL" ]; then - echo "FIXIE_URL が設定されていません" - exit 1 -fi +if ARGV.empty? + puts('Usage: c-search [CONNPASS_EVENT_URL | CONNPASS_EVENT_ID]') + exit(1) +end -if [ $# -eq 0 ] -then - echo "Usage: c-search [CONNPASS_EVENT_URL | CONNPASS_EVENT_ID]" +input = ARGV[0] +event_id = nil +if input =~ /^https?:\/\// + # URLからイベントIDを抽出 + event_id = URI(input).path[%r{event/(\d+)}, 1] else - id=$(echo $1 | sed -e 's/[^0-9]//g') - curl -x "$FIXIE_URL" -sL "https://connpass.com/api/v1/event/?event_id=${id}" | jq ".events[].series.id" -fi + event_id = input.gsub(/\D/, '') +end + +unless event_id && !event_id.empty? + puts "イベントIDが特定できませんでした: #{input}" + exit 1 +end + +client = ConnpassApiV2.client(ENV['CONNPASS_API_KEY']) +result = client.get_events(event_id: event_id) + +if result.results_returned > 0 + event = result.events.first + puts event.fetch('id') + #puts "id: #{event.fetch('id')}" + #puts "title: #{event.fetch('title')}" + #puts "group_id: #{event.fetch('group').fetch('id')}" + #puts "group_name: #{event.fetch('group').fetch('title')}" +else + puts "イベントが見つかりませんでした (event_id: #{event_id})" +end diff --git a/bin/setup b/bin/setup index 05f09bc97..6dc3da99c 100755 --- a/bin/setup +++ b/bin/setup @@ -34,7 +34,7 @@ FileUtils.chdir APP_ROOT do #today = Time.now.in_time_zone('Tokyo').to_date #from = (today - 90).strftime('%Y%m') #to = today.prev_month.strftime('%Y%m') - #if ENV['DOORKEEPER_API_TOKEN'] && ENV['FIXIE_URL'] + #if ENV['DOORKEEPER_API_TOKEN'] && ENV['CONNPASS_API_KEY'] # system! "bin/rails statistics:aggregation[#{from},#{to}]" # system! 'bin/rails upcoming_events:aggregation' #elsif ENV['DOORKEEPER_API_TOKEN'] @@ -43,7 +43,7 @@ FileUtils.chdir APP_ROOT do # system! 'bin/rails upcoming_events:aggregation[connpass]' #else # puts <<~MESSAGE - # 環境変数 DOORKEEPER_API_TOKEN と FIXIE_URL が設定されていないため、 + # 環境変数 DOORKEEPER_API_TOKEN と CONNPASS_API_KEY が設定されていないため、 # Doorkeeper API や connpass API を使ったイベント情報の取得をスキップします。 # # なお API 経由でイベント情報を取得しなくても、rails server は実行可能です。 diff --git a/lib/event_service/client.rb b/lib/event_service/client.rb index aa02dd962..37ac7ad45 100644 --- a/lib/event_service/client.rb +++ b/lib/event_service/client.rb @@ -16,10 +16,10 @@ def get(path, params) def connection_for(endpoint, proxy) Faraday.new(endpoint, proxy: proxy) do |f| f.response :logger if self.class.debug - + # faraday標準のJSONパーサーを使用 f.response :json, parser_options: { symbolize_names: true } - + # faraday標準のエラーハンドリングを使用 f.response :raise_error, include_request: true diff --git a/lib/event_service/providers/connpass.rb b/lib/event_service/providers/connpass.rb index a6658c7be..fd730aa3a 100644 --- a/lib/event_service/providers/connpass.rb +++ b/lib/event_service/providers/connpass.rb @@ -1,25 +1,27 @@ +require 'connpass_api_v2' + module EventService module Providers class Connpass - ENDPOINT = 'https://connpass.com/api/v1'.freeze - # NOTE: 期間は ym or ymd パラメータで指定(複数指定可能)、未指定時全期間が対象 - def initialize - @client = EventService::Client.new(ENDPOINT, proxy: ENV['FIXIE_URL']) + @client = ConnpassApiV2.client(ENV['CONNPASS_API_KEY']) end def search(keyword:) - @client.get('event/', { keyword: keyword, count: 100 }) + @client.get_events(keyword: keyword, count: 100) end # NOTE: yyyymm, yyyymmdd は文字列を要素とする配列(Array[String])で指定 - def fetch_events(series_id:, yyyymm: nil, yyyymmdd: nil) - series_id = series_id.join(',') if series_id.is_a?(Array) + def fetch_events(group_id:, yyyymm: nil, yyyymmdd: nil) + group_id = group_id.join(',') if group_id.is_a?(Array) + # API v1 -> v2 でパラメータ名が変更された + # https://connpass.com/about/api/v2/ + # e.g. series_id -> group_id params = { - series_id: series_id, - start: 1, - count: 100 + group_id: group_id, + start: 1, # offset → start + count: 100 # limit → count } param_period_patern = [] @@ -35,17 +37,22 @@ def fetch_events(series_id:, yyyymm: nil, yyyymmdd: nil) param_period_patern.each do |param_period| loop do - # connpass は https://connpass.com/robots.txt を守らない場合は、アクセス制限を施すので、下記の sleep を入れるようにした https://connpass.com/about/api/ - sleep 5 - part = @client.get('event/', params.merge(param_period)) + begin + args = params.merge(param_period).compact + res = @client.get_events(**args) + rescue ConnpassApiV2::Error => e + sleep 5 && retry if e.response&.status == 403 + + raise e + end - break if part['results_returned'].zero? + break if res.results_returned.zero? - events.push(*part.fetch('events')) + events.push(*res.events) - break if part.size < params[:count] + break if res.events.size < params[:count] - break if params[:start] + params[:count] > part['results_available'] + break if params[:start] + params[:count] > res.results_available params[:start] += params[:count] end diff --git a/lib/event_service/providers/doorkeeper.rb b/lib/event_service/providers/doorkeeper.rb index d415f2f7f..c8d6c8387 100644 --- a/lib/event_service/providers/doorkeeper.rb +++ b/lib/event_service/providers/doorkeeper.rb @@ -6,7 +6,7 @@ class Doorkeeper def initialize @client = EventService::Client.new(ENDPOINT) do |c| - c.authorization(:Bearer, ENV.fetch('DOORKEEPER_API_TOKEN')) + c.request :authorization, 'Bearer', ENV.fetch('DOORKEEPER_API_TOKEN') end @default_since = '2010-07-01'.to_date.beginning_of_day @default_until = Time.zone.yesterday.end_of_day diff --git a/lib/statistics/tasks/connpass.rb b/lib/statistics/tasks/connpass.rb index 43d46175a..8b5cba779 100644 --- a/lib/statistics/tasks/connpass.rb +++ b/lib/statistics/tasks/connpass.rb @@ -20,7 +20,7 @@ def run dojo.dojo_event_services.for(:connpass).pluck(:group_id) end - @client.fetch_events(**@params.merge(series_id: group_ids)).each do |e| + @client.fetch_events(**@params.merge(group_id: group_ids)).each do |e| dojo_event_service = DojoEventService.find_by(group_id: e.dig('series', 'id').to_s) next unless dojo_event_service @@ -28,10 +28,11 @@ def run dojo_name: dojo_event_service.dojo.name, service_name: dojo_event_service.name, service_group_id: dojo_event_service.group_id, - event_id: e['event_id'], - event_url: e['event_url'], - participants: e['accepted'], - evented_at: Time.zone.parse(e['started_at'])) + event_id: e.fetch('id'), + event_url: e.fetch('event_url'), + participants: e.fetch('accepted'), + evented_at: Time.zone.parse(e.fetch('started_at')) + ) end end diff --git a/lib/statistics/tasks/doorkeeper.rb b/lib/statistics/tasks/doorkeeper.rb index 0e2df2ab3..0100edb30 100644 --- a/lib/statistics/tasks/doorkeeper.rb +++ b/lib/statistics/tasks/doorkeeper.rb @@ -18,7 +18,8 @@ def initialize(dojos, period) def run @dojos.each do |dojo| dojo.dojo_event_services.for(:doorkeeper).each do |dojo_event_service| - @client.fetch_events(**@params.merge(group_id: dojo_event_service.group_id)).each do |e| + events = @client.fetch_events(**@params.merge(group_id: dojo_event_service.group_id)) + (events || []).compact.each do |e| next unless e['group'].to_s == dojo_event_service.group_id EventHistory.create!(dojo_id: dojo.id, diff --git a/lib/upcoming_events/tasks/connpass.rb b/lib/upcoming_events/tasks/connpass.rb index 83704dcac..60f84431f 100644 --- a/lib/upcoming_events/tasks/connpass.rb +++ b/lib/upcoming_events/tasks/connpass.rb @@ -11,22 +11,25 @@ def run group_ids = @dojos.flat_map do |dojo| dojo.dojo_event_services.for(:connpass).pluck(:group_id) end - - @client.fetch_events(**@params.merge(series_id: group_ids)).each do |e| - dojo_event_service = DojoEventService.find_by(group_id: e.dig('series', 'id').to_s) + + events = @client.fetch_events(**@params.merge(group_id: group_ids)) + puts "[connpass] Fetched events: #{events.size}" + events.each do |e| + puts "[connpass] event_id: #{e.fetch('id')}, title: #{e.fetch('title')}" + dojo_event_service = DojoEventService.find_by(group_id: e.dig('group', 'id').to_s) next unless dojo_event_service - - record = dojo_event_service.upcoming_events.find_or_initialize_by(event_id: e['event_id']) + + record = dojo_event_service.upcoming_events.find_or_initialize_by(event_id: e.fetch('id')) record.update!(service_name: dojo_event_service.name, - event_title: e['title'], - event_url: e['event_url'], - event_at: Time.zone.parse(e['started_at']), - event_end_at: Time.zone.parse(e['ended_at']), - participants: e['accepted'], - event_update_at: Time.zone.parse(e['updated_at']), - address: e['address'], - place: e['place'], - limit: e['limit']) + event_title: e.fetch('title'), + event_url: e.fetch('url'), + event_at: Time.zone.parse(e.fetch('started_at')), + event_end_at: Time.zone.parse(e.fetch('ended_at')), + participants: e.fetch('accepted'), + event_update_at: Time.zone.parse(e.fetch('updated_at')), + address: e.fetch('address'), + place: e.fetch('place'), + limit: e.fetch('limit')) end end diff --git a/lib/upcoming_events/tasks/doorkeeper.rb b/lib/upcoming_events/tasks/doorkeeper.rb index fedf25653..5c4365ca2 100644 --- a/lib/upcoming_events/tasks/doorkeeper.rb +++ b/lib/upcoming_events/tasks/doorkeeper.rb @@ -10,20 +10,23 @@ def initialize(dojos, period) def run @dojos.each do |dojo| dojo.dojo_event_services.for(:doorkeeper).each do |dojo_event_service| - @client.fetch_events(**@params.merge(group_id: dojo_event_service.group_id)).each do |e| - next unless e['group'].to_s == dojo_event_service.group_id + events = @client.fetch_events(**@params.merge(group_id: dojo_event_service.group_id)) + puts "[Doorkeeper] dojo_id: #{dojo.id}, group_id: #{dojo_event_service.group_id}, fetched events: #{events&.size || 0}" + (events || []).compact.each do |e| + puts "[Doorkeeper] event_id: #{e.fetch('id')}, title: #{e.fetch('title')}" + next unless e.fetch('group').to_s == dojo_event_service.group_id - record = dojo_event_service.upcoming_events.find_or_initialize_by(event_id: e['id']) + record = dojo_event_service.upcoming_events.find_or_initialize_by(event_id: e.fetch('id')) record.update!(service_name: dojo_event_service.name, - event_title: e['title'], - event_url: e['public_url'], - participants: e['participants'], - event_at: Time.zone.parse(e['starts_at']), - event_end_at: Time.zone.parse(e['ends_at']), - event_update_at: Time.zone.parse(e['updated_at']), - address: e['address'], - place: e['venue_name'], - limit: e['ticket_limit']) + event_title: e.fetch('title'), + event_url: e.fetch('public_url'), + participants: e.fetch('participants'), + event_at: Time.zone.parse(e.fetch('starts_at')), + event_end_at: Time.zone.parse(e.fetch('ends_at')), + event_update_at: Time.zone.parse(e.fetch('updated_at')), + address: e.fetch('address'), + place: e.fetch('venue_name'), + limit: e.fetch('ticket_limit')) end end end diff --git a/spec/lib/event_service/providers/connpass_spec.rb b/spec/lib/event_service/providers/connpass_spec.rb index 88f5072bf..b8a462aca 100644 --- a/spec/lib/event_service/providers/connpass_spec.rb +++ b/spec/lib/event_service/providers/connpass_spec.rb @@ -8,40 +8,28 @@ subject { described_class.new.search(keyword: 'coderdojo') } it do - expect(subject).to be_instance_of(Hash) - expect(subject['results_returned']).to eq 1 - expect(subject['events'].size).to eq 1 - expect(subject['events'].first['event_id']).to eq 12345 - expect(subject['events'].first['series']['url']).to eq 'https://coderdojo-okutama.connpass.com/' - expect(subject['events'].first['series']['id']).to eq 9876 + expect(subject).to be_a(ConnpassApiV2::Response) + expect(subject.results_returned).to eq 100 + expect(subject.events).to be_a(Array) end end describe '#fetch_events' do - context 'when a single series_id is given' do - subject { described_class.new.fetch_events(series_id: 9876) } + context 'when a single group_id is given' do + subject { described_class.new.fetch_events(group_id: 9876) } it do - expect(subject).to be_instance_of(Array) - expect(subject.size).to eq 1 - expect(subject.first['event_id']).to eq 12345 - expect(subject.first['series']['url']).to eq 'https://coderdojo-okutama.connpass.com/' - expect(subject.first['series']['id']).to eq 9876 + expect(subject).to be_a(Array) + expect(subject.size).to eq 4 end end - context 'when multiple series_ids are given' do - subject { described_class.new.fetch_events(series_id: [9876, 9877]) } + context 'when multiple group_ids are given' do + subject { described_class.new.fetch_events(group_id: [9876, 9877]) } it do - expect(subject).to be_instance_of(Array) - expect(subject.size).to eq 2 - expect(subject.first['event_id']).to eq 12345 - expect(subject.first['series']['url']).to eq 'https://coderdojo-okutama.connpass.com/' - expect(subject.first['series']['id']).to eq 9876 - expect(subject.second['event_id']).to eq 12346 # assuming the second event has id 12346 - expect(subject.second['series']['url']).to eq 'https://coderdojo-okutama2.connpass.com/' - expect(subject.second['series']['id']).to eq 9877 + expect(subject).to be_a(Array) + expect(subject.size).to eq 5 end end end diff --git a/spec/lib/statistics/aggregation_spec.rb b/spec/lib/statistics/aggregation_spec.rb index 6500fb75e..70627275e 100644 --- a/spec/lib/statistics/aggregation_spec.rb +++ b/spec/lib/statistics/aggregation_spec.rb @@ -32,7 +32,7 @@ subject { Statistics::Aggregation.new(from: Time.zone.today.prev_month.strftime('%Y%m')).run } it do - expect{ subject }.to change{ EventHistory.count }.from(0).to(3) + expect{ subject }.to change{ EventHistory.count }.from(0).to(2) end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index b8c1f817b..a0ada5510 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,5 +1,6 @@ # This file is copied to spec/ when you run 'rails generate rspec:install' ENV['RAILS_ENV'] ||= 'test' +ENV['CONNPASS_API_KEY'] = 'DUMMY_CONNPASS_API_KEY' require File.expand_path('../../config/environment', __FILE__) # Prevent database truncation if the environment is production abort("The Rails environment is running in production mode!") if Rails.env.production? diff --git a/spec/support/shared_contexts/statistics.rb b/spec/support/shared_contexts/statistics.rb index 9ea76bd7f..329917e1f 100644 --- a/spec/support/shared_contexts/statistics.rb +++ b/spec/support/shared_contexts/statistics.rb @@ -4,12 +4,22 @@ f.response :json, :content_type => /\bjson$/ f.adapter :test, Faraday::Adapter::Test::Stubs.new do |stub| # connpass - stub.get('/event/') do |env| - if env.params["series_id"] == '9876,9877' - multiple_series_ids_response - else - connpass_response - end + stub.get('/events/') do |env| + puts "[DEBUG] Request path: #{env.url.path}" + puts "[DEBUG] Request params: #{env.params.inspect}" + group_id = env.params["group_id"] + group_id = group_id.join(',') if group_id.is_a?(Array) + group_id = group_id.to_s if group_id.is_a?(Integer) + puts "[DEBUG] group_id: #{group_id.inspect}" + response_json = + if group_id == '9876,9877' + multiple_series_ids_response[2] + elsif group_id == '9876' + connpass_response[2] + else + connpass_response[2] + end + ConnpassApiV2::Response.new(JSON.parse(response_json)) end # doorkeeper @@ -21,6 +31,15 @@ before do allow_any_instance_of(EventService::Client).to receive(:connection_for).and_return(stub_connection) + allow_any_instance_of(ConnpassApiV2::Client).to receive(:get_events) do |instance, **args| + if args[:group_id] == '9876,9877' + ConnpassApiV2::Response.new(JSON.parse(multiple_series_ids_response[2])) + elsif args[:group_id] == '9876' + ConnpassApiV2::Response.new(JSON.parse(connpass_response[2])) + else + ConnpassApiV2::Response.new(JSON.parse(connpass_response[2])) + end + end end end @@ -32,7 +51,13 @@ [ 200, { 'Content-Type' => 'application/json' }, - '{"results_returned": 2, "events": [{"event_url": "https://coderdojo-okutama.connpass.com/event/12345/", "event_type": "participation", "owner_nickname": "nalabjp", "series": {"url": "https://coderdojo-okutama.connpass.com/", "id": 9876, "title": "CoderDojo series"}, "updated_at": "2017-04-29T14:59:30+09:00", "lat": "35.801763000000", "started_at": "2017-05-07T10:00:00+09:00", "hash_tag": "CoderDojo", "title": "CoderDojo title", "event_id": 12345, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "2017-05-07T12:00:00+09:00", "place": "Tokyo"},{"event_url": "https://coderdojo-okutama.connpass.com/event/12346/", "event_type": "participation", "owner_nickname": "nalabjp", "series": {"url": "https://coderdojo-okutama2.connpass.com/", "id": 9877, "title": "CoderDojo series"}, "updated_at": "2017-04-29T14:59:30+09:00", "lat": "35.801763000000", "started_at": "2017-05-07T10:00:00+09:00", "hash_tag": "CoderDojo", "title": "CoderDojo title", "event_id": 12346, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "2017-05-07T12:00:00+09:00", "place": "Tokyo"}], "results_start": 200, "results_available": 518}' + '{"results_returned": 5, "events": [ + {"url": "https://coderdojo-okutama.connpass.com/event/12345/", "event_type": "participation", "owner_nickname": "nalabjp", "group": {"url": "https://coderdojo-okutama.connpass.com/", "id": 9876, "title": "CoderDojo series"}, "updated_at": "2017-04-29T14:59:30+09:00", "lat": "35.801763000000", "started_at": "2017-05-07T10:00:00+09:00", "hash_tag": "CoderDojo", "title": "CoderDojo title", "id": 12345, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "2017-05-07T12:00:00+09:00", "place": "Tokyo"}, + {"url": "https://coderdojo-okutama.connpass.com/event/12346/", "event_type": "participation", "owner_nickname": "nalabjp", "group": {"url": "https://coderdojo-okutama2.connpass.com/", "id": 9877, "title": "CoderDojo series"}, "updated_at": "2017-04-29T14:59:30+09:00", "lat": "35.801763000000", "started_at": "2017-05-07T10:00:00+09:00", "hash_tag": "CoderDojo", "title": "CoderDojo title", "id": 12346, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "2017-05-07T12:00:00+09:00", "place": "Tokyo"}, + {"url": "https://coderdojo-okutama.connpass.com/event/12347/", "event_type": "participation", "owner_nickname": "nalabjp", "group": {"url": "https://coderdojo-okutama2.connpass.com/", "id": 9877, "title": "CoderDojo series"}, "updated_at": "2017-04-29T14:59:30+09:00", "lat": "35.801763000000", "started_at": "2017-05-07T10:00:00+09:00", "hash_tag": "CoderDojo", "title": "CoderDojo title", "id": 12347, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "2017-05-07T12:00:00+09:00", "place": "Tokyo"}, + {"url": "https://coderdojo-okutama.connpass.com/event/12348/", "event_type": "participation", "owner_nickname": "nalabjp", "group": {"url": "https://coderdojo-okutama2.connpass.com/", "id": 9877, "title": "CoderDojo series"}, "updated_at": "2017-04-29T14:59:30+09:00", "lat": "35.801763000000", "started_at": "2017-05-07T10:00:00+09:00", "hash_tag": "CoderDojo", "title": "CoderDojo title", "id": 12348, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "2017-05-07T12:00:00+09:00", "place": "Tokyo"}, + {"url": "https://coderdojo-okutama.connpass.com/event/12349/", "event_type": "participation", "owner_nickname": "nalabjp", "group": {"url": "https://coderdojo-okutama2.connpass.com/", "id": 9877, "title": "CoderDojo series"}, "updated_at": "2017-04-29T14:59:30+09:00", "lat": "35.801763000000", "started_at": "2017-05-07T10:00:00+09:00", "hash_tag": "CoderDojo", "title": "CoderDojo title", "id": 12349, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "2017-05-07T12:00:00+09:00", "place": "Tokyo"} + ], "results_start": 200, "results_available": 518}' ] end @@ -41,7 +66,12 @@ [ 200, { 'Content-Type' => 'application/json' }, - '{"results_returned": 1, "events": [{"event_url": "https://coderdojo-okutama.connpass.com/event/12345/", "event_type": "participation", "owner_nickname": "nalabjp", "series": {"url": "https://coderdojo-okutama.connpass.com/", "id": 9876, "title": "CoderDojo series"}, "updated_at": "2017-04-29T14:59:30+09:00", "lat": "35.801763000000", "started_at": "2017-05-07T10:00:00+09:00", "hash_tag": "CoderDojo", "title": "CoderDojo title", "event_id": 12345, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "2017-05-07T12:00:00+09:00", "place": "Tokyo"}], "results_start": 200, "results_available": 518}' + '{"results_returned": 100, "events": [ + {"url": "https://coderdojo-okutama.connpass.com/event/12345/", "event_type": "participation", "owner_nickname": "nalabjp", "group": {"url": "https://coderdojo-okutama.connpass.com/", "id": 9876, "title": "CoderDojo series"}, "updated_at": "2017-04-29T14:59:30+09:00", "lat": "35.801763000000", "started_at": "2017-05-07T10:00:00+09:00", "hash_tag": "CoderDojo", "title": "CoderDojo title", "id": 12345, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "2017-05-07T12:00:00+09:00", "place": "Tokyo"}, + {"url": "https://coderdojo-okutama.connpass.com/event/12346/", "event_type": "participation", "owner_nickname": "nalabjp", "group": {"url": "https://coderdojo-okutama2.connpass.com/", "id": 9877, "title": "CoderDojo series"}, "updated_at": "2017-04-29T14:59:30+09:00", "lat": "35.801763000000", "started_at": "2017-05-07T10:00:00+09:00", "hash_tag": "CoderDojo", "title": "CoderDojo title", "id": 12346, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "2017-05-07T12:00:00+09:00", "place": "Tokyo"}, + {"url": "https://coderdojo-okutama.connpass.com/event/12347/", "event_type": "participation", "owner_nickname": "nalabjp", "group": {"url": "https://coderdojo-okutama2.connpass.com/", "id": 9877, "title": "CoderDojo series"}, "updated_at": "2017-04-29T14:59:30+09:00", "lat": "35.801763000000", "started_at": "2017-05-07T10:00:00+09:00", "hash_tag": "CoderDojo", "title": "CoderDojo title", "id": 12347, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "2017-05-07T12:00:00+09:00", "place": "Tokyo"}, + {"url": "https://coderdojo-okutama.connpass.com/event/12348/", "event_type": "participation", "owner_nickname": "nalabjp", "group": {"url": "https://coderdojo-okutama2.connpass.com/", "id": 9877, "title": "CoderDojo series"}, "updated_at": "2017-04-29T14:59:30+09:00", "lat": "35.801763000000", "started_at": "2017-05-07T10:00:00+09:00", "hash_tag": "CoderDojo", "title": "CoderDojo title", "id": 12348, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "2017-05-07T12:00:00+09:00", "place": "Tokyo"} + ], "results_start": 200, "results_available": 518}' ] end end @@ -65,10 +95,28 @@ [ 200, { 'Content-Type' => 'application/json' }, - '{"results_returned": 1, "events": [{"event_url": "https://coderdojo-okutama.connpass.com/event/12345/", "event_type": "participation", "owner_nickname": "nalabjp", "series": {"url": "https://coderdojo-okutama.connpass.com/", "id": 9876, "title": "CoderDojo series"}, "updated_at": "' + + '{"results_returned": 5, "events": [ + {"url": "https://coderdojo-okutama.connpass.com/event/12345/", "event_type": "participation", "owner_nickname": "nalabjp", "group": {"url": "https://coderdojo-okutama.connpass.com/", "id": 9876, "title": "CoderDojo series"}, "updated_at": "' + + "#{Time.zone.today}T14:59:30+09:00" + '", "lat": "35.801763000000", "started_at": "' + + "#{Time.zone.today + 1.month}T13:00:00+09:00" + '", "hash_tag": "CoderDojo", "title": "CoderDojo title", "id": 12345, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "' + + "#{Time.zone.today + 1.month}T15:00:00+09:00" + '", "place": "Tokyo"}, + {"url": "https://coderdojo-okutama.connpass.com/event/12346/", "event_type": "participation", "owner_nickname": "nalabjp", "group": {"url": "https://coderdojo-okutama2.connpass.com/", "id": 9877, "title": "CoderDojo series"}, "updated_at": "' + + "#{Time.zone.today}T14:59:30+09:00" + '", "lat": "35.801763000000", "started_at": "' + + "#{Time.zone.today + 1.month}T13:00:00+09:00" + '", "hash_tag": "CoderDojo", "title": "CoderDojo title", "id": 12346, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "' + + "#{Time.zone.today + 1.month}T15:00:00+09:00" + '", "place": "Tokyo"}, + {"url": "https://coderdojo-okutama.connpass.com/event/12347/", "event_type": "participation", "owner_nickname": "nalabjp", "group": {"url": "https://coderdojo-okutama2.connpass.com/", "id": 9877, "title": "CoderDojo series"}, "updated_at": "' + + "#{Time.zone.today}T14:59:30+09:00" + '", "lat": "35.801763000000", "started_at": "' + + "#{Time.zone.today + 1.month}T13:00:00+09:00" + '", "hash_tag": "CoderDojo", "title": "CoderDojo title", "id": 12347, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "' + + "#{Time.zone.today + 1.month}T15:00:00+09:00" + '", "place": "Tokyo"}, + {"url": "https://coderdojo-okutama.connpass.com/event/12348/", "event_type": "participation", "owner_nickname": "nalabjp", "group": {"url": "https://coderdojo-okutama2.connpass.com/", "id": 9877, "title": "CoderDojo series"}, "updated_at": "' + + "#{Time.zone.today}T14:59:30+09:00" + '", "lat": "35.801763000000", "started_at": "' + + "#{Time.zone.today + 1.month}T13:00:00+09:00" + '", "hash_tag": "CoderDojo", "title": "CoderDojo title", "id": 12348, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "' + + "#{Time.zone.today + 1.month}T15:00:00+09:00" + '", "place": "Tokyo"}, + {"url": "https://coderdojo-okutama.connpass.com/event/12349/", "event_type": "participation", "owner_nickname": "nalabjp", "group": {"url": "https://coderdojo-okutama2.connpass.com/", "id": 9877, "title": "CoderDojo series"}, "updated_at": "' + "#{Time.zone.today}T14:59:30+09:00" + '", "lat": "35.801763000000", "started_at": "' + - "#{Time.zone.today + 1.month}T13:00:00+09:00" + '", "hash_tag": "CoderDojo", "title": "CoderDojo title", "event_id": 12345, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "' + - "#{Time.zone.today + 1.month}T15:00:00+09:00" + '", "place": "Tokyo"}], "results_start": 200, "results_available": 518}' + "#{Time.zone.today + 1.month}T13:00:00+09:00" + '", "hash_tag": "CoderDojo", "title": "CoderDojo title", "id": 12349, "lon": "139.087656000000", "waiting": 2, "limit": 10, "owner_id": 2525, "owner_display_name": "nalabjp", "description": "CoderDojo description", "address": "Okutama-cho Tokyo", "catch": "CoderDojo catch", "accepted": 10, "ended_at": "' + + "#{Time.zone.today + 1.month}T15:00:00+09:00" + '", "place": "Tokyo"} + ], "results_start": 200, "results_available": 518}' ] end end