Skip to content

Commit

Permalink
Add publication functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
angusmcleod committed Sep 4, 2024
1 parent cff577e commit bcfcbef
Show file tree
Hide file tree
Showing 16 changed files with 588 additions and 34 deletions.
6 changes: 6 additions & 0 deletions app/models/discourse_events/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ def self.client_names
belongs_to :category
belongs_to :source, foreign_key: "source_id", class_name: "DiscourseEvents::Source"

delegate :sync_type, to: :source

validates :client,
inclusion: {
in: Connection.client_names,
Expand All @@ -34,6 +36,10 @@ def self.client_names
validates :category, presence: true
validates :source, presence: true

def publish?
sync_type == "import_publish"
end

def self.available_clients
CLIENTS.select { |client, plugin| plugins.include?(plugin) }.keys.map(&:to_s)
end
Expand Down
10 changes: 10 additions & 0 deletions app/models/discourse_events/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ class Event < ActiveRecord::Base
in: %w[draft published cancelled],
message: "%{value} is not a valid event status",
}

before_create { self.uid = generate_uid if local? }

def generate_uid
SecureRandom.hex(16)
end

def local?
source_id.blank?
end
end
end

Expand Down
2 changes: 2 additions & 0 deletions app/models/discourse_events/source.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ class Source < ActiveRecord::Base
validates :provider, presence: true
validate :valid_source_options?

enum sync_type: { import: 0, import_publish: 1 }

def ready?
provider.authenticated?
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true
class AddSyncTypeToDiscourseEventsSource < ActiveRecord::Migration[7.1]
def change
add_column :discourse_events_sources, :sync_type, :integer
end
end
2 changes: 1 addition & 1 deletion extensions/guardian.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module EventsGuardianExtension
def can_edit_post?(post)
return false if post.event_connection.present?
return false if post.event_connections.present?
super
end
end
11 changes: 11 additions & 0 deletions extensions/topic.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true
module DiscourseEventsTopicExtension
def reload(options = nil)
@event = nil
super(options)
end

def event
@event ||= DiscourseEvents::Event.find_by(id: self.custom_fields['event_id'])
end
end
30 changes: 13 additions & 17 deletions lib/discourse_events/event_creator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,19 @@ def create
(
event_params.is_a?(String) ? ::JSON.parse(event_params) : event_params
).with_indifferent_access
event_start = event["start"]
event_end = event["end"]
event_all_day = event["all_day"]
timezone = event["timezone"]
rsvp = event["rsvp"]
going_max = event["going_max"]
going = event["going"]
event_version = 1

topic.custom_fields["event_start"] = event_start.to_datetime.to_i if event_start
topic.custom_fields["event_end"] = event_end.to_datetime.to_i if event_end
topic.custom_fields["event_all_day"] = event_all_day === "true" if event_all_day
topic.custom_fields["event_timezone"] = timezone if timezone
topic.custom_fields["event_rsvp"] = rsvp if rsvp
topic.custom_fields["event_going_max"] = going_max if going_max
topic.custom_fields["event_going"] = User.where(username: going).pluck(:id) if going
topic.custom_fields["event_version"] = event_version if event_version
event_start = event["start"] ? event["start"].to_datetime : nil
event_end = event["end"] ? event["end"].to_datetime : nil

topic.custom_fields["event_start"] = event_start.to_i if event_start
topic.custom_fields["event_end"] = event_end.to_i if event_end
topic.custom_fields["event_all_day"] = event["all_day"] === "true" if event["all_day"]
topic.custom_fields["event_timezone"] = event["timezone"] if event["timezone"]
topic.custom_fields["event_rsvp"] = event["rsvp"] if event["rsvp"]
topic.custom_fields["event_going_max"] = event["going_max"] if event["going_max"]
topic.custom_fields["event_going"] = User.where(username: event["going"]).pluck(
:id,
) if event["going"]
topic.custom_fields["event_version"] = 1

topic.save_custom_fields(true)
end
Expand Down
130 changes: 130 additions & 0 deletions lib/discourse_events/publish_manager.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# frozen_string_literal: true

module DiscourseEvents
class PublishManager
attr_reader :post
attr_accessor :publisher, :publication_type, :connections, :event_data, :published_events

def initialize(post, publication_type)
@post = post
@publication_type = publication_type
@connections = []
@published_events = {}
end

def ready?
publisher.present? && connections.present?
end

def perform
@publisher = get_publisher

setup_connections

return false unless ready?
return false unless publish_events

send("#{publication_type}_event")
end

def self.perform(post, publication_type)
new(post, publication_type).perform
end

protected

def create_event
event = nil

ActiveRecord::Base.transaction do
event = Event.create!(event_data.create_params)

connections.each do |connection|
if published_events[connection.id].present?
params = get_event_connection_params(event, connection)
EventConnection.create!(params)
end
end

publisher.after_publish(post, event)
end

event.present? ? event : false
end

def update_event
ActiveRecord::Base.transaction { post.topic.event.update!(event_data.update_params) }
end

def destroy_event
ActiveRecord::Base.transaction { post.topic.event.destroy! }
end

def setup_connections
if publication_type == "create"
## We inherent the category connections on create
post.topic&.category&.discourse_events_connections&.each do |connection|
next unless connection.publish?
@connections << connection
end
end

if %w[update destroy].include?(publication_type)
## We only update or destroy the established connections.
post.event_connections.each do |event_connection|
connection = event_connection.connection
next unless connection.publish?
@connections << connection
end
end
end

def publish_events
@event_data = publisher.get_event_data(post)
return false unless event_data&.valid?
publish_event_to_connection_sources
@published_events.present?
end

def publish_event_to_connection_sources
connections.each do |connection|
publisher.setup_provider(connection.source.provider)
event = publisher.send("#{publication_type}_event", event_data)
@published_events[connection.id] ||= []
@published_events[connection.id] << event if event.present?
end
end

def get_publisher
client = detect_client
return false unless Connection.client_names.include?(client)

publisher = "DiscourseEvents::Publisher::#{client.camelize}".constantize.new
return false unless publisher.ready?

publisher
end

def detect_client
if post.topic.has_event?
"events"
elsif post.respond_to?(:event) && post.event.present?
"discourse_events"
else
nil
end
end

def get_event_connection_params(event, connection)
params = {
event_id: event.id,
connection_id: connection.id,
topic_id: post.topic.id,
post_id: post.id,
client: connection.client,
}
params[:series_id] = event.series_id if event.series_id
params
end
end
end
53 changes: 53 additions & 0 deletions lib/discourse_events/publisher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# frozen_string_literal: true

module DiscourseEvents
class Publisher
attr_reader :logger
attr_accessor :provider

def initialize
@logger = Logger.new(:publisher)
OmniEvent.config.logger = @logger
end

def setup_provider(_provider)
OmniEvent::Builder.new { provider _provider.provider_type, _provider.options }

@provider = _provider
end

def create_event(event_data)
OmniEvent.create_event(provider.provider_type, event: event_data.create_event_hash)
end

def update_event(event_data)
OmniEvent.update_event(provider.provider_type, event: event_data.update_event_hash)
end

def destroy_event(event_data)
OmniEvent.destroy_event(provider.provider_type, event: event_data.destroy_event_hash)
end

def get_event_data(post)
raise NotImplementedError
end

def after_publish(post, event)
raise NotImplementedError
end

protected

def log(type, message)
logger.send(type.to_s, message)
end

def create_event_hash(event_data)
OmniEvent::EventHash.new(
provider: provider.provider_type,
data: event_data.data,
metadata: event_data.metadata,
)
end
end
end
22 changes: 22 additions & 0 deletions lib/discourse_events/publisher/discourse_events.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

module DiscourseEvents
class Publisher::DiscourseEvents < Publisher
def ready?
defined?(DiscoursePostEvent) == "constant" && DiscoursePostEvent.class == Module &&
::SiteSetting.calendar_enabled && ::SiteSetting.discourse_post_event_enabled
end

def get_event_data(post)
return nil unless post&.event&.starts_at.present?
event = post.event

Publisher::EventData.new(
start_time: event.starts_at,
end_time: event.ends_at,
name: event.name,
url: event.url,
)
end
end
end
Loading

0 comments on commit bcfcbef

Please sign in to comment.