meetalendar 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rubocop.yml +96 -0
- data/.travis.yml +21 -0
- data/Gemfile +20 -0
- data/LICENSE +20 -0
- data/README.md +141 -0
- data/Rakefile +5 -0
- data/app/controllers/comfy/admin/meetalendar/meetups_controller.rb +154 -0
- data/app/models/comfy/admin/meetalendar/auth_credential.rb +22 -0
- data/app/models/comfy/admin/meetalendar/meetup_group.rb +3 -0
- data/app/models/comfy/admin/meetalendar/meetups_calendar_syncer.rb +178 -0
- data/app/models/comfy/admin/meetalendar/meetups_controller_logic.rb +77 -0
- data/app/models/google/auth/store/db_token_store.rb +37 -0
- data/app/views/comfy/admin/meetalendar/meetups/_authorize_calendar.slim +6 -0
- data/app/views/comfy/admin/meetalendar/meetups/_edit.slim +6 -0
- data/app/views/comfy/admin/meetalendar/meetups/_search_mask.slim +19 -0
- data/app/views/comfy/admin/meetalendar/meetups/_search_result.slim +57 -0
- data/app/views/comfy/admin/meetalendar/meetups/authorize_calendar.slim +6 -0
- data/app/views/comfy/admin/meetalendar/meetups/edit.slim +11 -0
- data/app/views/comfy/admin/meetalendar/meetups/index.slim +26 -0
- data/app/views/comfy/admin/meetalendar/meetups/search_mask.slim +5 -0
- data/app/views/comfy/admin/meetalendar/meetups/search_result.slim +5 -0
- data/app/views/comfy/admin/meetalendar/partials/_navigation.html.haml +9 -0
- data/app/views/layouts/comfy/meetalendar/application.html.erb +28 -0
- data/bin/bundle +3 -0
- data/bin/rails +4 -0
- data/bin/rake +4 -0
- data/bin/setup +36 -0
- data/bin/update +31 -0
- data/bin/yarn +11 -0
- data/comfy_meetalendar.gemspec +44 -0
- data/config.ru +6 -0
- data/config/application.rb +38 -0
- data/config/boot.rb +7 -0
- data/config/database.yml +11 -0
- data/config/environment.rb +7 -0
- data/config/environments/development.rb +64 -0
- data/config/environments/test.rb +51 -0
- data/config/initializers/meetalendar.rb +23 -0
- data/config/locales/en.yml +33 -0
- data/config/meetalendar_routes.rb +3 -0
- data/config/storage.yml +35 -0
- data/db/migrate/00_create_cms.rb +142 -0
- data/db/migrate/01_create_meetalendar_meetup_groups.rb +13 -0
- data/db/migrate/02_create_meetalendar_auth_credentials.rb +16 -0
- data/lib/generators/comfy/meetalendar/README +5 -0
- data/lib/generators/comfy/meetalendar/meetalendar_generator.rb +61 -0
- data/lib/meetalendar.rb +29 -0
- data/lib/meetalendar/configuration.rb +24 -0
- data/lib/meetalendar/engine.rb +32 -0
- data/lib/meetalendar/routes/meetalendar_admin.rb +30 -0
- data/lib/meetalendar/routing.rb +3 -0
- data/lib/meetalendar/version.rb +7 -0
- data/lib/tasks/meetalendar_tasks.rake +14 -0
- metadata +244 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'attr_encrypted'
|
2
|
+
|
3
|
+
class Comfy::Admin::Meetalendar::AuthCredential < ApplicationRecord
|
4
|
+
self.table_name = "meetalendar_auth_credentials"
|
5
|
+
|
6
|
+
# TODO(Schau): There might be a better place for this function
|
7
|
+
def self.expand_env(str)
|
8
|
+
str.gsub(/\$([a-zA-Z_][a-zA-Z0-9_]*)|\${\g<1>}|%\g<1>%/) { ENV[$1] }
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_encrypted :access_token, key: Rails.application.secrets.secret_key_base.to_s.bytes[0..31].pack("c" * 32)
|
12
|
+
attr_encrypted :refresh_token, key: Rails.application.secrets.secret_key_base.to_s.bytes[0..31].pack("c" * 32)
|
13
|
+
|
14
|
+
def scope
|
15
|
+
# NOTE(Schau): Scope expected to be a json parsable string that results in an array.
|
16
|
+
parsed_scope = JSON.parse(self.scope_json)
|
17
|
+
parsed_scope = parsed_scope.empty? ? [] : parsed_scope
|
18
|
+
end
|
19
|
+
def scope=(new_scope)
|
20
|
+
self.scope_json = new_scope.to_json.to_s
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_resource'
|
3
|
+
|
4
|
+
require "date"
|
5
|
+
require_relative "../../../google/auth/store/db_token_store"
|
6
|
+
require "google/apis/calendar_v3"
|
7
|
+
require "googleauth"
|
8
|
+
|
9
|
+
require_relative "../../../../controllers/comfy/admin/meetalendar/meetups_controller"
|
10
|
+
|
11
|
+
module Comfy::Admin::Meetalendar::MeetupsCalendarSyncer
|
12
|
+
GOOGLE_CALENDAR_AUTH_OOB_URI ||= "urn:ietf:wg:oauth:2.0:oob".freeze
|
13
|
+
GOOGLE_CALENDAR_AUTH_APPLICATION_NAME ||= "Google Calendar API Ruby MeetupSync".freeze
|
14
|
+
GOOGLE_CALENDAR_AUTH_SCOPE ||= Google::Apis::CalendarV3::AUTH_CALENDAR_EVENTS.freeze
|
15
|
+
|
16
|
+
def self.prepare_authorizer
|
17
|
+
client_id = ::MEETALENDAR_CREDENTIALS_GOOGLE_CALENDAR_CLIENT_ID
|
18
|
+
token_store = Google::Auth::Stores::DbTokenStore.new
|
19
|
+
authorizer = Google::Auth::UserAuthorizer.new client_id, GOOGLE_CALENDAR_AUTH_SCOPE, token_store
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.get_authorization_url
|
23
|
+
self.prepare_authorizer.get_authorization_url base_url: GOOGLE_CALENDAR_AUTH_OOB_URI
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.authorize_and_remember(key_code)
|
27
|
+
authorizer = self.prepare_authorizer
|
28
|
+
user_id = "default"
|
29
|
+
|
30
|
+
begin
|
31
|
+
authorizer.get_and_store_credentials_from_code(user_id: user_id, code: key_code, base_url: GOOGLE_CALENDAR_AUTH_OOB_URI)
|
32
|
+
rescue => exception
|
33
|
+
Rails.logger.error "Authorization of google calendar api failed with exception: #{exception.message}"
|
34
|
+
raise ::ActiveResource::UnauthorizedAccess, "Authorization at google calendar failed."
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.authorize
|
39
|
+
authorizer = self.prepare_authorizer
|
40
|
+
user_id = "default"
|
41
|
+
credentials = authorizer.get_credentials user_id
|
42
|
+
|
43
|
+
if credentials.nil?
|
44
|
+
Rails.logger.error "Authorization failed as no google calendar api credentials are present."
|
45
|
+
raise ::ActiveResource::UnauthorizedAccess, "Please go to: <host>/admin/meetups in the admin interface of the website and renew the authorization of the calendar api."
|
46
|
+
end
|
47
|
+
credentials
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.add_to_key(current_key_data, to_add_data)
|
51
|
+
return_key_data = current_key_data.nil? ? [] : current_key_data.class == [].class ? current_key_data : [].push(current_key_data)
|
52
|
+
return_key_data.push(to_add_data)
|
53
|
+
return_key_data
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.get_path_authorized(path, args = {})
|
57
|
+
return_hash = {}
|
58
|
+
client = HTTPClient.new
|
59
|
+
token_store = Google::Auth::Stores::DbTokenStore.new
|
60
|
+
loaded_token = token_store.load("meetup")
|
61
|
+
if loaded_token.nil?
|
62
|
+
Rails.logger.error "Authorization failed as no currently authorized meetup api token was present."
|
63
|
+
raise ::ActiveResource::UnauthorizedAccess, "To access this path you need to have authenticated the Meetup API successfully."
|
64
|
+
parsed_path = {}.to_s
|
65
|
+
else
|
66
|
+
# try
|
67
|
+
current_tokens = JSON.parse(loaded_token)
|
68
|
+
request_uri = "https://api.meetup.com" + path.to_s
|
69
|
+
request_query_args = args.merge({"access_token" => (current_tokens["access_token"])})
|
70
|
+
result = client.request("GET", request_uri, request_query_args)
|
71
|
+
|
72
|
+
if result.nil? || result.status == Rack::Utils::SYMBOL_TO_STATUS_CODE[:unauthorized]
|
73
|
+
meetup_credentials = ::MEETALENDAR_CREDENTIALS_MEETUP
|
74
|
+
request_uri = "https://secure.meetup.com/oauth2/access"
|
75
|
+
request_query_args = {"client_id": meetup_credentials["client_id"], "client_secret": meetup_credentials["client_secret"], "grant_type": "refresh_token", "refresh_token": "#{current_tokens["refresh_token"]}"}
|
76
|
+
post_return = client.post_content(request_uri, request_query_args)
|
77
|
+
|
78
|
+
if post_return.nil? || post_return.status == 401
|
79
|
+
Rails.logger.error "Authorization with current token failed and token could not be refreshed. Was authorization to meetup api revoked?"
|
80
|
+
raise ::ActiveResource::UnauthorizedAccess, "To access this path you need to have authenticated the Meetup API successfully."
|
81
|
+
else
|
82
|
+
response = JSON.parse(post_return.to_s)
|
83
|
+
token_store.store("meetup", {"auth_id": "meetup", "client_id": meetup_credentials["client_id"], "access_token": response["access_token"], "refresh_token": response["refresh_token"], "scope": "", "expiration_time_millis": response["expires_in"] * 1000}.to_json.to_s)
|
84
|
+
|
85
|
+
# retry with refreshed token
|
86
|
+
current_tokens = JSON.parse(loaded_token)
|
87
|
+
request_uri = "https://api.meetup.com" + path.to_s
|
88
|
+
request_query_args = args.merge({"access_token" => (current_tokens["access_token"])})
|
89
|
+
result = client.request("GET", request_uri, request_query_args)
|
90
|
+
|
91
|
+
if result.nil? || result.status == 401
|
92
|
+
# really no success
|
93
|
+
Rails.logger.error "Authorization with current token failed, token was refreshed but authorization still fails. Was authorization to meetup api revoked?"
|
94
|
+
raise ::ActiveResource::UnauthorizedAccess, "To access this path you need to have authenticated the Meetup API successfully."
|
95
|
+
else
|
96
|
+
parsed_path = JSON.parse(result&.body.nil? ? {}.to_s : result.body.to_s)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
else
|
101
|
+
parsed_path = JSON.parse(result&.body.nil? ? {}.to_s : result.body.to_s)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
parsed_path
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.gather_meetups_in_approved_cities(time_now)
|
109
|
+
@meetups = MeetupGroup.all
|
110
|
+
group_ids = @meetups.map{ |meetup| meetup.group_id }
|
111
|
+
group_ids_approved_cities = @meetups.map{|meetup| ["#{meetup.group_id}", meetup.approved_cities.downcase.split(%r{,\s*})]}.to_h
|
112
|
+
|
113
|
+
request_result = Comfy::Admin::Meetalendar::MeetupsCalendarSyncer.get_path_authorized("/find/upcoming_events", {"page": 200})
|
114
|
+
|
115
|
+
upcoming_events = request_result.nil? ? {} : request_result
|
116
|
+
upcoming_events = upcoming_events.nil? || upcoming_events.empty? ? [] : upcoming_events["events"]
|
117
|
+
upcoming_events_of_groups = upcoming_events.select{|event|
|
118
|
+
!event["group"].nil? &&
|
119
|
+
group_ids.include?(event["group"]["id"]) &&
|
120
|
+
!event["venue"].nil? &&
|
121
|
+
group_ids_approved_cities["#{event["group"]["id"]}"].include?(event['venue']['city'].to_s.downcase)}
|
122
|
+
|
123
|
+
grouped_upcoming_events = upcoming_events_of_groups.group_by{|event| event["group"]["id"]}
|
124
|
+
# NOTE(Schau): Very likely i will be able to refactor this to be more clear.
|
125
|
+
limited_upcoming_events = Hash[grouped_upcoming_events.map{|k, v| [k, v.select{|event| Time.at(Rational(event["time"].to_i, 1000)) > time_now}.sort_by{|event| event["time"].to_i}.take(2)]}].select{|k, v| v.any?}
|
126
|
+
listed_upcoming_events = limited_upcoming_events.map{|k, v| v.first}
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.sync_meetups_to_calendar(listed_upcoming_events)
|
130
|
+
calendar_service = Google::Apis::CalendarV3::CalendarService.new
|
131
|
+
calendar_service.client_options.application_name = GOOGLE_CALENDAR_AUTH_APPLICATION_NAME
|
132
|
+
calendar_service.authorization = authorize
|
133
|
+
|
134
|
+
listed_upcoming_events.each{ |event|
|
135
|
+
if event.key?('venue')
|
136
|
+
venue_name_adress = event['venue']['name'] != event['venue']['address_1'] ? "#{event['venue']['name']}, #{event['venue']['address_1']}" : "#{event['venue']['address_1']}"
|
137
|
+
location = "#{venue_name_adress}, #{event['venue']['city']}, #{event['venue']['localized_country_name']}"
|
138
|
+
else
|
139
|
+
if event.key?('link')
|
140
|
+
location = event['link'].to_s
|
141
|
+
else
|
142
|
+
location = ""
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
description = event['description'].to_s + (defined?(event['link']) ? "\nLink: " + event['link'].to_s : "")
|
147
|
+
start_date_time = DateTime.parse(Time.at(Rational(event['time'].to_i, 1000)).to_s).to_s
|
148
|
+
end_date_time = DateTime.parse(Time.at(Rational(event['time'].to_i + event['duration'].to_i, 1000)).to_s).to_s
|
149
|
+
|
150
|
+
new_event_hash = {
|
151
|
+
id: Digest::MD5.hexdigest(event['id'].to_s),
|
152
|
+
summary: event['name'].to_s,
|
153
|
+
location: location,
|
154
|
+
description: description,
|
155
|
+
start: {
|
156
|
+
date_time: start_date_time,
|
157
|
+
time_zone: Time.zone.name
|
158
|
+
},
|
159
|
+
end: {
|
160
|
+
date_time: end_date_time,
|
161
|
+
time_zone: Time.zone.name
|
162
|
+
},
|
163
|
+
}
|
164
|
+
|
165
|
+
new_event = Google::Apis::CalendarV3::Event.new(new_event_hash)
|
166
|
+
begin
|
167
|
+
calendar_service.update_event('primary', new_event.id, new_event)
|
168
|
+
rescue # TODO(Schau): If possible, figure out the exact exceptions to minimize "braodness of healing"
|
169
|
+
begin
|
170
|
+
calendar_service.insert_event('primary', new_event)
|
171
|
+
rescue => exception
|
172
|
+
Rails.logger.error "An exception occurred while updating or inserting events into the google calendar. Exception: #{exception.message}"
|
173
|
+
raise ::ActiveResource::ClientError, "Could not update or insert event into the google calendar."
|
174
|
+
end
|
175
|
+
end
|
176
|
+
}
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_resource'
|
3
|
+
|
4
|
+
require 'multi_json'
|
5
|
+
require_relative "../../../google/auth/store/db_token_store"
|
6
|
+
|
7
|
+
module Comfy::Admin::Meetalendar::MeetupsControllerLogic
|
8
|
+
class Comfy::Admin::Meetalendar::MeetupsControllerLogic::SearchResult
|
9
|
+
attr_reader :groups_id_name
|
10
|
+
attr_reader :found_upcoming_grouped_events
|
11
|
+
attr_reader :found_last_grouped_events
|
12
|
+
attr_reader :meetup_groups
|
13
|
+
|
14
|
+
def initialize(groups_id_name, found_upcoming_grouped_events, found_last_grouped_events, meetup_groups)
|
15
|
+
@groups_id_name = groups_id_name
|
16
|
+
@found_upcoming_grouped_events = found_upcoming_grouped_events
|
17
|
+
@found_last_grouped_events = found_last_grouped_events
|
18
|
+
@meetup_groups = meetup_groups
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.authorize_meetup(request, callback_path)
|
23
|
+
meetup_credentials = ::MEETALENDAR_CREDENTIALS_MEETUP
|
24
|
+
|
25
|
+
redirect_url = "https://secure.meetup.com/oauth2/authorize" +
|
26
|
+
"?client_id=#{meetup_credentials["client_id"]}" +
|
27
|
+
"&response_type=code" +
|
28
|
+
"&redirect_uri=#{request.protocol}#{request.host_with_port}#{callback_path.to_s}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.callback(code, request, callback_path)
|
32
|
+
meetup_credentials = ::MEETALENDAR_CREDENTIALS_MEETUP
|
33
|
+
|
34
|
+
request_uri = "https://secure.meetup.com/oauth2/access"
|
35
|
+
request_query_hash = {"client_id": meetup_credentials["client_id"], "client_secret": meetup_credentials["client_secret"], "grant_type": "authorization_code", "redirect_uri": "#{request.protocol}#{request.host_with_port}#{callback_path.to_s}", "code": "#{code}"}
|
36
|
+
|
37
|
+
client = HTTPClient.new
|
38
|
+
begin
|
39
|
+
response = JSON.parse(client.post_content(request_uri, request_query_hash))
|
40
|
+
rescue => ex
|
41
|
+
Rails.logger.error "Failed to authorize Meetup API. Exception in callback: #{ex.message}"
|
42
|
+
raise ::ActiveResource::ClientError, "Failed to authorize Meetup API."
|
43
|
+
end
|
44
|
+
|
45
|
+
if !response.nil?
|
46
|
+
token_store = Google::Auth::Stores::DbTokenStore.new
|
47
|
+
token_store.store("meetup", {"auth_id": "meetup", "client_id": meetup_credentials["client_id"], "access_token": response["access_token"], "refresh_token": response["refresh_token"], "scope": "", "expiration_time_millis": response["expires_in"] * 1000}.to_json.to_s)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.search_result(parameters, time_now)
|
52
|
+
group_params = JSON.parse(parameters.nil? ? {} : parameters)
|
53
|
+
|
54
|
+
request_result = Comfy::Admin::Meetalendar::MeetupsCalendarSyncer.get_path_authorized("/find/groups", group_params.merge({"fields" => "last_event"}))
|
55
|
+
groups = request_result.nil? ? {} : request_result
|
56
|
+
|
57
|
+
groups_id_name = groups.map{|g| {id: g["id"].to_i, name: g["name"].to_s, link: g["link"].to_s} }
|
58
|
+
group_ids = groups.map{|g| g["id"]}
|
59
|
+
request_result = Comfy::Admin::Meetalendar::MeetupsCalendarSyncer.get_path_authorized("/find/upcoming_events", {"page": 200})
|
60
|
+
upcoming_events = request_result.nil? ? [] : request_result["events"]
|
61
|
+
|
62
|
+
upcoming_events_of_groups = upcoming_events.select{|e| !e["group"].nil? && group_ids.include?(e["group"]["id"])}
|
63
|
+
|
64
|
+
grouped_upcoming_events = upcoming_events_of_groups.group_by{|e| e["group"]["id"]}
|
65
|
+
limited_upcoming_events = Hash[grouped_upcoming_events.map{|k, v| [k, v.select{|e| Time.at(Rational(e["time"], 1000)) > time_now}.sort_by{|e| e["time"]}.take(2)]}].select{|k, v| v.any?}
|
66
|
+
|
67
|
+
found_upcoming_grouped_events = limited_upcoming_events
|
68
|
+
|
69
|
+
last_events = Hash[groups.group_by{|g| g["id"]}.map{|k, v| [k, v.map{|g| g["last_event"]}]}].select{|k, v| v.any?}
|
70
|
+
found_last_grouped_events = last_events
|
71
|
+
|
72
|
+
meetup_groups = groups.map{|g| Comfy::Admin::Meetalendar::MeetupGroup.new({"group_id": g["id"], "name": g["name"], "approved_cities": "", "group_link": g["link"]})}
|
73
|
+
|
74
|
+
search_result = Comfy::Admin::Meetalendar::MeetupsControllerLogic::SearchResult.new(groups_id_name, found_upcoming_grouped_events, found_last_grouped_events, meetup_groups)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "googleauth/token_store"
|
2
|
+
|
3
|
+
module Google
|
4
|
+
module Auth
|
5
|
+
module Stores
|
6
|
+
class DbTokenStore < Google::Auth::TokenStore
|
7
|
+
# (see Google::Auth::Stores::TokenStore#load)
|
8
|
+
def load id
|
9
|
+
credentials = Comfy::Admin::Meetalendar::AuthCredential.find_by(auth_id: id)
|
10
|
+
!credentials.nil? ?
|
11
|
+
{
|
12
|
+
# NOTE(Schau): The encryption algorithm must decipher the encrypted tokens! It does so in this function call: credentials.access_token and credentials.refresh_token
|
13
|
+
auth_id: credentials.auth_id,
|
14
|
+
client_id: credentials.client_id,
|
15
|
+
access_token: credentials.access_token,
|
16
|
+
refresh_token: credentials.refresh_token,
|
17
|
+
scope: credentials.scope,
|
18
|
+
expiration_time_millis: credentials.expiration_time_millis
|
19
|
+
}.to_json.to_s
|
20
|
+
: nil
|
21
|
+
end
|
22
|
+
|
23
|
+
# (see Google::Auth::Stores::TokenStore#store)
|
24
|
+
def store id, token
|
25
|
+
token_hash = JSON.parse(token).symbolize_keys
|
26
|
+
Comfy::Admin::Meetalendar::AuthCredential.find_or_initialize_by(auth_id: id).update(token_hash)
|
27
|
+
end
|
28
|
+
|
29
|
+
# (see Google::Auth::Stores::TokenStore#delete)
|
30
|
+
def delete id
|
31
|
+
credentials = User.find_by(auth_id: id)
|
32
|
+
credentials.destroy
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
. Currently approved cities:
|
2
|
+
= text_field_tag "edited_approved_cities", @meetup.approved_cities.to_s, class: "custom-control"
|
3
|
+
|
4
|
+
= form.form_actions do
|
5
|
+
= form.submit "Save Edited", class: "btn btn-primary"
|
6
|
+
= link_to 'Cancel', edit_comfy_admin_meetalendar_meetup_path(@site), class: "btn btn-link"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
ruby:
|
2
|
+
group_params = '{
|
3
|
+
"country": "DE",
|
4
|
+
"state": "Sachsen",
|
5
|
+
"city": "Dresden",
|
6
|
+
"category_id": 34,
|
7
|
+
"page": 200
|
8
|
+
}'
|
9
|
+
|
10
|
+
= form.text_area :parameters, cols: 80, rows: 21, value: group_params
|
11
|
+
|
12
|
+
/ TODO(Schau): One could change the text area with the json approach to text fields so it equals the meetup api (and web console test kit) more closely.
|
13
|
+
/ = form.text_field :city
|
14
|
+
/ = form.text_field :category_id
|
15
|
+
/ ...
|
16
|
+
|
17
|
+
= form.form_actions do
|
18
|
+
= form.submit "Search for Meetup Groups", class: "btn btn-primary"
|
19
|
+
= link_to 'Cancel', comfy_admin_meetalendar_meetups_path(@site), class: "btn btn-link"
|
@@ -0,0 +1,57 @@
|
|
1
|
+
/ TODO(Schau): How to integrate pagination into this form view? (Is this even possible with data that doesn't live in the database?)
|
2
|
+
|
3
|
+
ul.list
|
4
|
+
- @groups_id_name&.each do |group|
|
5
|
+
li
|
6
|
+
.row
|
7
|
+
.col-md-12.d-flex.item
|
8
|
+
.item-content.meetup_group
|
9
|
+
|
10
|
+
.item-title
|
11
|
+
.inputs
|
12
|
+
.checkbox_label
|
13
|
+
.col-md-8 class="custom-control custom-checkbox float-left"
|
14
|
+
= check_box_tag "[selected_groups_ids][]", "#{group[:id]}", false, id: "group_#{group[:id]}", class: "custom-control-input"
|
15
|
+
= label_tag "group_#{group[:id]}", group[:name], class: "custom-control-label"
|
16
|
+
= hidden_field_tag "[groups]#{group[:id]}[name]", group[:name]
|
17
|
+
= hidden_field_tag "[groups]#{group[:id]}[group_link]", group[:link]
|
18
|
+
.col-md-4
|
19
|
+
= link_to "View on Meetup", group[:link], class: 'btn btn-secondary float-right ml-4'
|
20
|
+
.approved_cities
|
21
|
+
= text_field_tag "[groups]#{group[:id]}[approved_cities]", nil, class: "custom-control"
|
22
|
+
/ NOTE(Schau): Link_to's that look like buttons, have the city names that where found in the venue hash and on click add that city name to the input field followed by a coma
|
23
|
+
|
24
|
+
.item_meta
|
25
|
+
/ TODO(Schau): Make all additional info unfoldable
|
26
|
+
.events
|
27
|
+
|
28
|
+
.past_events
|
29
|
+
h5 Last Event
|
30
|
+
- if @found_last_grouped_events&.key?(group[:id])
|
31
|
+
- @found_last_grouped_events[group[:id]].each do |event|
|
32
|
+
.event
|
33
|
+
.name = event["name"].to_s
|
34
|
+
.time
|
35
|
+
.start = l(Time.at(Rational(event["time"].to_i, 1000), Rational(event["utc_offset"].to_i, 24*60*601000)), format: :long)
|
36
|
+
.yes_rsvp_count = event["yes_rsvp_count"].to_s + " Teilnemher"
|
37
|
+
|
38
|
+
span class="border-top my-3"
|
39
|
+
|
40
|
+
.upcoming_events
|
41
|
+
h5 Upcoming
|
42
|
+
- if @found_upcoming_grouped_events&.key?(group[:id])
|
43
|
+
- @found_upcoming_grouped_events[group[:id]].each do |event|
|
44
|
+
.event
|
45
|
+
.name = link_to event["name"], event["link"]
|
46
|
+
.time
|
47
|
+
.city = "In ".to_s + event.dig("venue", "city").to_s + ", Von ".to_s
|
48
|
+
.start = l(Time.at(event["time"].to_i.div(1000)), format: :long)
|
49
|
+
.to bis
|
50
|
+
.end = l(Time.at((event["time"].to_i + event["duration"].to_i).div(1000)), format: :short)
|
51
|
+
/ TODO(Schau): One could make the city name of the found events clickable so that the user easily can add this city's name to the list of approved cities. (One should research if Meetup has a way to represent each city on the planet with an id that the system gave this city's name. (Or Meetup realy relies on strings, then this doesn't quite make the effort worth.))
|
52
|
+
.description
|
53
|
+
= sanitize(event["description"])
|
54
|
+
|
55
|
+
= form.form_actions do
|
56
|
+
= form.submit "Add selected Meetup Groups", class: "btn btn-primary"
|
57
|
+
= link_to 'Cancel', comfy_admin_meetalendar_meetups_path(@site), class: "btn btn-link"
|
@@ -0,0 +1,6 @@
|
|
1
|
+
.page-header
|
2
|
+
h2= 'Authorize Calendar Access'
|
3
|
+
|
4
|
+
.goto_url = link_to "Please follow this link and grant this application access to your calendar.", @goto_url, target: "_blank"
|
5
|
+
= comfy_form_with url: :authorize_calendar_comfy_admin_meetalendar_meetups, method: :get do |authorize_calendar|
|
6
|
+
= render 'authorize_calendar', form: authorize_calendar
|
@@ -0,0 +1,11 @@
|
|
1
|
+
.page-header
|
2
|
+
h2 Edit Meetup
|
3
|
+
|
4
|
+
.row
|
5
|
+
.col-md-8.item
|
6
|
+
.item-content
|
7
|
+
.item-title
|
8
|
+
= link_to @meetup.name, @meetup.group_link, target: "_blank"
|
9
|
+
.item_meta
|
10
|
+
= comfy_form_with url: :comfy_admin_meetalendar_meetup, method: :patch do |edit|
|
11
|
+
= render 'edit', form: edit
|
@@ -0,0 +1,26 @@
|
|
1
|
+
.page-header
|
2
|
+
= link_to 'Add Groups', search_mask_comfy_admin_meetalendar_meetups_path(@site), class: 'btn btn-primary float-right ml-1'
|
3
|
+
= link_to 'Authorize Calendar', authorize_calendar_comfy_admin_meetalendar_meetups_path(@site), class: 'btn btn-secondary float-right ml-1'
|
4
|
+
= link_to 'Authorize Meetup', authorize_meetup_comfy_admin_meetalendar_meetups_path(@site), class: 'btn btn-secondary float-right'
|
5
|
+
h2= 'Subscribed Meetup Groups'
|
6
|
+
|
7
|
+
|
8
|
+
= paginate @meetups, theme: 'comfy'
|
9
|
+
|
10
|
+
ul.list
|
11
|
+
- @meetups&.each do |meetup_group|
|
12
|
+
li
|
13
|
+
.row
|
14
|
+
.col-md-8.item
|
15
|
+
.item-content
|
16
|
+
.item-title
|
17
|
+
= link_to meetup_group.name, meetup_group.group_link, target: "_blank"
|
18
|
+
.item_meta
|
19
|
+
= "Approved Cities: " + meetup_group.approved_cities.to_s
|
20
|
+
|
21
|
+
.col-md-4.d-flex.align-items-center.justify-content-md-end
|
22
|
+
.btn-group.btn-group-sm
|
23
|
+
= link_to 'Edit', edit_comfy_admin_meetalendar_meetup_path(@site, meetup_group), class: 'btn btn-outline-secondary'
|
24
|
+
= link_to 'Delete', comfy_admin_meetalendar_meetup_path(@site, meetup_group), method: :delete, data: {confirm: 'Are you sure?'}, class: 'btn btn-danger'
|
25
|
+
|
26
|
+
= paginate @meetups, theme: 'comfy'
|