2017-06-29 12:01:04 -04:00
|
|
|
# Similar to an ActiveRecord class, but uses PluginStore for storage instead. Adapted from discourse-data-explorer
|
|
|
|
# Using this means we can use a standard serializer for sending JSON to the client, and also have convenient save/update/delete methods
|
|
|
|
# Since this is now being used in two plugins, maybe it should be built into core somehow
|
|
|
|
class DiscourseChat::Rule
|
2017-07-04 14:37:56 -04:00
|
|
|
attr_accessor :id, :provider, :channel, :category_id, :tags, :filter, :error_key
|
2017-06-29 12:01:04 -04:00
|
|
|
|
|
|
|
def initialize(h={})
|
2017-07-03 12:38:13 -04:00
|
|
|
@provider = ''
|
|
|
|
@channel = ''
|
|
|
|
@category_id = nil
|
2017-07-05 17:38:53 -04:00
|
|
|
@tags = nil
|
2017-07-03 12:38:13 -04:00
|
|
|
@filter = 'watch'
|
2017-07-04 14:37:56 -04:00
|
|
|
@error_key = nil
|
2017-06-29 12:01:04 -04:00
|
|
|
h.each {|k,v| public_send("#{k}=",v)}
|
|
|
|
end
|
|
|
|
|
2017-07-03 12:38:13 -04:00
|
|
|
def tags=(array)
|
|
|
|
if array.nil? or array.empty?
|
|
|
|
@tags = nil
|
|
|
|
else
|
|
|
|
@tags = array
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def category_id=(val)
|
2017-07-03 19:14:01 -04:00
|
|
|
if val.nil? or val.blank?
|
2017-07-03 12:38:13 -04:00
|
|
|
@category_id = nil
|
|
|
|
else
|
|
|
|
@category_id = val.to_i
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-06-29 12:01:04 -04:00
|
|
|
# saving/loading functions
|
|
|
|
def self.alloc_id
|
|
|
|
DistributedMutex.synchronize('discourse-chat_rule-id') do
|
|
|
|
max_id = DiscourseChat.pstore_get("rule:_id")
|
|
|
|
max_id = 1 unless max_id
|
|
|
|
DiscourseChat.pstore_set("rule:_id", max_id + 1)
|
|
|
|
max_id
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.from_hash(h)
|
|
|
|
rule = DiscourseChat::Rule.new
|
2017-07-04 14:37:56 -04:00
|
|
|
[:provider, :channel, :category_id, :tags, :filter, :error_key].each do |sym|
|
2017-06-29 12:01:04 -04:00
|
|
|
rule.send("#{sym}=", h[sym]) if h[sym]
|
|
|
|
end
|
|
|
|
if h[:id]
|
|
|
|
rule.id = h[:id].to_i
|
|
|
|
end
|
|
|
|
rule
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_hash
|
|
|
|
{
|
|
|
|
id: @id,
|
|
|
|
provider: @provider,
|
|
|
|
channel: @channel,
|
|
|
|
category_id: @category_id,
|
|
|
|
tags: @tags,
|
|
|
|
filter: @filter,
|
2017-07-04 14:37:56 -04:00
|
|
|
error_key: @error_key,
|
2017-06-29 12:01:04 -04:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.find(id, opts={})
|
|
|
|
hash = DiscourseChat.pstore_get("rule:#{id}")
|
|
|
|
unless hash
|
|
|
|
return DiscourseChat::Rule.new if opts[:ignore_deleted]
|
|
|
|
raise Discourse::NotFound
|
|
|
|
end
|
|
|
|
from_hash hash
|
|
|
|
end
|
|
|
|
|
2017-07-04 14:37:56 -04:00
|
|
|
def update(h, validate=true)
|
|
|
|
[:provider, :channel, :category_id, :tags, :filter, :error_key].each do |sym|
|
|
|
|
public_send("#{sym}=", h[sym]) if h.key?(sym)
|
2017-06-29 15:19:40 -04:00
|
|
|
end
|
|
|
|
|
2017-07-04 14:37:56 -04:00
|
|
|
save(validate)
|
2017-06-29 15:19:40 -04:00
|
|
|
end
|
|
|
|
|
2017-07-04 14:37:56 -04:00
|
|
|
def save(validate=true)
|
|
|
|
if validate
|
|
|
|
return false if not valid?
|
|
|
|
end
|
2017-07-03 12:38:13 -04:00
|
|
|
|
2017-06-29 12:01:04 -04:00
|
|
|
unless @id && @id > 0
|
|
|
|
@id = self.class.alloc_id
|
|
|
|
end
|
|
|
|
DiscourseChat.pstore_set "rule:#{id}", to_hash
|
|
|
|
return self
|
|
|
|
end
|
|
|
|
|
2017-07-04 14:37:56 -04:00
|
|
|
def save!(validate=true)
|
|
|
|
if not save(validate)
|
2017-07-03 12:38:13 -04:00
|
|
|
raise 'Rule not valid'
|
|
|
|
end
|
|
|
|
return self
|
|
|
|
end
|
|
|
|
|
|
|
|
def valid?
|
|
|
|
|
|
|
|
# Validate provider
|
|
|
|
return false if not ::DiscourseChat::Provider.providers.map {|x| x::PROVIDER_NAME}.include? @provider
|
|
|
|
|
|
|
|
# Validate channel
|
|
|
|
return false if @channel.blank?
|
2017-07-03 19:14:01 -04:00
|
|
|
|
|
|
|
provider = ::DiscourseChat::Provider.get_by_name(@provider)
|
|
|
|
if defined? provider::PROVIDER_CHANNEL_REGEX
|
|
|
|
channel_regex = Regexp.new provider::PROVIDER_CHANNEL_REGEX
|
|
|
|
return false if not channel_regex.match?(@channel)
|
|
|
|
end
|
2017-07-03 12:38:13 -04:00
|
|
|
|
|
|
|
# Validate category
|
|
|
|
return false if not (@category_id.nil? or Category.where(id: @category_id).exists?)
|
|
|
|
|
|
|
|
# Validate tags
|
|
|
|
if not @tags.nil?
|
|
|
|
@tags.each do |tag|
|
|
|
|
return false if not Tag.where(name: tag).exists?
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Validate filter
|
|
|
|
return false if not ['watch','follow','mute'].include? @filter
|
|
|
|
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2017-06-29 12:01:04 -04:00
|
|
|
def destroy
|
|
|
|
DiscourseChat.pstore_delete "rule:#{id}"
|
|
|
|
end
|
|
|
|
|
|
|
|
def read_attribute_for_serialization(attr)
|
|
|
|
self.send(attr)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.all_for_provider(provider)
|
|
|
|
self.where("value::json->>'provider'=?", provider)
|
|
|
|
end
|
|
|
|
|
2017-07-05 17:38:53 -04:00
|
|
|
def self.all_for_channel(provider, channel)
|
|
|
|
self.where("value::json->>'provider'=? AND value::json->>'channel'=?", provider, channel)
|
|
|
|
end
|
|
|
|
|
2017-06-29 12:01:04 -04:00
|
|
|
def self.all_for_category(category_id)
|
|
|
|
if category_id.nil?
|
|
|
|
self.where("json_typeof(value::json->'category_id')='null'")
|
|
|
|
else
|
|
|
|
self.where("value::json->>'category_id'=?", category_id.to_s)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Use JSON selectors like this:
|
2017-06-29 12:50:54 -04:00
|
|
|
# Rule.where("value::json->>'provider'=?", "slack")
|
2017-06-29 12:01:04 -04:00
|
|
|
def self.where(*args)
|
|
|
|
rows = self._all_raw.where(*args)
|
|
|
|
self._from_psr_rows(rows)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.all
|
|
|
|
self._from_psr_rows(self._all_raw)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self._all_raw
|
|
|
|
PluginStoreRow.where(plugin_name: DiscourseChat.plugin_name)
|
|
|
|
.where("key LIKE 'rule:%'")
|
|
|
|
.where("key != 'rule:_id'")
|
|
|
|
end
|
|
|
|
|
|
|
|
def self._from_psr_rows(raw)
|
2017-07-05 17:38:53 -04:00
|
|
|
rules = raw.map do |psr|
|
2017-06-29 12:01:04 -04:00
|
|
|
from_hash PluginStore.cast_value(psr.type_name, psr.value)
|
|
|
|
end
|
2017-07-05 17:38:53 -04:00
|
|
|
|
|
|
|
filter_order = ["mute", "watch", "follow"]
|
|
|
|
rules = rules.sort_by{ |r| [r.channel, r.category_id.nil? ? 0 : r.category_id, filter_order.index(r.filter)] }
|
|
|
|
return rules
|
2017-06-29 12:01:04 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.destroy_all
|
|
|
|
self._all_raw().destroy_all
|
|
|
|
end
|
|
|
|
end
|