diff --git a/app/controllers/discourse_events/connection_controller.rb b/app/controllers/discourse_events/connection_controller.rb
index cb7a3bd1..3865c09a 100644
--- a/app/controllers/discourse_events/connection_controller.rb
+++ b/app/controllers/discourse_events/connection_controller.rb
@@ -60,7 +60,7 @@ def connection_params
:category_id,
:source_id,
:client,
- filters: %i[id query_column query_value],
+ filters: %i[id query_column query_operator query_value],
)
.to_h
@@ -95,7 +95,8 @@ def create_or_update
if connection_params[:filters].present?
valid_filters =
connection_params[:filters].select do |filter|
- has_keys = %i[id query_column query_value].all? { |key| filter.key?(key) }
+ has_keys =
+ %i[id query_column query_operator query_value].all? { |key| filter.key?(key) }
has_values = filter.values.all?(&:present?)
has_keys && has_values
end
@@ -103,10 +104,15 @@ def create_or_update
saved_ids = []
valid_filters.each do |f|
- params = f.slice(:query_column, :query_value)
+ params = f.slice(:query_column, :query_operator, :query_value)
if f[:id] === "new"
- filter = @connection.filters.create(params)
+ filter =
+ DiscourseEvents::Filter.create(
+ model_id: @connection.id,
+ model_type: "DiscourseEvents::Connection",
+ **params,
+ )
else
filter = @connection.filters.update(f[:id].to_i, params)
end
diff --git a/app/models/discourse_events/connection.rb b/app/models/discourse_events/connection.rb
index bf518637..c70d05fa 100644
--- a/app/models/discourse_events/connection.rb
+++ b/app/models/discourse_events/connection.rb
@@ -16,8 +16,8 @@ def self.client_names
dependent: :destroy
has_many :events, through: :event_connections, source: :event
has_many :filters,
- foreign_key: "connection_id",
- class_name: "DiscourseEvents::ConnectionFilter",
+ foreign_key: "model_id",
+ class_name: "DiscourseEvents::Filter",
dependent: :destroy
belongs_to :user
diff --git a/app/models/discourse_events/connection_filter.rb b/app/models/discourse_events/filter.rb
similarity index 65%
rename from app/models/discourse_events/connection_filter.rb
rename to app/models/discourse_events/filter.rb
index 0d68ad4c..7dc82784 100644
--- a/app/models/discourse_events/connection_filter.rb
+++ b/app/models/discourse_events/filter.rb
@@ -1,23 +1,27 @@
# frozen_string_literal: true
module DiscourseEvents
- class ConnectionFilter < ActiveRecord::Base
- self.table_name = "discourse_events_connection_filters"
+ class Filter < ActiveRecord::Base
+ self.table_name = "discourse_events_filters"
- belongs_to :connection, foreign_key: "connection_id", class_name: "DiscourseEvents::Connection"
+ MODEL_TYPES = %w[DiscourseEvents::Connection]
+
+ belongs_to :model, polymorphic: true
enum :query_column, %i[name], prefix: true
+ enum :query_operator, %i[like], prefix: true
- OPERATORS = { name: "ILIKE" }
+ OPERATORS = { like: "ILIKE" }
validate :query_value_format
+ validates :model_type, inclusion: { in: MODEL_TYPES }
def sql_value
- "%#{self.query_value}%" if sql_operator === "ILIKE"
+ "%#{self.query_value}%" if query_operator_like?
end
def sql_operator
- OPERATORS[self.query_column.to_sym]
+ OPERATORS[self.query_operator.to_sym]
end
def sql_column
@@ -34,7 +38,7 @@ def query_value_format
# == Schema Information
#
-# Table name: discourse_events_connection_filters
+# Table name: discourse_events_filters
#
# id :bigint not null, primary key
# connection_id :bigint not null
diff --git a/app/serializers/discourse_events/connection_filter_serializer.rb b/app/serializers/discourse_events/connection_filter_serializer.rb
deleted file mode 100644
index ea2de62d..00000000
--- a/app/serializers/discourse_events/connection_filter_serializer.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# frozen_string_literal: true
-
-module DiscourseEvents
- class ConnectionFilterSerializer < ApplicationSerializer
- attributes :id, :query_column, :query_value
- end
-end
diff --git a/app/serializers/discourse_events/connection_serializer.rb b/app/serializers/discourse_events/connection_serializer.rb
index 39c6c0ab..cef749e3 100644
--- a/app/serializers/discourse_events/connection_serializer.rb
+++ b/app/serializers/discourse_events/connection_serializer.rb
@@ -4,7 +4,7 @@ module DiscourseEvents
class ConnectionSerializer < ApplicationSerializer
attributes :id, :user, :category_id, :source_id, :client
- has_many :filters, serializer: ConnectionFilterSerializer, embed: :objects
+ has_many :filters, serializer: FilterSerializer, embed: :objects
def user
ConnectionUserSerializer.new(object.user, root: false).as_json
diff --git a/app/serializers/discourse_events/filter_serializer.rb b/app/serializers/discourse_events/filter_serializer.rb
new file mode 100644
index 00000000..1d9de05c
--- /dev/null
+++ b/app/serializers/discourse_events/filter_serializer.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module DiscourseEvents
+ class FilterSerializer < ApplicationSerializer
+ attributes :id, :query_column, :query_operator, :query_value
+ end
+end
diff --git a/assets/javascripts/discourse/components/events-connection-row.js b/assets/javascripts/discourse/components/events-connection-row.js
index b7baf7bf..e8358474 100644
--- a/assets/javascripts/discourse/components/events-connection-row.js
+++ b/assets/javascripts/discourse/components/events-connection-row.js
@@ -3,7 +3,7 @@ import { notEmpty, readOnly } from "@ember/object/computed";
import { service } from "@ember/service";
import discourseComputed from "discourse-common/utils/decorators";
import Connection from "../models/connection";
-import EventsConnectionFilters from "./modal/events-connection-filters";
+import EventsFilters from "./modal/events-filters";
function filtersMatch(filters1, filters2) {
if ((filters1 && !filters2) || (!filters1 && filters2)) {
@@ -21,7 +21,9 @@ function filtersMatch(filters1, filters2) {
return filters1.every((f1) =>
filters2.some((f2) => {
return (
- f2.query_column === f1.query_column && f2.query_value === f1.query_value
+ f2.query_column === f1.query_column &&
+ f2.query_operator === f2.query_operator &&
+ f2.query_value === f1.query_value
);
})
);
@@ -57,6 +59,7 @@ export default Component.extend({
"connection.to_time",
"connection.filters.[]",
"connection.filters.@each.query_column",
+ "connection.filters.@each.query_operator",
"connection.filters.@each.query_value"
)
connectionChanged(
@@ -130,10 +133,8 @@ export default Component.extend({
},
openFilters() {
- this.modal.show(EventsConnectionFilters, {
- model: {
- connection: this.get("connection"),
- },
+ this.modal.show(EventsFilters, {
+ model: this.get("connection"),
});
},
diff --git a/assets/javascripts/discourse/components/events-provider-row.hbs b/assets/javascripts/discourse/components/events-provider-row.hbs
index 34b17549..d8bd0933 100644
--- a/assets/javascripts/discourse/components/events-provider-row.hbs
+++ b/assets/javascripts/discourse/components/events-provider-row.hbs
@@ -104,7 +104,6 @@
@action={{action "saveProvider"}}
@icon="save"
@class={{this.saveClass}}
- @label="admin.events.connection.filters.add.label"
@title="admin.events.provider.save.title"
@disabled={{this.saveDisabled}}
/>
diff --git a/assets/javascripts/discourse/components/modal/events-connection-filters.hbs b/assets/javascripts/discourse/components/modal/events-connection-filters.hbs
deleted file mode 100644
index 67609010..00000000
--- a/assets/javascripts/discourse/components/modal/events-connection-filters.hbs
+++ /dev/null
@@ -1,49 +0,0 @@
-
- <:body>
-
-
- <:footer>
-
-
-
\ No newline at end of file
diff --git a/assets/javascripts/discourse/components/modal/events-connection-filters.js b/assets/javascripts/discourse/components/modal/events-connection-filters.js
deleted file mode 100644
index 5b783d78..00000000
--- a/assets/javascripts/discourse/components/modal/events-connection-filters.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { A } from "@ember/array";
-import Component from "@ember/component";
-import discourseComputed from "discourse-common/utils/decorators";
-import ConnectionFilter from "../../models/connection-filter";
-
-const QUERY_COLUMNS = [
- {
- name: "Event Name",
- id: "name",
- },
-];
-
-export default Component.extend({
- @discourseComputed
- queryColumns() {
- return QUERY_COLUMNS;
- },
-
- didInsertElement() {
- this._super(...arguments);
-
- if (!this.model.connection.filters) {
- this.model.connection.set("filters", A());
- }
- },
-
- actions: {
- addFilter() {
- const filter = ConnectionFilter.create({ id: "new" });
- this.model.connection.get("filters").pushObject(filter);
- },
-
- removeFilter(filter) {
- this.model.connection.get("filters").removeObject(filter);
- },
- },
-});
diff --git a/assets/javascripts/discourse/components/modal/events-filters.hbs b/assets/javascripts/discourse/components/modal/events-filters.hbs
new file mode 100644
index 00000000..f78c8d59
--- /dev/null
+++ b/assets/javascripts/discourse/components/modal/events-filters.hbs
@@ -0,0 +1,64 @@
+
+ <:body>
+ {{#if hasFilters}}
+
+ {{/if}}
+
+
+ <:footer>
+
+
+
\ No newline at end of file
diff --git a/assets/javascripts/discourse/components/modal/events-filters.js b/assets/javascripts/discourse/components/modal/events-filters.js
new file mode 100644
index 00000000..050e6c37
--- /dev/null
+++ b/assets/javascripts/discourse/components/modal/events-filters.js
@@ -0,0 +1,52 @@
+import { A } from "@ember/array";
+import Component from "@ember/component";
+import { notEmpty } from "@ember/object/computed";
+import discourseComputed from "discourse-common/utils/decorators";
+import Filter from "../../models/filter";
+
+const QUERY_COLUMNS = [
+ {
+ name: "Event Name",
+ id: "name",
+ },
+];
+
+const QUERY_OPERATORS = [
+ {
+ name: "Like",
+ id: "like",
+ },
+];
+
+export default Component.extend({
+ hasFilters: notEmpty("model.filters"),
+
+ @discourseComputed
+ queryColumns() {
+ return QUERY_COLUMNS;
+ },
+
+ @discourseComputed
+ queryOperators() {
+ return QUERY_OPERATORS;
+ },
+
+ didInsertElement() {
+ this._super(...arguments);
+
+ if (!this.model.filters) {
+ this.model.set("filters", A());
+ }
+ },
+
+ actions: {
+ addFilter() {
+ const filter = Filter.create({ id: "new" });
+ this.model.get("filters").pushObject(filter);
+ },
+
+ removeFilter(filter) {
+ this.model.get("filters").removeObject(filter);
+ },
+ },
+});
diff --git a/assets/javascripts/discourse/models/connection-filter.js b/assets/javascripts/discourse/models/connection-filter.js
deleted file mode 100644
index 46a02e87..00000000
--- a/assets/javascripts/discourse/models/connection-filter.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import EmberObject from "@ember/object";
-
-const ConnectionFilter = EmberObject.extend();
-
-export default ConnectionFilter;
diff --git a/assets/javascripts/discourse/models/filter.js b/assets/javascripts/discourse/models/filter.js
new file mode 100644
index 00000000..cd65fb17
--- /dev/null
+++ b/assets/javascripts/discourse/models/filter.js
@@ -0,0 +1,5 @@
+import EmberObject from "@ember/object";
+
+const Filter = EmberObject.extend();
+
+export default Filter;
diff --git a/assets/javascripts/discourse/routes/admin-plugins-events-connection.js b/assets/javascripts/discourse/routes/admin-plugins-events-connection.js
index 2f753dfd..003dd4e7 100644
--- a/assets/javascripts/discourse/routes/admin-plugins-events-connection.js
+++ b/assets/javascripts/discourse/routes/admin-plugins-events-connection.js
@@ -2,7 +2,7 @@ import { A } from "@ember/array";
import DiscourseRoute from "discourse/routes/discourse";
import { contentsMap } from "../lib/events";
import Connection from "../models/connection";
-import ConnectionFilter from "../models/connection-filter";
+import Filter from "../models/filter";
import Source from "../models/source";
export default DiscourseRoute.extend({
@@ -17,7 +17,7 @@ export default DiscourseRoute.extend({
if (c.filters) {
c.filters = A(
c.filters.map((f) => {
- return ConnectionFilter.create(f);
+ return Filter.create(f);
})
);
}
diff --git a/assets/javascripts/discourse/templates/admin-plugins-events-connection.hbs b/assets/javascripts/discourse/templates/admin-plugins-events-connection.hbs
index 36c03766..8f9abd26 100644
--- a/assets/javascripts/discourse/templates/admin-plugins-events-connection.hbs
+++ b/assets/javascripts/discourse/templates/admin-plugins-events-connection.hbs
@@ -17,7 +17,7 @@
{{I18n "admin.events.connection.category"}} |
{{I18n "admin.events.connection.source.label"}} |
{{I18n "admin.events.connection.client.label"}} |
- {{I18n "admin.events.connection.filters.label"}} |
+ {{I18n "admin.events.filters.label"}} |
{{I18n "admin.events.actions"}} |
diff --git a/assets/stylesheets/common/admin.scss b/assets/stylesheets/common/admin.scss
index 1e1a5326..ab628b4b 100644
--- a/assets/stylesheets/common/admin.scss
+++ b/assets/stylesheets/common/admin.scss
@@ -190,7 +190,7 @@ $pavilion_primary: #3c1c8c;
}
.provider-type {
- width: 150px;
+ width: 130px;
}
.status-column {
@@ -366,25 +366,21 @@ $pavilion_primary: #3c1c8c;
}
}
-.connection-filters {
- min-width: 500px;
-
- ul {
- margin: 0;
- list-style: none;
+.events-filters-modal {
+ table {
+ width: 100%;
+ margin-bottom: 1em;
- li {
- display: flex;
- margin-bottom: 1em;
- gap: 1em;
+ td {
+ padding: 1em 0.5em;
+ }
+ }
- input {
- margin: 0;
- }
+ input {
+ margin: 0;
+ }
- .select-kit {
- min-width: 150px;
- }
- }
+ .select-kit {
+ min-width: 150px;
}
}
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 66b80958..147d2305 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -191,21 +191,24 @@ en:
sync:
label: Sync
title: Sync Connection
- filters:
- title: Connection Filters
- label: Filters
- add:
- label: Add
- title: Add a filter
- done:
- label: Done
- title: Close filters
- filter:
- query_column:
- select: Select an attribute...
- query_value: Enter a value
- remove:
- title: Remove filter
+ filters:
+ title: Filters
+ label: Filters
+ add:
+ label: Add
+ title: Add a filter
+ done:
+ label: Done
+ title: Close filters
+ filter:
+ query_column:
+ label: Attribute
+ query_operator:
+ label: Operator
+ query_value:
+ label: Value
+ remove:
+ title: Remove filter
event:
title: Events
diff --git a/db/migrate/20240814091227_create_discourse_events_filters.rb b/db/migrate/20240814091227_create_discourse_events_filters.rb
new file mode 100644
index 00000000..5f19e168
--- /dev/null
+++ b/db/migrate/20240814091227_create_discourse_events_filters.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+class CreateDiscourseEventsFilters < ActiveRecord::Migration[7.1]
+ def up
+ create_table :discourse_events_filters do |t|
+ t.integer :model_id
+ t.string :model_type
+ t.integer :query_column
+ t.integer :query_operator
+ t.string :query_value
+
+ t.timestamps
+ end
+
+ execute "INSERT INTO discourse_events_filters (model_id, model_type, query_column, query_operator, query_value, created_at, updated_at)
+ SELECT cfs.id, 'DiscourseEvents::Connection', cfs.query_column, 0, cfs.query_value, cfs.created_at, cfs.updated_at
+ FROM discourse_events_connection_filters cfs"
+
+ add_index :discourse_events_filters,
+ %i[query_column query_operator query_value],
+ unique: true,
+ name: :idx_events_filter_column_operator_value
+ end
+
+ def down
+ remove_index :discourse_events_filters,
+ %i[query_column query_operator query_value],
+ name: :idx_events_filter_column_operator_value
+
+ drop_table :discourse_events_filters
+ end
+end
diff --git a/plugin.rb b/plugin.rb
index 52e2e516..d0bf6438 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
# name: discourse-events
# about: Allows you to manage events in Discourse
-# version: 0.5.5
+# version: 0.5.6
# authors: Angus McLeod
# contact_emails: angus@pavilion.tech
# url: https://github.com/paviliondev/discourse-events
@@ -60,7 +60,7 @@
require_relative "lib/discourse_events/syncer/events.rb"
require_relative "lib/discourse_events/auth/base.rb"
require_relative "lib/discourse_events/auth/meetup.rb"
- require_relative "app/models/discourse_events/connection_filter.rb"
+ require_relative "app/models/discourse_events/filter.rb"
require_relative "app/models/discourse_events/connection.rb"
require_relative "app/models/discourse_events/event_connection.rb"
require_relative "app/models/discourse_events/event.rb"
@@ -76,7 +76,7 @@
require_relative "app/controllers/discourse_events/provider_controller.rb"
require_relative "app/controllers/discourse_events/source_controller.rb"
require_relative "app/serializers/discourse_events/basic_event_serializer.rb"
- require_relative "app/serializers/discourse_events/connection_filter_serializer.rb"
+ require_relative "app/serializers/discourse_events/filter_serializer.rb"
require_relative "app/serializers/discourse_events/connection_serializer.rb"
require_relative "app/serializers/discourse_events/connection_user_serializer.rb"
require_relative "app/serializers/discourse_events/source_serializer.rb"
diff --git a/spec/fabricators/discourse_events_connection_filter_fabricator.rb b/spec/fabricators/discourse_events_connection_filter_fabricator.rb
deleted file mode 100644
index 17b75428..00000000
--- a/spec/fabricators/discourse_events_connection_filter_fabricator.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# frozen_string_literal: true
-
-Fabricator(:discourse_events_connection_filter, from: "DiscourseEvents::ConnectionFilter") do
- connection { Fabricate(:discourse_events_connection) }
- query_column { :name }
-end
diff --git a/spec/fabricators/discourse_events_filter_fabricator.rb b/spec/fabricators/discourse_events_filter_fabricator.rb
new file mode 100644
index 00000000..de37c4bf
--- /dev/null
+++ b/spec/fabricators/discourse_events_filter_fabricator.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+Fabricator(:discourse_events_filter, from: "DiscourseEvents::Filter") do
+ model { Fabricate(:discourse_events_connection) }
+ query_column { :name }
+ query_operator { :like }
+end
diff --git a/spec/lib/discourse_events/syncer_spec.rb b/spec/lib/discourse_events/syncer_spec.rb
index 8de5dcaf..bca6dffd 100644
--- a/spec/lib/discourse_events/syncer_spec.rb
+++ b/spec/lib/discourse_events/syncer_spec.rb
@@ -140,11 +140,7 @@ def sync_events(opts = {})
context "with filters" do
fab!(:filter1) do
- Fabricate(
- :discourse_events_connection_filter,
- connection: connection,
- query_value: event2.name,
- )
+ Fabricate(:discourse_events_filter, model: connection, query_value: event2.name)
end
it "filters events" do
diff --git a/spec/requests/discourse_events/connection_controller_spec.rb b/spec/requests/discourse_events/connection_controller_spec.rb
index 9065c282..4a86cbed 100644
--- a/spec/requests/discourse_events/connection_controller_spec.rb
+++ b/spec/requests/discourse_events/connection_controller_spec.rb
@@ -118,7 +118,14 @@
params: {
connection: {
client: "discourse_events",
- filters: [{ id: "new", query_column: "name", query_value: "Development" }],
+ filters: [
+ {
+ id: "new",
+ query_column: "name",
+ query_operator: "like",
+ query_value: "Development",
+ },
+ ],
},
}
expect(response.status).to eq(200)
@@ -129,15 +136,20 @@
end
it "updates filters" do
- filter1 = Fabricate(:discourse_events_connection_filter, connection: connection)
- filter2 = Fabricate(:discourse_events_connection_filter, connection: connection)
+ filter1 = Fabricate(:discourse_events_filter, model: connection)
+ filter2 = Fabricate(:discourse_events_filter, model: connection)
put "/admin/plugins/events/connection/#{connection.id}.json",
params: {
connection: {
client: "discourse_events",
filters: [
- { id: filter1.id, query_column: filter1.query_column, query_value: "New Value" },
+ {
+ id: filter1.id,
+ query_column: filter1.query_column,
+ query_operator: filter1.query_operator,
+ query_value: "New Value",
+ },
],
},
}
diff --git a/test/javascripts/acceptance/admin-connection-test.js b/test/javascripts/acceptance/admin-connection-test.js
index 1c9bd25f..c36baae3 100644
--- a/test/javascripts/acceptance/admin-connection-test.js
+++ b/test/javascripts/acceptance/admin-connection-test.js
@@ -170,33 +170,31 @@ acceptance("Events | Connection", function (needs) {
await click("tr[data-connection-id='1'] .btn.show-filters");
- assert.ok(
- exists(".events-connection-filters-modal"),
- "it shows the filter modal"
- );
+ assert.ok(exists(".events-filters-modal"), "it shows the filter modal");
- await click(".events-connection-filters-modal .add-filter");
+ await click(".events-filters-modal .add-filter");
assert.ok(
- exists(".events-connection-filters-modal .filter-column"),
+ exists(".events-filters-modal .filter-column"),
"it shows the filter column"
);
-
assert.ok(
- exists(".events-connection-filters-modal .filter-value"),
+ exists(".events-filters-modal .filter-value"),
"it shows the filter value"
);
- await selectKit(".events-connection-filters-modal .filter-column").expand();
- await selectKit(
- ".events-connection-filters-modal .filter-column"
- ).selectRowByValue("name");
+ await selectKit(".events-filters-modal .filter-column").expand();
+ await selectKit(".events-filters-modal .filter-column").selectRowByValue(
+ "name"
+ );
- await fillIn(
- ".events-connection-filters-modal .filter-value",
- "Event Name"
+ await selectKit(".events-filters-modal .filter-operator").expand();
+ await selectKit(".events-filters-modal .filter-operator").selectRowByValue(
+ "like"
);
- await click(".events-connection-filters-modal .btn-primary");
+ await fillIn(".events-filters-modal .filter-value", "Event Name");
+
+ await click(".events-filters-modal .btn-primary");
assert.ok(
exists("tr[data-connection-id='1'] .btn-primary.show-filters"),
@@ -206,21 +204,20 @@ acceptance("Events | Connection", function (needs) {
await click("#add-connection");
await click("tr[data-connection-id='new'] .btn.show-filters");
- assert.ok(
- exists(".events-connection-filters-modal"),
- "it shows the filter modal"
- );
+ assert.ok(exists(".events-filters-modal"), "it shows the filter modal");
- await click(".events-connection-filters-modal .add-filter");
+ await click(".events-filters-modal .add-filter");
assert.blank(
- selectKit(".events-connection-filters-modal .filter-column")
- .header()
- .value(),
+ selectKit(".events-filters-modal .filter-column").header().value(),
"filter column is blank"
);
assert.blank(
- query(".events-connection-filters-modal .filter-value").value,
+ selectKit(".events-filters-modal .filter-operator").header().value(),
+ "filter operator is blank"
+ );
+ assert.blank(
+ query(".events-filters-modal .filter-value").value,
"filter value is blank"
);
});