Skip to content

[WIP]直近のイベント情報を集計するtaskの追加 #297

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ group :development do
gem 'web-console'
gem 'spring'
gem 'listen'
gem 'dotenv-rails'
end

group :development, :test do
Expand Down
7 changes: 6 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ GEM
declarative (0.0.10)
declarative-option (0.1.0)
diff-lcs (1.3)
dotenv (2.5.0)
dotenv-rails (2.5.0)
dotenv (= 2.5.0)
railties (>= 3.2, < 6.0)
erubi (1.7.1)
erubis (2.7.0)
ethon (0.11.0)
Expand Down Expand Up @@ -385,6 +389,7 @@ DEPENDENCIES
bootstrap-sass
capybara
coffee-rails
dotenv-rails
faraday
faraday_middleware (= 0.10)
font-awesome-rails
Expand Down Expand Up @@ -426,4 +431,4 @@ RUBY VERSION
ruby 2.4.2p198

BUNDLED WITH
1.16.1
1.16.3
2 changes: 2 additions & 0 deletions app/models/dojo_event_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ class DojoEventService < ApplicationRecord
EXTERNAL_SERVICES = %i( connpass doorkeeper facebook )
INTERNAL_SERVICES = %i( static_yaml )

has_many :upcoming_events

belongs_to :dojo
enum name: EXTERNAL_SERVICES + INTERNAL_SERVICES

Expand Down
12 changes: 12 additions & 0 deletions app/models/upcoming_event.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class UpcomingEvent < ApplicationRecord
belongs_to :dojo
belongs_to :dojo_event_service

validates :dojo_event_service_id, presence: true
validates :event_id, presence: true
validates :event_url,presence: true

validates :event_at,presence: true

scope :for, ->(service) { UpcomingEvent.where(dojo_event_service: DojoEventService.for(service)) }
end
9 changes: 9 additions & 0 deletions lib/tasks/upcoming.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require_relative '../upcoming.rb'

namespace :upcoming do
desc '月次のイベント開催予定を集計します'
task :aggregation, [:from, :to] => :environment do |tasks, args|
EventService::Providers::Facebook.access_token = Koala::Facebook::OAuth.new(ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_APP_SECRET']).get_app_access_token
Upcoming::Aggregation.new(args).run
end
end
5 changes: 5 additions & 0 deletions lib/upcoming.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Upcoming; end

require_relative 'upcoming/tasks'
require_relative 'upcoming/aggregation'
require_relative 'event_service'
133 changes: 133 additions & 0 deletions lib/upcoming/aggregation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
module Upcoming
class Aggregation
def initialize(args)
@from = Time.current.beginning_of_week
@to = Time.current.next_month
@dojos = fetch_dojos
end

def run
Upcoming::Aggregation::Monthly.new(@dojos, @from, @to).run
end

private

def fetch_dojos
{
externals: find_dojos_by(DojoEventService::EXTERNAL_SERVICES),
internals: find_dojos_by(DojoEventService::INTERNAL_SERVICES)
}
end

def find_dojos_by(services)
services.each.with_object({}) do |name, hash|
hash[name] = Dojo.eager_load(:dojo_event_services).where(dojo_event_services: { name: name }).to_a
end
end

class Base
def initialize(dojos, from, to)
@externals = dojos[:externals]
@internals = dojos[:internals]
@list = build_list(from, to)
@from = from
@to = to
end

def run
with_notifying do
delete_upcoming_event
execute
execute_once
end
end

private

def with_notifying
yield
Notifier.notify_success(date_format(@from), date_format(@to))
rescue => e
Notifier.notify_failure(date_format(@from), date_format(@to), e)
end

def delete_upcoming_event
(@externals.keys + @internals.keys).each do |kind|
"Upcoming::Tasks::#{kind.to_s.camelize}".constantize.delete_upcoming_event
end
end

def execute
raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
end

def execute_once
@internals.each do |kind, list|
"Upcoming::Tasks::#{kind.to_s.camelize}".constantize.new(list, nil).run
end
end

def build_list(_from, _to)
raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
end

def date_format(_date)
raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
end
end

class Monthly < Base
private

def execute
@list.each do |date|
puts "Aggregate for #{date_format(date)}"

@externals.each do |kind, list|
"Upcoming::Tasks::#{kind.to_s.camelize}".constantize.new(list, date).run
end
end
end

def build_list(from, to)
loop.with_object([from]) do |_, list|
nm = list.last.next_month
raise StopIteration if nm > to
list << nm
end
end

def date_format(date)
date.strftime('%Y/%m')
end
end

class Notifier
class << self
def notify_success(from, to)
notify("#{from}~#{to}のイベント登録を行いました")
end

def notify_failure(from, to, exception)
notify("#{from}~#{to}のイベント登録でエラーが発生しました\n#{exception.message}\n#{exception.backtrace.join("\n")}")
end

private

def idobata_hook_url
return @idobata_hook_url if defined?(@idobata_hook_url)
@idobata_hook_url = ENV['IDOBATA_HOOK_URL']
end

def notifierable?
idobata_hook_url.present?
end

def notify(msg)
$stdout.puts msg
puts `curl --data-urlencode "source=#{msg}" -s #{idobata_hook_url} -o /dev/null -w "idobata: %{http_code}"` if notifierable?
end
end
end
end
end
9 changes: 9 additions & 0 deletions lib/upcoming/tasks.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Upcoming
module Tasks
end
end

require_relative 'tasks/connpass'
require_relative 'tasks/doorkeeper'
require_relative 'tasks/facebook'
require_relative 'tasks/static_yaml'
36 changes: 36 additions & 0 deletions lib/upcoming/tasks/connpass.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
module Upcoming
module Tasks
class Connpass
def self.delete_upcoming_event
UpcomingEvent.for(:connpass).delete_all
end

def initialize(dojos, date)
@client = EventService::Providers::Connpass.new
@dojos = dojos
@params = build_params(date)
end

def run
@dojos.each do |dojo|
dojo.dojo_event_services.for(:connpass).each do |dojo_event_service|
@client.fetch_events(@params.merge(series_id: dojo_event_service.group_id)).each do |e|
next unless e.dig('series', 'id').to_s == dojo_event_service.group_id

UpcomingEvent.create!(dojo_event_service: dojo_event_service,
event_id: e['event_id'],
event_url: e['event_url'],
event_at: Time.zone.parse(e['started_at']))
end
end
end
end

private

def build_params(date)
{ yyyymm: "#{date.year}#{date.month}" }
end
end
end
end
39 changes: 39 additions & 0 deletions lib/upcoming/tasks/doorkeeper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module Upcoming
module Tasks
class Doorkeeper
def self.delete_upcoming_event
UpcomingEvent.for(:doorkeeper).delete_all
end

def initialize(dojos, date)
@client = EventService::Providers::Doorkeeper.new
@dojos = dojos
@params = build_params(date)
end

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

UpcomingEvent.create!(dojo_event_service: dojo_event_service,
event_id: e['id'],
event_url: e['public_url'],
event_at: Time.zone.parse(e['starts_at']))
end
end
end
end

private

def build_params(date)
{
since_at: date.beginning_of_month,
until_at: date.end_of_month
}
end
end
end
end
39 changes: 39 additions & 0 deletions lib/upcoming/tasks/facebook.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module Upcoming
module Tasks
class Facebook
def self.delete_upcoming_event
UpcomingEvent.for(:facebook).delete_all
end

def initialize(dojos, date)
@client = EventService::Providers::Facebook.new
@dojos = dojos
@params = build_params(date)
end

def run
@dojos.each do |dojo|
dojo.dojo_event_services.for(:facebook).each do |dojo_event_service|
@client.fetch_events(@params.merge(group_id: dojo_event_service.group_id)).each do |e|
next unless e.dig('owner', 'id') == dojo_event_service.group_id

UpcomingEvent.create!(dojo_event_service_id: e['id'],
event_id: e['id'],
event_url: "https://www.facebook.com/events/#{e['id']}",
event_at: Time.zone.parse(e['start_time']))
end
end
end
end

private

def build_params(date)
{
since_at: date.beginning_of_month,
until_at: date.end_of_month
}
end
end
end
end
33 changes: 33 additions & 0 deletions lib/upcoming/tasks/static_yaml.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module Upcoming
module Tasks
class StaticYaml
def self.delete_upcoming_event
UpcomingEvent.for(:static_yaml).delete_all
end

def initialize(dojos, _date)
@client = EventService::Providers::StaticYaml.new
@dojos = dojos
end

def run
dojos_hash = @dojos.index_by(&:id)
@client.fetch_events.each do |e|
dojo = dojos_hash[e['dojo_id'].to_i]
next unless dojo

dojo.dojo_event_services.for(:static_yaml).each do |dojo_event_service|
evented_at = Time.zone.parse(e['evented_at'])
event_id = "#{SecureRandom.uuid}"

UpcomingEvent.create!(dojo_event_service: dojo_event_service,
event_id: event_id,
event_url: "https://dummy.url/#{event_id}",
event_at: evented_at)

end
end
end
end
end
end
24 changes: 24 additions & 0 deletions logfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
2018-06-26 17:30:30.851 JST [91625] LOG: listening on IPv6 address "::1", port 5432
2018-06-26 17:30:30.851 JST [91625] LOG: listening on IPv4 address "127.0.0.1", port 5432
2018-06-26 17:30:30.852 JST [91625] LOG: listening on Unix socket "/tmp/.s.PGSQL.5432"
2018-06-26 17:30:30.978 JST [91626] LOG: database system was shut down at 2018-06-13 16:41:22 JST
2018-06-26 17:30:30.998 JST [91625] LOG: database system is ready to accept connections
2018-06-26 17:30:53.572 JST [91837] ERROR: column upcoming_events.service_name does not exist at character 37
2018-06-26 17:30:53.572 JST [91837] STATEMENT: DELETE FROM "upcoming_events" WHERE "upcoming_events"."service_name" = $1
2018-06-26 17:31:34.879 JST [92027] ERROR: database "coderdojo_jp_development" already exists
2018-06-26 17:31:34.879 JST [92027] STATEMENT: CREATE DATABASE "coderdojo_jp_development" ENCODING = 'unicode'
2018-06-26 17:31:34.890 JST [92028] ERROR: database "coderdojo_jp_test" already exists
2018-06-26 17:31:34.890 JST [92028] STATEMENT: CREATE DATABASE "coderdojo_jp_test" ENCODING = 'unicode'
2018-06-26 17:32:08.025 JST [92199] ERROR: column upcoming_events.service_name does not exist at character 37
2018-06-26 17:32:08.025 JST [92199] STATEMENT: DELETE FROM "upcoming_events" WHERE "upcoming_events"."service_name" = $1
2018-06-28 14:54:47.903 JST [91625] LOG: received smart shutdown request
2018-06-28 14:54:47.906 JST [91625] LOG: worker process: logical replication launcher (PID 91632) exited with exit code 1
2018-06-28 14:54:47.906 JST [91627] LOG: shutting down
2018-06-28 14:54:47.925 JST [91625] LOG: database system is shut down
2018-07-23 21:50:52.263 JST [90475] LOG: listening on IPv6 address "::1", port 5432
2018-07-23 21:50:52.265 JST [90475] LOG: listening on IPv4 address "127.0.0.1", port 5432
2018-07-23 21:50:52.269 JST [90475] LOG: listening on Unix socket "/tmp/.s.PGSQL.5432"
2018-07-23 21:50:52.400 JST [90476] LOG: database system was shut down at 2018-07-23 16:48:21 JST
2018-07-23 21:50:52.419 JST [90475] LOG: database system is ready to accept connections
2018-07-23 21:51:02.976 JST [90575] ERROR: column upcoming_events.service_name does not exist at character 37
2018-07-23 21:51:02.976 JST [90575] STATEMENT: DELETE FROM "upcoming_events" WHERE "upcoming_events"."service_name" = $1