diff --git a/app/assets/javascripts/global_activities/index.js b/app/assets/javascripts/global_activities/index.js
index 4efc1e2e1..20c5fab2c 100644
--- a/app/assets/javascripts/global_activities/index.js
+++ b/app/assets/javascripts/global_activities/index.js
@@ -1,4 +1,4 @@
-/* global animateSpinner globalActivities */
+/* global animateSpinner globalActivities HelperModule */
'use strict';
@@ -59,6 +59,37 @@
});
}
+ function validateActivityFilterName() {
+ let filterName = $('#saveFilterModal .activity-filter-name-input').val();
+ $('#saveFilterModal .btn-confirm').prop('disabled', filterName.length === 0);
+ }
+
+ $('#saveFilterModal')
+ .on('keyup', '.activity-filter-name-input', function() {
+ validateActivityFilterName();
+ })
+ .on('click', '.btn-confirm', function() {
+ $.ajax({
+ url: this.dataset.saveFilterUrl,
+ type: 'POST',
+ global: false,
+ dataType: 'json',
+ data: {
+ name: $('#saveFilterModal .activity-filter-name-input').val(),
+ filter: globalActivities.getFilters()
+ },
+ success: function(data) {
+ HelperModule.flashAlertMsg(data.message, 'success');
+ $('#saveFilterModal .activity-filter-name-input').val('');
+ validateActivityFilterName();
+ $('#saveFilterModal').modal('hide');
+ },
+ error: function(response) {
+ HelperModule.flashAlertMsg(response.responseJSON.errors.join(','), 'danger');
+ }
+ });
+ });
+
initExpandCollapseAllButtons();
initShowMoreButton();
}());
diff --git a/app/controllers/global_activities_controller.rb b/app/controllers/global_activities_controller.rb
index a0b79c68b..67c493147 100644
--- a/app/controllers/global_activities_controller.rb
+++ b/app/controllers/global_activities_controller.rb
@@ -3,6 +3,8 @@
class GlobalActivitiesController < ApplicationController
include InputSanitizeHelper
+ before_action :check_create_activity_filter_permissions, only: :save_activity_filter
+
def index
# Preload filter format
# {
@@ -106,8 +108,21 @@ class GlobalActivitiesController < ApplicationController
render json: get_objects(Report)
end
+ def save_activity_filter
+ activity_filter = ActivityFilter.new(activity_filter_params)
+ if activity_filter.save
+ render json: { message: t('global_activities.index.activity_filter_saved') }
+ else
+ render json: { errors: activity_filter.errors.full_messages }, status: :unprocessable_entity
+ end
+ end
+
private
+ def check_create_activity_filter_permissions
+ render_403 && return unless can_create_acitivity_filters?
+ end
+
def get_objects(subject)
query = subject_search_params[:query]
teams =
@@ -138,6 +153,10 @@ class GlobalActivitiesController < ApplicationController
matched.map { |pr| { value: pr[0], label: escape_input(pr[1]) } }
end
+ def activity_filter_params
+ params.permit(:name, filter: {})
+ end
+
def activity_filters
params.permit(
:page, :starting_timestamp, :from_date, :to_date, types: [], subjects: {}, users: [], teams: []
diff --git a/app/models/activity_filter.rb b/app/models/activity_filter.rb
new file mode 100644
index 000000000..9006cd447
--- /dev/null
+++ b/app/models/activity_filter.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+class ActivityFilter < ApplicationRecord
+ validates :name, presence: true
+ validates :filter, presence: true
+end
diff --git a/app/permissions/organization.rb b/app/permissions/organization.rb
index 47e7891b9..0c06f1087 100644
--- a/app/permissions/organization.rb
+++ b/app/permissions/organization.rb
@@ -8,5 +8,9 @@ module Organization
can :create_teams do |_|
true
end
+
+ can :create_acitivity_filters do
+ ENV['WEBHOOKS_ENABLED'] == 'true'
+ end
end
end
diff --git a/app/views/global_activities/_save_filter_modal.html.erb b/app/views/global_activities/_save_filter_modal.html.erb
new file mode 100644
index 000000000..8014d5d63
--- /dev/null
+++ b/app/views/global_activities/_save_filter_modal.html.erb
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+ <%= t('global_activities.index.save_filter_modal.description') %>
+
+
+
+
+
+
+
+
+
+
diff --git a/app/views/global_activities/_top_pane.html.erb b/app/views/global_activities/_top_pane.html.erb
index b4586d2e1..e83abcd3c 100644
--- a/app/views/global_activities/_top_pane.html.erb
+++ b/app/views/global_activities/_top_pane.html.erb
@@ -17,6 +17,11 @@
+<%= render partial: 'save_filter_modal' %>
+
diff --git a/config/locales/en.yml b/config/locales/en.yml
index f2ed6495c..b4a8cab78 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -1682,6 +1682,7 @@ en:
activities_counter_label: " activities"
expand_all: "Expand all"
collapse_all: "Collapse all"
+
modal:
modal_title: "Activities"
result_type:
diff --git a/config/locales/global_activities/en.yml b/config/locales/global_activities/en.yml
index 79d7e3a97..2e13d6786 100644
--- a/config/locales/global_activities/en.yml
+++ b/config/locales/global_activities/en.yml
@@ -36,6 +36,13 @@ en:
select_reports: Select Reports
no_name: "(unnamed)"
content_generation_error: "Failed to render activity content with id: %{activity_id}"
+ activity_filter_saved: "Filter successfully saved to the Webhooks page!"
+ save_filter: "Save filter"
+ save_filter_modal:
+ title: "Save filter"
+ description: "Saved filter will be located in the Webhooks section of the Settings. It can be used to trigger webhooks."
+ filter_name_label: "Filter name"
+ filter_name_placeholder: "Name your filter"
content:
create_project_html: "%{user} created project %{project}."
rename_project_html: "%{user} renamed project %{project}."
diff --git a/config/routes.rb b/config/routes.rb
index e4a3bf31c..ebcad31d0 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -761,6 +761,7 @@ Rails.application.routes.draw do
get :protocol_filter
get :team_filter
get :user_filter
+ post :save_activity_filter
end
end
diff --git a/db/migrate/20210531114633_create_activity_filters.rb b/db/migrate/20210531114633_create_activity_filters.rb
new file mode 100644
index 000000000..b517a5671
--- /dev/null
+++ b/db/migrate/20210531114633_create_activity_filters.rb
@@ -0,0 +1,10 @@
+class CreateActivityFilters < ActiveRecord::Migration[4.2]
+ def change
+ create_table :activity_filters do |t|
+ t.string :name, null: false
+ t.jsonb :filter, null: false
+
+ t.timestamps null: false
+ end
+ end
+end
diff --git a/db/structure.sql b/db/structure.sql
index 5e7b05333..e1bb211dd 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -193,6 +193,39 @@ CREATE SEQUENCE public.activities_id_seq
ALTER SEQUENCE public.activities_id_seq OWNED BY public.activities.id;
+--
+-- Name: activity_filters; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.activity_filters (
+ id integer NOT NULL,
+ name character varying NOT NULL,
+ filter jsonb NOT NULL,
+ created_at timestamp without time zone NOT NULL,
+ updated_at timestamp without time zone NOT NULL
+);
+
+
+--
+-- Name: activity_filters_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE public.activity_filters_id_seq
+ AS integer
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+--
+-- Name: activity_filters_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE public.activity_filters_id_seq OWNED BY public.activity_filters.id;
+
+
--
-- Name: ar_internal_metadata; Type: TABLE; Schema: public; Owner: -
--
@@ -2918,6 +2951,13 @@ ALTER TABLE ONLY public.active_storage_variant_records ALTER COLUMN id SET DEFAU
ALTER TABLE ONLY public.activities ALTER COLUMN id SET DEFAULT nextval('public.activities_id_seq'::regclass);
+--
+-- Name: activity_filters id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.activity_filters ALTER COLUMN id SET DEFAULT nextval('public.activity_filters_id_seq'::regclass);
+
+
--
-- Name: asset_text_data id; Type: DEFAULT; Schema: public; Owner: -
--
@@ -3468,6 +3508,14 @@ ALTER TABLE ONLY public.activities
ADD CONSTRAINT activities_pkey PRIMARY KEY (id);
+--
+-- Name: activity_filters activity_filters_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.activity_filters
+ ADD CONSTRAINT activity_filters_pkey PRIMARY KEY (id);
+
+
--
-- Name: ar_internal_metadata ar_internal_metadata_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -7234,6 +7282,8 @@ INSERT INTO "schema_migrations" (version) VALUES
('20210312185911'),
('20210325152257'),
('20210407143303'),
-('20210506125657');
+('20210410100006'),
+('20210506125657'),
+('20210531114633');