DEV: Introduce syntax_tree for ruby formatting (#208)
This commit is contained in:
parent
ac6b0467a1
commit
148d6c32a3
|
@ -55,3 +55,12 @@ jobs:
|
||||||
- name: Rubocop
|
- name: Rubocop
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
run: bundle exec rubocop .
|
run: bundle exec rubocop .
|
||||||
|
|
||||||
|
- name: Syntax Tree
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
run: |
|
||||||
|
if test -f .streerc; then
|
||||||
|
bundle exec stree check Gemfile $(git ls-files '*.rb') $(git ls-files '*.rake')
|
||||||
|
else
|
||||||
|
echo "Stree config not detected for this repository. Skipping."
|
||||||
|
fi
|
||||||
|
|
|
@ -80,7 +80,7 @@ jobs:
|
||||||
|
|
||||||
- name: Get yarn cache directory
|
- name: Get yarn cache directory
|
||||||
id: yarn-cache-dir
|
id: yarn-cache-dir
|
||||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Yarn cache
|
- name: Yarn cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
|
@ -130,7 +130,7 @@ jobs:
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
if [ 0 -lt $(find plugins/${{ github.event.repository.name }}/spec -type f -name "*.rb" 2> /dev/null | wc -l) ]; then
|
if [ 0 -lt $(find plugins/${{ github.event.repository.name }}/spec -type f -name "*.rb" 2> /dev/null | wc -l) ]; then
|
||||||
echo "::set-output name=files_exist::true"
|
echo "files_exist=true" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Plugin RSpec
|
- name: Plugin RSpec
|
||||||
|
@ -142,7 +142,7 @@ jobs:
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
if [ 0 -lt $(find plugins/${{ github.event.repository.name }}/test/javascripts -type f \( -name "*.js" -or -name "*.es6" \) 2> /dev/null | wc -l) ]; then
|
if [ 0 -lt $(find plugins/${{ github.event.repository.name }}/test/javascripts -type f \( -name "*.js" -or -name "*.es6" \) 2> /dev/null | wc -l) ]; then
|
||||||
echo "::set-output name=files_exist::true"
|
echo "files_exist=true" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Plugin QUnit
|
- name: Plugin QUnit
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
inherit_gem:
|
inherit_gem:
|
||||||
rubocop-discourse: default.yml
|
rubocop-discourse: stree-compat.yml
|
||||||
|
|
5
Gemfile
5
Gemfile
|
@ -1,7 +1,8 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
source 'https://rubygems.org'
|
source "https://rubygems.org"
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
gem 'rubocop-discourse'
|
gem "rubocop-discourse"
|
||||||
|
gem "syntax_tree"
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,6 +6,7 @@ GEM
|
||||||
parallel (1.22.1)
|
parallel (1.22.1)
|
||||||
parser (3.1.2.1)
|
parser (3.1.2.1)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
|
prettier_print (1.2.0)
|
||||||
rainbow (3.1.1)
|
rainbow (3.1.1)
|
||||||
regexp_parser (2.6.0)
|
regexp_parser (2.6.0)
|
||||||
rexml (3.2.5)
|
rexml (3.2.5)
|
||||||
|
@ -27,6 +28,8 @@ GEM
|
||||||
rubocop-rspec (2.13.2)
|
rubocop-rspec (2.13.2)
|
||||||
rubocop (~> 1.33)
|
rubocop (~> 1.33)
|
||||||
ruby-progressbar (1.11.0)
|
ruby-progressbar (1.11.0)
|
||||||
|
syntax_tree (5.1.0)
|
||||||
|
prettier_print (>= 1.2.0)
|
||||||
unicode-display_width (2.3.0)
|
unicode-display_width (2.3.0)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
|
@ -39,6 +42,7 @@ PLATFORMS
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
rubocop-discourse
|
rubocop-discourse
|
||||||
|
syntax_tree
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.3.10
|
2.3.10
|
||||||
|
|
|
@ -3,19 +3,17 @@
|
||||||
class DataExplorer::QueryController < ::ApplicationController
|
class DataExplorer::QueryController < ::ApplicationController
|
||||||
requires_plugin DataExplorer.plugin_name
|
requires_plugin DataExplorer.plugin_name
|
||||||
|
|
||||||
before_action :set_group, only: %i(group_reports_index group_reports_show group_reports_run)
|
before_action :set_group, only: %i[group_reports_index group_reports_show group_reports_run]
|
||||||
before_action :set_query, only: %i(group_reports_show group_reports_run show update)
|
before_action :set_query, only: %i[group_reports_show group_reports_run show update]
|
||||||
before_action :ensure_admin
|
before_action :ensure_admin
|
||||||
|
|
||||||
skip_before_action :check_xhr, only: %i(show group_reports_run run)
|
skip_before_action :check_xhr, only: %i[show group_reports_run run]
|
||||||
skip_before_action :ensure_admin, only: %i(
|
skip_before_action :ensure_admin,
|
||||||
group_reports_index
|
only: %i[group_reports_index group_reports_show group_reports_run]
|
||||||
group_reports_show
|
|
||||||
group_reports_run
|
|
||||||
)
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
queries = DataExplorer::Query.where(hidden: false).order(:last_run_at, :name).includes(:groups).to_a
|
queries =
|
||||||
|
DataExplorer::Query.where(hidden: false).order(:last_run_at, :name).includes(:groups).to_a
|
||||||
|
|
||||||
database_queries_ids = DataExplorer::Query.pluck(:id)
|
database_queries_ids = DataExplorer::Query.pluck(:id)
|
||||||
Queries.default.each do |params|
|
Queries.default.each do |params|
|
||||||
|
@ -30,19 +28,19 @@ class DataExplorer::QueryController < ::ApplicationController
|
||||||
queries << query
|
queries << query
|
||||||
end
|
end
|
||||||
|
|
||||||
render_serialized queries, DataExplorer::QuerySerializer, root: 'queries'
|
render_serialized queries, DataExplorer::QuerySerializer, root: "queries"
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
check_xhr unless params[:export]
|
check_xhr unless params[:export]
|
||||||
|
|
||||||
if params[:export]
|
if params[:export]
|
||||||
response.headers['Content-Disposition'] = "attachment; filename=#{@query.slug}.dcquery.json"
|
response.headers["Content-Disposition"] = "attachment; filename=#{@query.slug}.dcquery.json"
|
||||||
response.sending_file = true
|
response.sending_file = true
|
||||||
end
|
end
|
||||||
|
|
||||||
return raise Discourse::NotFound if !guardian.user_can_access_query?(@query) || @query.hidden
|
return raise Discourse::NotFound if !guardian.user_can_access_query?(@query) || @query.hidden
|
||||||
render_serialized @query, DataExplorer::QuerySerializer, root: 'query'
|
render_serialized @query, DataExplorer::QuerySerializer, root: "query"
|
||||||
end
|
end
|
||||||
|
|
||||||
def groups
|
def groups
|
||||||
|
@ -55,40 +53,48 @@ class DataExplorer::QueryController < ::ApplicationController
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json do
|
format.json do
|
||||||
queries = DataExplorer::Query.for_group(@group)
|
queries = DataExplorer::Query.for_group(@group)
|
||||||
render_serialized(queries, DataExplorer::QuerySerializer, root: 'queries')
|
render_serialized(queries, DataExplorer::QuerySerializer, root: "queries")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def group_reports_show
|
def group_reports_show
|
||||||
return raise Discourse::NotFound if !guardian.group_and_user_can_access_query?(@group, @query) || @query.hidden
|
if !guardian.group_and_user_can_access_query?(@group, @query) || @query.hidden
|
||||||
|
return raise Discourse::NotFound
|
||||||
|
end
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json do
|
format.json do
|
||||||
query_group = DataExplorer::QueryGroup.find_by(query_id: @query.id, group_id: @group.id)
|
query_group = DataExplorer::QueryGroup.find_by(query_id: @query.id, group_id: @group.id)
|
||||||
|
|
||||||
render json: {
|
render json: {
|
||||||
query: serialize_data(@query, DataExplorer::QuerySerializer, root: nil),
|
query: serialize_data(@query, DataExplorer::QuerySerializer, root: nil),
|
||||||
query_group: serialize_data(query_group, DataExplorer::QueryGroupSerializer, root: nil),
|
query_group:
|
||||||
}
|
serialize_data(query_group, DataExplorer::QueryGroupSerializer, root: nil),
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def group_reports_run
|
def group_reports_run
|
||||||
return raise Discourse::NotFound if !guardian.group_and_user_can_access_query?(@group, @query) || @query.hidden
|
if !guardian.group_and_user_can_access_query?(@group, @query) || @query.hidden
|
||||||
|
return raise Discourse::NotFound
|
||||||
|
end
|
||||||
|
|
||||||
run
|
run
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
query = DataExplorer::Query.create!(params.require(:query).permit(:name, :description, :sql).merge(user_id: current_user.id, last_run_at: Time.now))
|
query =
|
||||||
|
DataExplorer::Query.create!(
|
||||||
|
params
|
||||||
|
.require(:query)
|
||||||
|
.permit(:name, :description, :sql)
|
||||||
|
.merge(user_id: current_user.id, last_run_at: Time.now),
|
||||||
|
)
|
||||||
group_ids = params.require(:query)[:group_ids]
|
group_ids = params.require(:query)[:group_ids]
|
||||||
group_ids&.each do |group_id|
|
group_ids&.each { |group_id| query.query_groups.find_or_create_by!(group_id: group_id) }
|
||||||
query.query_groups.find_or_create_by!(group_id: group_id)
|
render_serialized query, DataExplorer::QuerySerializer, root: "query"
|
||||||
end
|
|
||||||
render_serialized query, DataExplorer::QuerySerializer, root: 'query'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
@ -97,12 +103,10 @@ class DataExplorer::QueryController < ::ApplicationController
|
||||||
|
|
||||||
group_ids = params.require(:query)[:group_ids]
|
group_ids = params.require(:query)[:group_ids]
|
||||||
DataExplorer::QueryGroup.where.not(group_id: group_ids).where(query_id: @query.id).delete_all
|
DataExplorer::QueryGroup.where.not(group_id: group_ids).where(query_id: @query.id).delete_all
|
||||||
group_ids&.each do |group_id|
|
group_ids&.each { |group_id| @query.query_groups.find_or_create_by!(group_id: group_id) }
|
||||||
@query.query_groups.find_or_create_by!(group_id: group_id)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
render_serialized @query, DataExplorer::QuerySerializer, root: 'query'
|
render_serialized @query, DataExplorer::QuerySerializer, root: "query"
|
||||||
rescue DataExplorer::ValidationError => e
|
rescue DataExplorer::ValidationError => e
|
||||||
render_json_error e.message
|
render_json_error e.message
|
||||||
end
|
end
|
||||||
|
@ -116,9 +120,7 @@ class DataExplorer::QueryController < ::ApplicationController
|
||||||
|
|
||||||
def schema
|
def schema
|
||||||
schema_version = DB.query_single("SELECT max(version) AS tag FROM schema_migrations").first
|
schema_version = DB.query_single("SELECT max(version) AS tag FROM schema_migrations").first
|
||||||
if stale?(public: true, etag: schema_version, template: false)
|
render json: DataExplorer.schema if stale?(public: true, etag: schema_version, template: false)
|
||||||
render json: DataExplorer.schema
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return value:
|
# Return value:
|
||||||
|
@ -135,9 +137,7 @@ class DataExplorer::QueryController < ::ApplicationController
|
||||||
query = DataExplorer::Query.find(params[:id].to_i)
|
query = DataExplorer::Query.find(params[:id].to_i)
|
||||||
query.update!(last_run_at: Time.now)
|
query.update!(last_run_at: Time.now)
|
||||||
|
|
||||||
if params[:download]
|
response.sending_file = true if params[:download]
|
||||||
response.sending_file = true
|
|
||||||
end
|
|
||||||
|
|
||||||
query_params = {}
|
query_params = {}
|
||||||
query_params = MultiJson.load(params[:params]) if params[:params]
|
query_params = MultiJson.load(params[:params]) if params[:params]
|
||||||
|
@ -145,18 +145,17 @@ class DataExplorer::QueryController < ::ApplicationController
|
||||||
opts = { current_user: current_user.username }
|
opts = { current_user: current_user.username }
|
||||||
opts[:explain] = true if params[:explain] == "true"
|
opts[:explain] = true if params[:explain] == "true"
|
||||||
|
|
||||||
opts[:limit] =
|
opts[:limit] = if params[:format] == "csv"
|
||||||
if params[:format] == "csv"
|
if params[:limit].present?
|
||||||
if params[:limit].present?
|
limit = params[:limit].to_i
|
||||||
limit = params[:limit].to_i
|
limit = DataExplorer::QUERY_RESULT_MAX_LIMIT if limit > DataExplorer::QUERY_RESULT_MAX_LIMIT
|
||||||
limit = DataExplorer::QUERY_RESULT_MAX_LIMIT if limit > DataExplorer::QUERY_RESULT_MAX_LIMIT
|
limit
|
||||||
limit
|
else
|
||||||
else
|
DataExplorer::QUERY_RESULT_MAX_LIMIT
|
||||||
DataExplorer::QUERY_RESULT_MAX_LIMIT
|
|
||||||
end
|
|
||||||
elsif params[:limit].present?
|
|
||||||
params[:limit] == "ALL" ? "ALL" : params[:limit].to_i
|
|
||||||
end
|
end
|
||||||
|
elsif params[:limit].present?
|
||||||
|
params[:limit] == "ALL" ? "ALL" : params[:limit].to_i
|
||||||
|
end
|
||||||
|
|
||||||
result = DataExplorer.run_query(query, query_params, opts)
|
result = DataExplorer.run_query(query, query_params, opts)
|
||||||
|
|
||||||
|
@ -168,23 +167,21 @@ class DataExplorer::QueryController < ::ApplicationController
|
||||||
err_msg = err.message
|
err_msg = err.message
|
||||||
if err.is_a? ActiveRecord::StatementInvalid
|
if err.is_a? ActiveRecord::StatementInvalid
|
||||||
err_class = err.original_exception.class
|
err_class = err.original_exception.class
|
||||||
err_msg.gsub!("#{err_class}:", '')
|
err_msg.gsub!("#{err_class}:", "")
|
||||||
else
|
else
|
||||||
err_msg = "#{err_class}: #{err_msg}"
|
err_msg = "#{err_class}: #{err_msg}"
|
||||||
end
|
end
|
||||||
|
|
||||||
render json: {
|
render json: { success: false, errors: [err_msg] }, status: 422
|
||||||
success: false,
|
|
||||||
errors: [err_msg]
|
|
||||||
}, status: 422
|
|
||||||
else
|
else
|
||||||
pg_result = result[:pg_result]
|
pg_result = result[:pg_result]
|
||||||
cols = pg_result.fields
|
cols = pg_result.fields
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json do
|
format.json do
|
||||||
if params[:download]
|
if params[:download]
|
||||||
response.headers['Content-Disposition'] =
|
response.headers[
|
||||||
"attachment; filename=#{query.slug}@#{Slug.for(Discourse.current_hostname, 'discourse')}-#{Date.today}.dcqresult.json"
|
"Content-Disposition"
|
||||||
|
] = "attachment; filename=#{query.slug}@#{Slug.for(Discourse.current_hostname, "discourse")}-#{Date.today}.dcqresult.json"
|
||||||
end
|
end
|
||||||
json = {
|
json = {
|
||||||
success: true,
|
success: true,
|
||||||
|
@ -193,7 +190,7 @@ class DataExplorer::QueryController < ::ApplicationController
|
||||||
result_count: pg_result.values.length || 0,
|
result_count: pg_result.values.length || 0,
|
||||||
params: query_params,
|
params: query_params,
|
||||||
columns: cols,
|
columns: cols,
|
||||||
default_limit: SiteSetting.data_explorer_query_result_limit
|
default_limit: SiteSetting.data_explorer_query_result_limit,
|
||||||
}
|
}
|
||||||
json[:explain] = result[:explain] if opts[:explain]
|
json[:explain] = result[:explain] if opts[:explain]
|
||||||
|
|
||||||
|
@ -208,16 +205,16 @@ class DataExplorer::QueryController < ::ApplicationController
|
||||||
render json: json
|
render json: json
|
||||||
end
|
end
|
||||||
format.csv do
|
format.csv do
|
||||||
response.headers['Content-Disposition'] =
|
response.headers[
|
||||||
"attachment; filename=#{query.slug}@#{Slug.for(Discourse.current_hostname, 'discourse')}-#{Date.today}.dcqresult.csv"
|
"Content-Disposition"
|
||||||
|
] = "attachment; filename=#{query.slug}@#{Slug.for(Discourse.current_hostname, "discourse")}-#{Date.today}.dcqresult.csv"
|
||||||
|
|
||||||
require 'csv'
|
require "csv"
|
||||||
text = CSV.generate do |csv|
|
text =
|
||||||
csv << cols
|
CSV.generate do |csv|
|
||||||
pg_result.values.each do |row|
|
csv << cols
|
||||||
csv << row
|
pg_result.values.each { |row| csv << row }
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
render plain: text
|
render plain: text
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,9 +7,13 @@ module Jobs
|
||||||
def execute(args)
|
def execute(args)
|
||||||
return unless SiteSetting.data_explorer_enabled
|
return unless SiteSetting.data_explorer_enabled
|
||||||
|
|
||||||
DataExplorer::Query.where("id > 0")
|
DataExplorer::Query
|
||||||
|
.where("id > 0")
|
||||||
.where(hidden: true)
|
.where(hidden: true)
|
||||||
.where("(last_run_at IS NULL OR last_run_at < :days_ago) AND updated_at < :days_ago", days_ago: 7.days.ago)
|
.where(
|
||||||
|
"(last_run_at IS NULL OR last_run_at < :days_ago) AND updated_at < :days_ago",
|
||||||
|
days_ago: 7.days.ago,
|
||||||
|
)
|
||||||
.delete_all
|
.delete_all
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,18 +2,20 @@
|
||||||
|
|
||||||
module DataExplorer
|
module DataExplorer
|
||||||
class Query < ActiveRecord::Base
|
class Query < ActiveRecord::Base
|
||||||
self.table_name = 'data_explorer_queries'
|
self.table_name = "data_explorer_queries"
|
||||||
has_many :query_groups
|
has_many :query_groups
|
||||||
has_many :groups, through: :query_groups
|
has_many :groups, through: :query_groups
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
|
|
||||||
scope :for_group, ->(group) do
|
scope :for_group,
|
||||||
where(hidden: false)
|
->(group) {
|
||||||
.joins("INNER JOIN data_explorer_query_groups
|
where(hidden: false).joins(
|
||||||
|
"INNER JOIN data_explorer_query_groups
|
||||||
ON data_explorer_query_groups.query_id = data_explorer_queries.id
|
ON data_explorer_query_groups.query_id = data_explorer_queries.id
|
||||||
AND data_explorer_query_groups.group_id = #{group.id}")
|
AND data_explorer_query_groups.group_id = #{group.id}",
|
||||||
end
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def params
|
def params
|
||||||
@params ||= DataExplorer::Parameter.create_from_sql(sql)
|
@params ||= DataExplorer::Parameter.create_from_sql(sql)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
module DataExplorer
|
module DataExplorer
|
||||||
class QueryGroup < ActiveRecord::Base
|
class QueryGroup < ActiveRecord::Base
|
||||||
self.table_name = 'data_explorer_query_groups'
|
self.table_name = "data_explorer_query_groups"
|
||||||
|
|
||||||
belongs_to :query
|
belongs_to :query
|
||||||
belongs_to :group
|
belongs_to :group
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class DataExplorer::QueryGroupSerializer < ActiveModel::Serializer
|
class DataExplorer::QueryGroupSerializer < ActiveModel::Serializer
|
||||||
attributes :id, :group_id, :query_id, :bookmark,
|
attributes :id,
|
||||||
|
:group_id,
|
||||||
def query_group_bookmark
|
:query_id,
|
||||||
@query_group_bookmark ||= Bookmark.find_by(user: scope.user, bookmarkable: object)
|
:bookmark,
|
||||||
end
|
def query_group_bookmark
|
||||||
|
@query_group_bookmark ||= Bookmark.find_by(user: scope.user, bookmarkable: object)
|
||||||
|
end
|
||||||
|
|
||||||
def include_bookmark?
|
def include_bookmark?
|
||||||
query_group_bookmark.present?
|
query_group_bookmark.present?
|
||||||
|
@ -18,8 +20,7 @@ class DataExplorer::QueryGroupSerializer < ActiveModel::Serializer
|
||||||
name: query_group_bookmark.name,
|
name: query_group_bookmark.name,
|
||||||
auto_delete_preference: query_group_bookmark.auto_delete_preference,
|
auto_delete_preference: query_group_bookmark.auto_delete_preference,
|
||||||
bookmarkable_id: query_group_bookmark.bookmarkable_id,
|
bookmarkable_id: query_group_bookmark.bookmarkable_id,
|
||||||
bookmarkable_type: query_group_bookmark.bookmarkable_type
|
bookmarkable_type: query_group_bookmark.bookmarkable_type,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,17 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class DataExplorer::QuerySerializer < ActiveModel::Serializer
|
class DataExplorer::QuerySerializer < ActiveModel::Serializer
|
||||||
attributes :id, :sql, :name, :description, :param_info, :created_at, :username, :group_ids, :last_run_at, :hidden, :user_id
|
attributes :id,
|
||||||
|
:sql,
|
||||||
|
:name,
|
||||||
|
:description,
|
||||||
|
:param_info,
|
||||||
|
:created_at,
|
||||||
|
:username,
|
||||||
|
:group_ids,
|
||||||
|
:last_run_at,
|
||||||
|
:hidden,
|
||||||
|
:user_id
|
||||||
|
|
||||||
def param_info
|
def param_info
|
||||||
object&.params&.map(&:to_hash)
|
object&.params&.map(&:to_hash)
|
||||||
|
|
|
@ -18,7 +18,7 @@ class CreateDataExplorerQueries < ActiveRecord::Migration[6.0]
|
||||||
t.index :query_id
|
t.index :query_id
|
||||||
t.index :group_id
|
t.index :group_id
|
||||||
end
|
end
|
||||||
add_index(:data_explorer_query_groups, [:query_id, :group_id], unique: true)
|
add_index(:data_explorer_query_groups, %i[query_id group_id], unique: true)
|
||||||
|
|
||||||
DB.exec <<~SQL, now: Time.zone.now
|
DB.exec <<~SQL, now: Time.zone.now
|
||||||
INSERT INTO data_explorer_queries(id, name, description, sql, user_id, last_run_at, hidden, created_at, updated_at)
|
INSERT INTO data_explorer_queries(id, name, description, sql, user_id, last_run_at, hidden, created_at, updated_at)
|
||||||
|
@ -56,20 +56,32 @@ class CreateDataExplorerQueries < ActiveRecord::Migration[6.0]
|
||||||
WHERE plugin_name = 'discourse-data-explorer' AND type_name = 'JSON'
|
WHERE plugin_name = 'discourse-data-explorer' AND type_name = 'JSON'
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
DB.query("SELECT * FROM plugin_store_rows WHERE plugin_name = 'discourse-data-explorer' AND type_name = 'JSON'").each do |row|
|
DB
|
||||||
json = JSON.parse(row.value)
|
.query(
|
||||||
next if json['group_ids'].blank?
|
"SELECT * FROM plugin_store_rows WHERE plugin_name = 'discourse-data-explorer' AND type_name = 'JSON'",
|
||||||
query_id = DB.query("SELECT id FROM data_explorer_queries WHERE
|
)
|
||||||
name = ? AND sql = ?", json['name'], json['sql']).first.id
|
.each do |row|
|
||||||
|
json = JSON.parse(row.value)
|
||||||
|
next if json["group_ids"].blank?
|
||||||
|
query_id =
|
||||||
|
DB
|
||||||
|
.query(
|
||||||
|
"SELECT id FROM data_explorer_queries WHERE
|
||||||
|
name = ? AND sql = ?",
|
||||||
|
json["name"],
|
||||||
|
json["sql"],
|
||||||
|
)
|
||||||
|
.first
|
||||||
|
.id
|
||||||
|
|
||||||
json['group_ids'].each do |group_id|
|
json["group_ids"].each do |group_id|
|
||||||
next if group_id.blank? || query_id.blank?
|
next if group_id.blank? || query_id.blank?
|
||||||
DB.exec <<~SQL
|
DB.exec <<~SQL
|
||||||
INSERT INTO data_explorer_query_groups(query_id, group_id)
|
INSERT INTO data_explorer_query_groups(query_id, group_id)
|
||||||
VALUES(#{query_id}, #{group_id})
|
VALUES(#{query_id}, #{group_id})
|
||||||
SQL
|
SQL
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
DB.exec <<~SQL
|
DB.exec <<~SQL
|
||||||
SELECT
|
SELECT
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
class FixQueryIds < ActiveRecord::Migration[6.0]
|
class FixQueryIds < ActiveRecord::Migration[6.0]
|
||||||
def up
|
def up
|
||||||
Rake::Task['data_explorer:fix_query_ids'].invoke
|
Rake::Task["data_explorer:fix_query_ids"].invoke
|
||||||
end
|
end
|
||||||
|
|
||||||
def down
|
def down
|
||||||
|
|
|
@ -10,7 +10,7 @@ class DataExplorerQueryGroupBookmarkable < BaseBookmarkable
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.preload_associations
|
def self.preload_associations
|
||||||
[:data_explorer_queries, :groups]
|
%i[data_explorer_queries groups]
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.list_query(user, guardian)
|
def self.list_query(user, guardian)
|
||||||
|
@ -20,17 +20,22 @@ class DataExplorerQueryGroupBookmarkable < BaseBookmarkable
|
||||||
return if group_ids.empty?
|
return if group_ids.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
query = user.bookmarks_of_type("DataExplorer::QueryGroup")
|
query =
|
||||||
.joins("INNER JOIN data_explorer_query_groups ON data_explorer_query_groups.id = bookmarks.bookmarkable_id")
|
user
|
||||||
.joins("LEFT JOIN data_explorer_queries ON data_explorer_queries.id = data_explorer_query_groups.query_id")
|
.bookmarks_of_type("DataExplorer::QueryGroup")
|
||||||
|
.joins(
|
||||||
|
"INNER JOIN data_explorer_query_groups ON data_explorer_query_groups.id = bookmarks.bookmarkable_id",
|
||||||
|
)
|
||||||
|
.joins(
|
||||||
|
"LEFT JOIN data_explorer_queries ON data_explorer_queries.id = data_explorer_query_groups.query_id",
|
||||||
|
)
|
||||||
query = query.where("data_explorer_query_groups.group_id IN (?)", group_ids) if !user.admin?
|
query = query.where("data_explorer_query_groups.group_id IN (?)", group_ids) if !user.admin?
|
||||||
query
|
query
|
||||||
end
|
end
|
||||||
|
|
||||||
# Searchable only by data_explorer_queries name
|
# Searchable only by data_explorer_queries name
|
||||||
def self.search_query(bookmarks, query, ts_query, &bookmarkable_search)
|
def self.search_query(bookmarks, query, ts_query, &bookmarkable_search)
|
||||||
bookmarkable_search.call(bookmarks,
|
bookmarkable_search.call(bookmarks, "data_explorer_queries.name ILIKE :q")
|
||||||
"data_explorer_queries.name ILIKE :q")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.reminder_handler(bookmark)
|
def self.reminder_handler(bookmark)
|
||||||
|
@ -38,8 +43,9 @@ class DataExplorerQueryGroupBookmarkable < BaseBookmarkable
|
||||||
bookmark,
|
bookmark,
|
||||||
data: {
|
data: {
|
||||||
title: bookmark.bookmarkable.query.name,
|
title: bookmark.bookmarkable.query.name,
|
||||||
bookmarkable_url: "/g/#{bookmark.bookmarkable.group.name}/reports/#{bookmark.bookmarkable.query.id}"
|
bookmarkable_url:
|
||||||
}
|
"/g/#{bookmark.bookmarkable.group.name}/reports/#{bookmark.bookmarkable.query.id}",
|
||||||
|
},
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -51,5 +57,4 @@ class DataExplorerQueryGroupBookmarkable < BaseBookmarkable
|
||||||
return false if !bookmark.bookmarkable.group
|
return false if !bookmark.bookmarkable.group
|
||||||
guardian.user_is_a_member_of_group?(bookmark.bookmarkable.group)
|
guardian.user_is_a_member_of_group?(bookmark.bookmarkable.group)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
194
lib/queries.rb
194
lib/queries.rb
|
@ -11,96 +11,104 @@ class Queries
|
||||||
# you must run the query with id=-1 on the site again to update these changes in the site db
|
# you must run the query with id=-1 on the site again to update these changes in the site db
|
||||||
|
|
||||||
queries = {
|
queries = {
|
||||||
"most-common-likers": {
|
"most-common-likers": {
|
||||||
"id": -1,
|
id: -1,
|
||||||
"name": "Most Common Likers",
|
name: "Most Common Likers",
|
||||||
"description": "Which users like particular other users the most?"
|
description: "Which users like particular other users the most?",
|
||||||
},
|
},
|
||||||
"most-messages": {
|
"most-messages": {
|
||||||
"id": -2,
|
id: -2,
|
||||||
"name": "Who has been sending the most messages in the last week?",
|
name: "Who has been sending the most messages in the last week?",
|
||||||
"description": "tracking down suspicious PM activity"
|
description: "tracking down suspicious PM activity",
|
||||||
},
|
},
|
||||||
"edited-post-spam": {
|
"edited-post-spam": {
|
||||||
"id": -3,
|
id: -3,
|
||||||
"name": "Last 500 posts that were edited by TL0/TL1 users",
|
name: "Last 500 posts that were edited by TL0/TL1 users",
|
||||||
"description": "fighting human-driven copy-paste spam"
|
description: "fighting human-driven copy-paste spam",
|
||||||
},
|
},
|
||||||
"new-topics": {
|
"new-topics": {
|
||||||
"id": -4,
|
id: -4,
|
||||||
"name": "New Topics by Category",
|
name: "New Topics by Category",
|
||||||
"description": "Lists all new topics ordered by category and creation_date. The query accepts a ‘months_ago’ parameter. It defaults to 0 to give you the stats for the current month."
|
description:
|
||||||
},
|
"Lists all new topics ordered by category and creation_date. The query accepts a ‘months_ago’ parameter. It defaults to 0 to give you the stats for the current month.",
|
||||||
"active-topics": {
|
},
|
||||||
"id": -5,
|
"active-topics": {
|
||||||
"name": "Top 100 Active Topics",
|
id: -5,
|
||||||
"description": "based on the number of replies, it accepts a ‘months_ago’ parameter, defaults to 1 to give results for the last calendar month."
|
name: "Top 100 Active Topics",
|
||||||
},
|
description:
|
||||||
"top-likers": {
|
"based on the number of replies, it accepts a ‘months_ago’ parameter, defaults to 1 to give results for the last calendar month.",
|
||||||
"id": -6,
|
},
|
||||||
"name": "Top 100 Likers",
|
"top-likers": {
|
||||||
"description": "returns the top 100 likers for a given monthly period ordered by like_count. It accepts a ‘months_ago’ parameter, defaults to 1 to give results for the last calendar month."
|
id: -6,
|
||||||
},
|
name: "Top 100 Likers",
|
||||||
"quality-users": {
|
description:
|
||||||
"id": -7,
|
"returns the top 100 likers for a given monthly period ordered by like_count. It accepts a ‘months_ago’ parameter, defaults to 1 to give results for the last calendar month.",
|
||||||
"name": "Top 50 Quality Users",
|
},
|
||||||
"description": "based on post score calculated using reply count, likes, incoming links, bookmarks, time spent and read count."
|
"quality-users": {
|
||||||
},
|
id: -7,
|
||||||
"user-participation": {
|
name: "Top 50 Quality Users",
|
||||||
"id": -8,
|
description:
|
||||||
"name": "User Participation Statistics",
|
"based on post score calculated using reply count, likes, incoming links, bookmarks, time spent and read count.",
|
||||||
"description": "Detailed statistics for the most active users."
|
},
|
||||||
},
|
"user-participation": {
|
||||||
"largest-uploads": {
|
id: -8,
|
||||||
"id": -9,
|
name: "User Participation Statistics",
|
||||||
"name": "Top 50 Largest Uploads",
|
description: "Detailed statistics for the most active users.",
|
||||||
"description": "sorted by file size."
|
},
|
||||||
},
|
"largest-uploads": {
|
||||||
"inactive-users": {
|
id: -9,
|
||||||
"id": -10,
|
name: "Top 50 Largest Uploads",
|
||||||
"name": "Inactive Users with no posts",
|
description: "sorted by file size.",
|
||||||
"description": "analyze pre-Discourse signups."
|
},
|
||||||
},
|
"inactive-users": {
|
||||||
"active-lurkers": {
|
id: -10,
|
||||||
"id": -11,
|
name: "Inactive Users with no posts",
|
||||||
"name": "Most Active Lurkers",
|
description: "analyze pre-Discourse signups.",
|
||||||
"description": "active users without posts and excessive read times, it accepts a post_read_count parameter that sets the threshold for posts read."
|
},
|
||||||
},
|
"active-lurkers": {
|
||||||
"topic-user-notification-level": {
|
id: -11,
|
||||||
"id": -12,
|
name: "Most Active Lurkers",
|
||||||
"name": "List of topics a user is watching/tracking/muted",
|
description:
|
||||||
"description": "The query requires a ‘notification_level’ parameter. Use 0 for muted, 1 for regular, 2 for tracked and 3 for watched topics."
|
"active users without posts and excessive read times, it accepts a post_read_count parameter that sets the threshold for posts read.",
|
||||||
},
|
},
|
||||||
"assigned-topics-report": {
|
"topic-user-notification-level": {
|
||||||
"id": -13,
|
id: -12,
|
||||||
"name": "List of assigned topics by user",
|
name: "List of topics a user is watching/tracking/muted",
|
||||||
"description": "This report requires the assign plugin, it will find all assigned topics"
|
description:
|
||||||
},
|
"The query requires a ‘notification_level’ parameter. Use 0 for muted, 1 for regular, 2 for tracked and 3 for watched topics.",
|
||||||
"group-members-reply-count": {
|
},
|
||||||
"id": -14,
|
"assigned-topics-report": {
|
||||||
"name": "Group Members Reply Count",
|
id: -13,
|
||||||
"description": "Number of replies by members of a group over a given time period. Requires 'group_name', 'start_date', and 'end_date' parameters. Dates need to be in the form 'yyyy-mm-dd'. Accepts an 'include_pms' parameter."
|
name: "List of assigned topics by user",
|
||||||
},
|
description: "This report requires the assign plugin, it will find all assigned topics",
|
||||||
"total-assigned-topics-report": {
|
},
|
||||||
"id": -15,
|
"group-members-reply-count": {
|
||||||
"name": "Total topics assigned per user",
|
id: -14,
|
||||||
"description": "Count of assigned topis per user linking to assign list"
|
name: "Group Members Reply Count",
|
||||||
},
|
description:
|
||||||
"poll-results": {
|
"Number of replies by members of a group over a given time period. Requires 'group_name', 'start_date', and 'end_date' parameters. Dates need to be in the form 'yyyy-mm-dd'. Accepts an 'include_pms' parameter.",
|
||||||
"id": -16,
|
},
|
||||||
"name": "Poll results report",
|
"total-assigned-topics-report": {
|
||||||
"description": "Details of a poll result, including details about each vote and voter, useful for analyzing results in external software."
|
id: -15,
|
||||||
},
|
name: "Total topics assigned per user",
|
||||||
"top-tags-per-year": {
|
description: "Count of assigned topis per user linking to assign list",
|
||||||
"id": -17,
|
},
|
||||||
"name": "Top tags per year",
|
"poll-results": {
|
||||||
"description": "List the top tags per year."
|
id: -16,
|
||||||
},
|
name: "Poll results report",
|
||||||
"number_of_replies_by_category": {
|
description:
|
||||||
"id": -18,
|
"Details of a poll result, including details about each vote and voter, useful for analyzing results in external software.",
|
||||||
"name": "Number of replies by category",
|
},
|
||||||
"description": "List the number of replies by category."
|
"top-tags-per-year": {
|
||||||
}
|
id: -17,
|
||||||
|
name: "Top tags per year",
|
||||||
|
description: "List the top tags per year.",
|
||||||
|
},
|
||||||
|
number_of_replies_by_category: {
|
||||||
|
id: -18,
|
||||||
|
name: "Number of replies by category",
|
||||||
|
description: "List the number of replies by category.",
|
||||||
|
},
|
||||||
}.with_indifferent_access
|
}.with_indifferent_access
|
||||||
|
|
||||||
queries["most-common-likers"]["sql"] = <<~SQL
|
queries["most-common-likers"]["sql"] = <<~SQL
|
||||||
|
@ -546,8 +554,8 @@ class Queries
|
||||||
ORDER BY p.year DESC, qt DESC
|
ORDER BY p.year DESC, qt DESC
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
# convert query ids from "mostcommonlikers" to "-1", "mostmessages" to "-2" etc.
|
# convert query ids from "mostcommonlikers" to "-1", "mostmessages" to "-2" etc.
|
||||||
queries.transform_keys!.with_index { |key, idx| "-#{idx + 1}" }
|
queries.transform_keys!.with_index { |key, idx| "-#{idx + 1}" }
|
||||||
queries
|
queries
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
# rake data_explorer:list_hidden_queries
|
# rake data_explorer:list_hidden_queries
|
||||||
desc "Shows a list of hidden queries"
|
desc "Shows a list of hidden queries"
|
||||||
task('data_explorer:list_hidden_queries').clear
|
task("data_explorer:list_hidden_queries").clear
|
||||||
task 'data_explorer:list_hidden_queries' => :environment do |t|
|
task "data_explorer:list_hidden_queries" => :environment do |t|
|
||||||
puts "\nHidden Queries\n\n"
|
puts "\nHidden Queries\n\n"
|
||||||
|
|
||||||
hidden_queries = DataExplorer::Query.where(hidden: false)
|
hidden_queries = DataExplorer::Query.where(hidden: false)
|
||||||
|
@ -18,8 +18,8 @@ end
|
||||||
# rake data_explorer[-1]
|
# rake data_explorer[-1]
|
||||||
# rake data_explorer[1,-2,3,-4,5]
|
# rake data_explorer[1,-2,3,-4,5]
|
||||||
desc "Hides one or multiple queries by ID"
|
desc "Hides one or multiple queries by ID"
|
||||||
task('data_explorer').clear
|
task("data_explorer").clear
|
||||||
task 'data_explorer' => :environment do |t, args|
|
task "data_explorer" => :environment do |t, args|
|
||||||
args.extras.each do |arg|
|
args.extras.each do |arg|
|
||||||
id = arg.to_i
|
id = arg.to_i
|
||||||
query = DataExplorer::Query.find_by(id: id)
|
query = DataExplorer::Query.find_by(id: id)
|
||||||
|
@ -37,8 +37,8 @@ end
|
||||||
# rake data_explorer:unhide_query[-1]
|
# rake data_explorer:unhide_query[-1]
|
||||||
# rake data_explorer:unhide_query[1,-2,3,-4,5]
|
# rake data_explorer:unhide_query[1,-2,3,-4,5]
|
||||||
desc "Unhides one or multiple queries by ID"
|
desc "Unhides one or multiple queries by ID"
|
||||||
task('data_explorer:unhide_query').clear
|
task("data_explorer:unhide_query").clear
|
||||||
task 'data_explorer:unhide_query' => :environment do |t, args|
|
task "data_explorer:unhide_query" => :environment do |t, args|
|
||||||
args.extras.each do |arg|
|
args.extras.each do |arg|
|
||||||
id = arg.to_i
|
id = arg.to_i
|
||||||
query = DataExplorer::Query.find_by(id: id)
|
query = DataExplorer::Query.find_by(id: id)
|
||||||
|
@ -56,8 +56,8 @@ end
|
||||||
# rake data_explorer:hard_delete[-1]
|
# rake data_explorer:hard_delete[-1]
|
||||||
# rake data_explorer:hard_delete[1,-2,3,-4,5]
|
# rake data_explorer:hard_delete[1,-2,3,-4,5]
|
||||||
desc "Hard deletes one or multiple queries by ID"
|
desc "Hard deletes one or multiple queries by ID"
|
||||||
task('data_explorer:hard_delete').clear
|
task("data_explorer:hard_delete").clear
|
||||||
task 'data_explorer:hard_delete' => :environment do |t, args|
|
task "data_explorer:hard_delete" => :environment do |t, args|
|
||||||
args.extras.each do |arg|
|
args.extras.each do |arg|
|
||||||
id = arg.to_i
|
id = arg.to_i
|
||||||
query = DataExplorer::Query.find_by(id: id)
|
query = DataExplorer::Query.find_by(id: id)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
desc 'Fix query IDs to match the old ones used in the plugin store (q:id)'
|
desc "Fix query IDs to match the old ones used in the plugin store (q:id)"
|
||||||
|
|
||||||
task('data_explorer:fix_query_ids').clear
|
task("data_explorer:fix_query_ids").clear
|
||||||
task 'data_explorer:fix_query_ids' => :environment do
|
task "data_explorer:fix_query_ids" => :environment do
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
# Only queries with unique title can be fixed
|
# Only queries with unique title can be fixed
|
||||||
movements = DB.query <<~SQL
|
movements = DB.query <<~SQL
|
||||||
|
@ -20,7 +20,8 @@ task 'data_explorer:fix_query_ids' => :environment do
|
||||||
if movements.present?
|
if movements.present?
|
||||||
# If there are new queries, they still may have conflict
|
# If there are new queries, they still may have conflict
|
||||||
# We just want to move their ids to safe space and we will not move them back
|
# We just want to move their ids to safe space and we will not move them back
|
||||||
additional_conflicts = DB.query(<<~SQL, from: movements.map { |m| m.from }, to: movements.map { |m| m.to })
|
additional_conflicts =
|
||||||
|
DB.query(<<~SQL, from: movements.map { |m| m.from }, to: movements.map { |m| m.to })
|
||||||
SELECT id FROM data_explorer_queries
|
SELECT id FROM data_explorer_queries
|
||||||
WHERE id IN (:to)
|
WHERE id IN (:to)
|
||||||
AND id NOT IN (:from)
|
AND id NOT IN (:from)
|
||||||
|
@ -84,7 +85,8 @@ task 'data_explorer:fix_query_ids' => :environment do
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
# insert additional_conflicts to temporary tables
|
# insert additional_conflicts to temporary tables
|
||||||
new_id = DB.query("select greatest(max(id), 1) from tmp_data_explorer_queries").first.greatest + 1
|
new_id =
|
||||||
|
DB.query("select greatest(max(id), 1) from tmp_data_explorer_queries").first.greatest + 1
|
||||||
additional_conflicts.each do |conflict_id|
|
additional_conflicts.each do |conflict_id|
|
||||||
DB.exec <<-SQL
|
DB.exec <<-SQL
|
||||||
INSERT INTO tmp_data_explorer_queries(id, name, description, sql, user_id, last_run_at, hidden, created_at, updated_at)
|
INSERT INTO tmp_data_explorer_queries(id, name, description, sql, user_id, last_run_at, hidden, created_at, updated_at)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
describe DataExplorer do
|
describe DataExplorer do
|
||||||
describe '.run_query' do
|
describe ".run_query" do
|
||||||
fab!(:topic) { Fabricate(:topic) }
|
fab!(:topic) { Fabricate(:topic) }
|
||||||
|
|
||||||
it 'should run a query that includes PG template patterns' do
|
it "should run a query that includes PG template patterns" do
|
||||||
sql = <<~SQL
|
sql = <<~SQL
|
||||||
WITH query AS (
|
WITH query AS (
|
||||||
SELECT TO_CHAR(created_at, 'yyyy:mm:dd') AS date FROM topics
|
SELECT TO_CHAR(created_at, 'yyyy:mm:dd') AS date FROM topics
|
||||||
|
@ -19,7 +19,7 @@ describe DataExplorer do
|
||||||
expect(result[:pg_result][0]["date"]).to eq(topic.created_at.strftime("%Y:%m:%d"))
|
expect(result[:pg_result][0]["date"]).to eq(topic.created_at.strftime("%Y:%m:%d"))
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should run a query containing a question mark in the comment' do
|
it "should run a query containing a question mark in the comment" do
|
||||||
sql = <<~SQL
|
sql = <<~SQL
|
||||||
WITH query AS (
|
WITH query AS (
|
||||||
SELECT id FROM topics -- some SQL ? comment ?
|
SELECT id FROM topics -- some SQL ? comment ?
|
||||||
|
@ -34,7 +34,7 @@ describe DataExplorer do
|
||||||
expect(result[:pg_result][0]["id"]).to eq(topic.id)
|
expect(result[:pg_result][0]["id"]).to eq(topic.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'can run a query with params interpolation' do
|
it "can run a query with params interpolation" do
|
||||||
topic2 = Fabricate(:topic)
|
topic2 = Fabricate(:topic)
|
||||||
|
|
||||||
sql = <<~SQL
|
sql = <<~SQL
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
describe Guardian do
|
describe Guardian do
|
||||||
before { SiteSetting.data_explorer_enabled = true }
|
before { SiteSetting.data_explorer_enabled = true }
|
||||||
|
|
||||||
def make_query(group_ids = [])
|
def make_query(group_ids = [])
|
||||||
query = DataExplorer::Query.create!(name: "Query number #{Fabrication::Sequencer.sequence("query-id", 1)}", sql: "SELECT 1")
|
query =
|
||||||
|
DataExplorer::Query.create!(
|
||||||
|
name: "Query number #{Fabrication::Sequencer.sequence("query-id", 1)}",
|
||||||
|
sql: "SELECT 1",
|
||||||
|
)
|
||||||
|
|
||||||
group_ids.each do |group_id|
|
group_ids.each { |group_id| query.query_groups.create!(group_id: group_id) }
|
||||||
query.query_groups.create!(group_id: group_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
query
|
query
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
describe 'API keys scoped to query#run' do
|
describe "API keys scoped to query#run" do
|
||||||
before do
|
before { SiteSetting.data_explorer_enabled = true }
|
||||||
SiteSetting.data_explorer_enabled = true
|
|
||||||
end
|
|
||||||
|
|
||||||
fab!(:query1) { DataExplorer::Query.create!(name: "Query 1", sql: "SELECT 1 AS query1_res") }
|
fab!(:query1) { DataExplorer::Query.create!(name: "Query 1", sql: "SELECT 1 AS query1_res") }
|
||||||
fab!(:query2) { DataExplorer::Query.create!(name: "Query 2", sql: "SELECT 1 AS query2_res") }
|
fab!(:query2) { DataExplorer::Query.create!(name: "Query 2", sql: "SELECT 1 AS query2_res") }
|
||||||
|
@ -13,11 +11,7 @@ describe 'API keys scoped to query#run' do
|
||||||
|
|
||||||
let(:all_queries_api_key) do
|
let(:all_queries_api_key) do
|
||||||
key = ApiKey.create!
|
key = ApiKey.create!
|
||||||
ApiKeyScope.create!(
|
ApiKeyScope.create!(resource: "data_explorer", action: "run_queries", api_key_id: key.id)
|
||||||
resource: "data_explorer",
|
|
||||||
action: "run_queries",
|
|
||||||
api_key_id: key.id
|
|
||||||
)
|
|
||||||
key
|
key
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -27,73 +21,83 @@ describe 'API keys scoped to query#run' do
|
||||||
resource: "data_explorer",
|
resource: "data_explorer",
|
||||||
action: "run_queries",
|
action: "run_queries",
|
||||||
api_key_id: key.id,
|
api_key_id: key.id,
|
||||||
allowed_parameters: { "id" => [query1.id.to_s] }
|
allowed_parameters: {
|
||||||
|
"id" => [query1.id.to_s],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
key
|
key
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'cannot hit any other endpoints' do
|
it "cannot hit any other endpoints" do
|
||||||
get "/latest.json", headers: {
|
get "/latest.json",
|
||||||
"Api-Key" => all_queries_api_key.key,
|
headers: {
|
||||||
"Api-Username" => admin.username
|
"Api-Key" => all_queries_api_key.key,
|
||||||
}
|
"Api-Username" => admin.username,
|
||||||
|
}
|
||||||
expect(response.status).to eq(403)
|
expect(response.status).to eq(403)
|
||||||
|
|
||||||
get "/latest.json", headers: {
|
get "/latest.json",
|
||||||
"Api-Key" => single_query_api_key.key,
|
headers: {
|
||||||
"Api-Username" => admin.username
|
"Api-Key" => single_query_api_key.key,
|
||||||
}
|
"Api-Username" => admin.username,
|
||||||
|
}
|
||||||
expect(response.status).to eq(403)
|
expect(response.status).to eq(403)
|
||||||
|
|
||||||
get "/u/#{admin.username}.json", headers: {
|
get "/u/#{admin.username}.json",
|
||||||
"Api-Key" => all_queries_api_key.key,
|
headers: {
|
||||||
"Api-Username" => admin.username
|
"Api-Key" => all_queries_api_key.key,
|
||||||
}
|
"Api-Username" => admin.username,
|
||||||
|
}
|
||||||
expect(response.status).to eq(403)
|
expect(response.status).to eq(403)
|
||||||
|
|
||||||
get "/u/#{admin.username}.json", headers: {
|
get "/u/#{admin.username}.json",
|
||||||
"Api-Key" => single_query_api_key.key,
|
headers: {
|
||||||
"Api-Username" => admin.username
|
"Api-Key" => single_query_api_key.key,
|
||||||
}
|
"Api-Username" => admin.username,
|
||||||
|
}
|
||||||
expect(response.status).to eq(403)
|
expect(response.status).to eq(403)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can only run the queries they're allowed to run" do
|
it "can only run the queries they're allowed to run" do
|
||||||
expect {
|
expect {
|
||||||
post "/admin/plugins/explorer/queries/#{query1.id}/run.json", headers: {
|
post "/admin/plugins/explorer/queries/#{query1.id}/run.json",
|
||||||
"Api-Key" => single_query_api_key.key,
|
headers: {
|
||||||
"Api-Username" => admin.username
|
"Api-Key" => single_query_api_key.key,
|
||||||
}
|
"Api-Username" => admin.username,
|
||||||
|
}
|
||||||
}.to change { query1.reload.last_run_at }
|
}.to change { query1.reload.last_run_at }
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response.parsed_body["success"]).to eq(true)
|
expect(response.parsed_body["success"]).to eq(true)
|
||||||
expect(response.parsed_body["columns"]).to eq(["query1_res"])
|
expect(response.parsed_body["columns"]).to eq(["query1_res"])
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
post "/admin/plugins/explorer/queries/#{query2.id}/run.json", headers: {
|
post "/admin/plugins/explorer/queries/#{query2.id}/run.json",
|
||||||
"Api-Key" => single_query_api_key.key,
|
headers: {
|
||||||
"Api-Username" => admin.username
|
"Api-Key" => single_query_api_key.key,
|
||||||
}
|
"Api-Username" => admin.username,
|
||||||
|
}
|
||||||
}.not_to change { query2.reload.last_run_at }
|
}.not_to change { query2.reload.last_run_at }
|
||||||
expect(response.status).to eq(403)
|
expect(response.status).to eq(403)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can run all queries if they're not restricted to any queries" do
|
it "can run all queries if they're not restricted to any queries" do
|
||||||
expect {
|
expect {
|
||||||
post "/admin/plugins/explorer/queries/#{query1.id}/run.json", headers: {
|
post "/admin/plugins/explorer/queries/#{query1.id}/run.json",
|
||||||
"Api-Key" => all_queries_api_key.key,
|
headers: {
|
||||||
"Api-Username" => admin.username
|
"Api-Key" => all_queries_api_key.key,
|
||||||
}
|
"Api-Username" => admin.username,
|
||||||
|
}
|
||||||
}.to change { query1.reload.last_run_at }
|
}.to change { query1.reload.last_run_at }
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response.parsed_body["success"]).to eq(true)
|
expect(response.parsed_body["success"]).to eq(true)
|
||||||
expect(response.parsed_body["columns"]).to eq(["query1_res"])
|
expect(response.parsed_body["columns"]).to eq(["query1_res"])
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
post "/admin/plugins/explorer/queries/#{query2.id}/run.json", headers: {
|
post "/admin/plugins/explorer/queries/#{query2.id}/run.json",
|
||||||
"Api-Key" => all_queries_api_key.key,
|
headers: {
|
||||||
"Api-Username" => admin.username
|
"Api-Key" => all_queries_api_key.key,
|
||||||
}
|
"Api-Username" => admin.username,
|
||||||
|
}
|
||||||
}.to change { query2.reload.last_run_at }
|
}.to change { query2.reload.last_run_at }
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response.parsed_body["success"]).to eq(true)
|
expect(response.parsed_body["success"]).to eq(true)
|
||||||
|
|
|
@ -9,12 +9,60 @@ describe Jobs::DeleteHiddenQueries do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "will correctly destroy old hidden queries" do
|
it "will correctly destroy old hidden queries" do
|
||||||
DataExplorer::Query.create!(id: 1, name: "A", description: "A description for A", sql: "SELECT 1 as value", hidden: false, last_run_at: 2.days.ago, updated_at: 2.days.ago)
|
DataExplorer::Query.create!(
|
||||||
DataExplorer::Query.create!(id: 2, name: "B", description: "A description for B", sql: "SELECT 1 as value", hidden: true, last_run_at: 8.days.ago, updated_at: 8.days.ago)
|
id: 1,
|
||||||
DataExplorer::Query.create!(id: 3, name: "C", description: "A description for C", sql: "SELECT 1 as value", hidden: true, last_run_at: 4.days.ago, updated_at: 4.days.ago)
|
name: "A",
|
||||||
DataExplorer::Query.create!(id: 4, name: "D", description: "A description for D", sql: "SELECT 1 as value", hidden: true, last_run_at: nil, updated_at: 10.days.ago)
|
description: "A description for A",
|
||||||
DataExplorer::Query.create!(id: 5, name: "E", description: "A description for E", sql: "SELECT 1 as value", hidden: true, last_run_at: 5.days.ago, updated_at: 10.days.ago)
|
sql: "SELECT 1 as value",
|
||||||
DataExplorer::Query.create!(id: 6, name: "F", description: "A description for F", sql: "SELECT 1 as value", hidden: true, last_run_at: 10.days.ago, updated_at: 5.days.ago)
|
hidden: false,
|
||||||
|
last_run_at: 2.days.ago,
|
||||||
|
updated_at: 2.days.ago,
|
||||||
|
)
|
||||||
|
DataExplorer::Query.create!(
|
||||||
|
id: 2,
|
||||||
|
name: "B",
|
||||||
|
description: "A description for B",
|
||||||
|
sql: "SELECT 1 as value",
|
||||||
|
hidden: true,
|
||||||
|
last_run_at: 8.days.ago,
|
||||||
|
updated_at: 8.days.ago,
|
||||||
|
)
|
||||||
|
DataExplorer::Query.create!(
|
||||||
|
id: 3,
|
||||||
|
name: "C",
|
||||||
|
description: "A description for C",
|
||||||
|
sql: "SELECT 1 as value",
|
||||||
|
hidden: true,
|
||||||
|
last_run_at: 4.days.ago,
|
||||||
|
updated_at: 4.days.ago,
|
||||||
|
)
|
||||||
|
DataExplorer::Query.create!(
|
||||||
|
id: 4,
|
||||||
|
name: "D",
|
||||||
|
description: "A description for D",
|
||||||
|
sql: "SELECT 1 as value",
|
||||||
|
hidden: true,
|
||||||
|
last_run_at: nil,
|
||||||
|
updated_at: 10.days.ago,
|
||||||
|
)
|
||||||
|
DataExplorer::Query.create!(
|
||||||
|
id: 5,
|
||||||
|
name: "E",
|
||||||
|
description: "A description for E",
|
||||||
|
sql: "SELECT 1 as value",
|
||||||
|
hidden: true,
|
||||||
|
last_run_at: 5.days.ago,
|
||||||
|
updated_at: 10.days.ago,
|
||||||
|
)
|
||||||
|
DataExplorer::Query.create!(
|
||||||
|
id: 6,
|
||||||
|
name: "F",
|
||||||
|
description: "A description for F",
|
||||||
|
sql: "SELECT 1 as value",
|
||||||
|
hidden: true,
|
||||||
|
last_run_at: 10.days.ago,
|
||||||
|
updated_at: 5.days.ago,
|
||||||
|
)
|
||||||
|
|
||||||
subject.execute(nil)
|
subject.execute(nil)
|
||||||
expect(DataExplorer::Query.all.length).to eq(4)
|
expect(DataExplorer::Query.all.length).to eq(4)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
describe DataExplorerQueryGroupBookmarkable do
|
describe DataExplorerQueryGroupBookmarkable do
|
||||||
fab!(:admin_user) { Fabricate(:admin) }
|
fab!(:admin_user) { Fabricate(:admin) }
|
||||||
|
@ -10,14 +10,24 @@ describe DataExplorerQueryGroupBookmarkable do
|
||||||
fab!(:group1) { Fabricate(:group) }
|
fab!(:group1) { Fabricate(:group) }
|
||||||
fab!(:group2) { Fabricate(:group) }
|
fab!(:group2) { Fabricate(:group) }
|
||||||
fab!(:group3) { Fabricate(:group) }
|
fab!(:group3) { Fabricate(:group) }
|
||||||
fab!(:query1) { Fabricate(:query, name: "My First Query",
|
fab!(:query1) do
|
||||||
description: "This is the description of my 1st query.",
|
Fabricate(
|
||||||
sql: "Not really important",
|
:query,
|
||||||
user: admin_user) }
|
name: "My First Query",
|
||||||
fab!(:query2) { Fabricate(:query, name: "My Second Query",
|
description: "This is the description of my 1st query.",
|
||||||
description: "This is my 2nd query's description.",
|
sql: "Not really important",
|
||||||
sql: "Not really important",
|
user: admin_user,
|
||||||
user: admin_user) }
|
)
|
||||||
|
end
|
||||||
|
fab!(:query2) do
|
||||||
|
Fabricate(
|
||||||
|
:query,
|
||||||
|
name: "My Second Query",
|
||||||
|
description: "This is my 2nd query's description.",
|
||||||
|
sql: "Not really important",
|
||||||
|
user: admin_user,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
SiteSetting.data_explorer_enabled = true
|
SiteSetting.data_explorer_enabled = true
|
||||||
|
@ -41,28 +51,40 @@ describe DataExplorerQueryGroupBookmarkable do
|
||||||
let!(:group_user3) { Fabricate(:group_user, user: user, group: group3) }
|
let!(:group_user3) { Fabricate(:group_user, user: user, group: group3) }
|
||||||
|
|
||||||
# User bookmarked the same Query 1 twice, from different Groups (0 and 1)
|
# User bookmarked the same Query 1 twice, from different Groups (0 and 1)
|
||||||
let!(:bookmark1) { Fabricate(:bookmark, user: user,
|
let!(:bookmark1) do
|
||||||
bookmarkable: query_group1,
|
Fabricate(:bookmark, user: user, bookmarkable: query_group1, name: "something i gotta do")
|
||||||
name: "something i gotta do") }
|
end
|
||||||
let!(:bookmark2) { Fabricate(:bookmark, user: user,
|
let!(:bookmark2) do
|
||||||
bookmarkable: query_group2,
|
Fabricate(
|
||||||
name: "something else i have to do") }
|
:bookmark,
|
||||||
|
user: user,
|
||||||
|
bookmarkable: query_group2,
|
||||||
|
name: "something else i have to do",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
# User also bookmarked Query 2 from Group 1.
|
# User also bookmarked Query 2 from Group 1.
|
||||||
let!(:bookmark3) { Fabricate(:bookmark, user: user,
|
let!(:bookmark3) do
|
||||||
bookmarkable: query_group3,
|
Fabricate(
|
||||||
name: "this is the other query I needed.") }
|
:bookmark,
|
||||||
|
user: user,
|
||||||
|
bookmarkable: query_group3,
|
||||||
|
name: "this is the other query I needed.",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
# User previously bookmarked Query 1 from Group 2, of which she is no longer a member.
|
# User previously bookmarked Query 1 from Group 2, of which she is no longer a member.
|
||||||
let!(:bookmark4) { Fabricate(:bookmark, user: user,
|
let!(:bookmark4) do
|
||||||
bookmarkable: query_group4,
|
Fabricate(:bookmark, user: user, bookmarkable: query_group4, name: "something i gotta do also")
|
||||||
name: "something i gotta do also") }
|
end
|
||||||
|
|
||||||
subject { RegisteredBookmarkable.new(DataExplorerQueryGroupBookmarkable) }
|
subject { RegisteredBookmarkable.new(DataExplorerQueryGroupBookmarkable) }
|
||||||
|
|
||||||
describe "#perform_list_query" do
|
describe "#perform_list_query" do
|
||||||
it "returns all the user's bookmarks" do
|
it "returns all the user's bookmarks" do
|
||||||
expect(subject.perform_list_query(user, guardian).map(&:id)).to match_array([bookmark1.id, bookmark2.id, bookmark3.id])
|
expect(subject.perform_list_query(user, guardian).map(&:id)).to match_array(
|
||||||
|
[bookmark1.id, bookmark2.id, bookmark3.id],
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not return bookmarks made from groups that the user is no longer a member of" do
|
it "does not return bookmarks made from groups that the user is no longer a member of" do
|
||||||
|
@ -75,24 +97,32 @@ describe DataExplorerQueryGroupBookmarkable do
|
||||||
# bookmarks is now empty, because user is not a member of any Groups with permission to see the query
|
# bookmarks is now empty, because user is not a member of any Groups with permission to see the query
|
||||||
expect(subject.perform_list_query(user, guardian)).to be_empty
|
expect(subject.perform_list_query(user, guardian)).to be_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#perform_search_query" do
|
describe "#perform_search_query" do
|
||||||
before do
|
before { SearchIndexer.enable }
|
||||||
SearchIndexer.enable
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns bookmarks that match by name" do
|
it "returns bookmarks that match by name" do
|
||||||
ts_query = Search.ts_query(term: "gotta", ts_config: "simple")
|
ts_query = Search.ts_query(term: "gotta", ts_config: "simple")
|
||||||
expect(subject.perform_search_query(subject.perform_list_query(user, guardian), "%gotta%", ts_query).map(&:id)).to match_array([bookmark1.id])
|
expect(
|
||||||
|
subject.perform_search_query(
|
||||||
|
subject.perform_list_query(user, guardian),
|
||||||
|
"%gotta%",
|
||||||
|
ts_query,
|
||||||
|
).map(&:id),
|
||||||
|
).to match_array([bookmark1.id])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns bookmarks that match by Query name" do
|
it "returns bookmarks that match by Query name" do
|
||||||
ts_query = Search.ts_query(term: "First", ts_config: "simple")
|
ts_query = Search.ts_query(term: "First", ts_config: "simple")
|
||||||
expect(subject.perform_search_query(subject.perform_list_query(user, guardian), "%First%", ts_query).map(&:id)).to match_array([bookmark1.id, bookmark2.id])
|
expect(
|
||||||
|
subject.perform_search_query(
|
||||||
|
subject.perform_list_query(user, guardian),
|
||||||
|
"%First%",
|
||||||
|
ts_query,
|
||||||
|
).map(&:id),
|
||||||
|
).to match_array([bookmark1.id, bookmark2.id])
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#can_send_reminder?" do
|
describe "#can_send_reminder?" do
|
||||||
|
@ -106,17 +136,20 @@ describe DataExplorerQueryGroupBookmarkable do
|
||||||
|
|
||||||
describe "#reminder_handler" do
|
describe "#reminder_handler" do
|
||||||
it "creates a notification for the user with the correct details" do
|
it "creates a notification for the user with the correct details" do
|
||||||
expect { subject.send_reminder_notification(bookmark1) }.to change { Notification.count }.by(1)
|
expect { subject.send_reminder_notification(bookmark1) }.to change { Notification.count }.by(
|
||||||
|
1,
|
||||||
|
)
|
||||||
notif = user.notifications.last
|
notif = user.notifications.last
|
||||||
expect(notif.notification_type).to eq(Notification.types[:bookmark_reminder])
|
expect(notif.notification_type).to eq(Notification.types[:bookmark_reminder])
|
||||||
expect(notif.data).to eq(
|
expect(notif.data).to eq(
|
||||||
{
|
{
|
||||||
title: bookmark1.bookmarkable.query.name,
|
title: bookmark1.bookmarkable.query.name,
|
||||||
bookmarkable_url: "/g/#{bookmark1.bookmarkable.group.name}/reports/#{bookmark1.bookmarkable.query.id}",
|
bookmarkable_url:
|
||||||
|
"/g/#{bookmark1.bookmarkable.group.name}/reports/#{bookmark1.bookmarkable.query.id}",
|
||||||
display_username: bookmark1.user.username,
|
display_username: bookmark1.user.username,
|
||||||
bookmark_name: bookmark1.name,
|
bookmark_name: bookmark1.name,
|
||||||
bookmark_id: bookmark1.id
|
bookmark_id: bookmark1.id,
|
||||||
}.to_json
|
}.to_json,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -144,6 +177,5 @@ describe DataExplorerQueryGroupBookmarkable do
|
||||||
|
|
||||||
expect(subject.can_see?(guardian, bookmark4)).to eq(true)
|
expect(subject.can_see?(guardian, bookmark4)).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
describe "Data explorer group serializer additions" do
|
describe "Data explorer group serializer additions" do
|
||||||
fab!(:group_user) { Fabricate(:user) }
|
fab!(:group_user) { Fabricate(:user) }
|
||||||
|
|
|
@ -1,37 +1,35 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
describe DataExplorer::QueryController do
|
describe DataExplorer::QueryController do
|
||||||
def response_json
|
def response_json
|
||||||
response.parsed_body
|
response.parsed_body
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before { SiteSetting.data_explorer_enabled = true }
|
||||||
SiteSetting.data_explorer_enabled = true
|
|
||||||
end
|
|
||||||
|
|
||||||
def make_query(sql, opts = {}, group_ids = [])
|
def make_query(sql, opts = {}, group_ids = [])
|
||||||
query = DataExplorer::Query.create!(name: opts[:name] || "Query number", description: "A description for query number", sql: sql, hidden: opts[:hidden] || false)
|
query =
|
||||||
group_ids.each do |group_id|
|
DataExplorer::Query.create!(
|
||||||
query.query_groups.create!(group_id: group_id)
|
name: opts[:name] || "Query number",
|
||||||
end
|
description: "A description for query number",
|
||||||
|
sql: sql,
|
||||||
|
hidden: opts[:hidden] || false,
|
||||||
|
)
|
||||||
|
group_ids.each { |group_id| query.query_groups.create!(group_id: group_id) }
|
||||||
query
|
query
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "Admin" do
|
describe "Admin" do
|
||||||
fab!(:admin) { Fabricate(:admin) }
|
fab!(:admin) { Fabricate(:admin) }
|
||||||
|
|
||||||
before do
|
before { sign_in(admin) }
|
||||||
sign_in(admin)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "when disabled" do
|
describe "when disabled" do
|
||||||
before do
|
before { SiteSetting.data_explorer_enabled = false }
|
||||||
SiteSetting.data_explorer_enabled = false
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'denies every request' do
|
it "denies every request" do
|
||||||
get "/admin/plugins/explorer/queries.json"
|
get "/admin/plugins/explorer/queries.json"
|
||||||
expect(response.status).to eq(404)
|
expect(response.status).to eq(404)
|
||||||
|
|
||||||
|
@ -41,9 +39,7 @@ describe DataExplorer::QueryController do
|
||||||
get "/admin/plugins/explorer/queries/3.json"
|
get "/admin/plugins/explorer/queries/3.json"
|
||||||
expect(response.status).to eq(404)
|
expect(response.status).to eq(404)
|
||||||
|
|
||||||
post "/admin/plugins/explorer/queries.json", params: {
|
post "/admin/plugins/explorer/queries.json", params: { id: 3 }
|
||||||
id: 3
|
|
||||||
}
|
|
||||||
expect(response.status).to eq(404)
|
expect(response.status).to eq(404)
|
||||||
|
|
||||||
post "/admin/plugins/explorer/queries/3/run.json"
|
post "/admin/plugins/explorer/queries/3/run.json"
|
||||||
|
@ -62,28 +58,28 @@ describe DataExplorer::QueryController do
|
||||||
DataExplorer::Query.destroy_all
|
DataExplorer::Query.destroy_all
|
||||||
get "/admin/plugins/explorer/queries.json"
|
get "/admin/plugins/explorer/queries.json"
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response_json['queries'].count).to eq(Queries.default.count)
|
expect(response_json["queries"].count).to eq(Queries.default.count)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "shows all available queries in alphabetical order" do
|
it "shows all available queries in alphabetical order" do
|
||||||
DataExplorer::Query.destroy_all
|
DataExplorer::Query.destroy_all
|
||||||
make_query('SELECT 1 as value', name: 'B')
|
make_query("SELECT 1 as value", name: "B")
|
||||||
make_query('SELECT 1 as value', name: 'A')
|
make_query("SELECT 1 as value", name: "A")
|
||||||
get "/admin/plugins/explorer/queries.json"
|
get "/admin/plugins/explorer/queries.json"
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response_json['queries'].length).to eq(Queries.default.count + 2)
|
expect(response_json["queries"].length).to eq(Queries.default.count + 2)
|
||||||
expect(response_json['queries'][0]['name']).to eq('A')
|
expect(response_json["queries"][0]["name"]).to eq("A")
|
||||||
expect(response_json['queries'][1]['name']).to eq('B')
|
expect(response_json["queries"][1]["name"]).to eq("B")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't show hidden/deleted queries" do
|
it "doesn't show hidden/deleted queries" do
|
||||||
DataExplorer::Query.destroy_all
|
DataExplorer::Query.destroy_all
|
||||||
make_query('SELECT 1 as value', name: 'A', hidden: false)
|
make_query("SELECT 1 as value", name: "A", hidden: false)
|
||||||
make_query('SELECT 1 as value', name: 'B', hidden: true)
|
make_query("SELECT 1 as value", name: "B", hidden: true)
|
||||||
make_query('SELECT 1 as value', name: 'C', hidden: true)
|
make_query("SELECT 1 as value", name: "C", hidden: true)
|
||||||
get "/admin/plugins/explorer/queries.json"
|
get "/admin/plugins/explorer/queries.json"
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response_json['queries'].length).to eq(Queries.default.count + 1)
|
expect(response_json["queries"].length).to eq(Queries.default.count + 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -93,29 +89,32 @@ describe DataExplorer::QueryController do
|
||||||
|
|
||||||
it "allows group to access system query" do
|
it "allows group to access system query" do
|
||||||
query = DataExplorer::Query.find(-4)
|
query = DataExplorer::Query.find(-4)
|
||||||
put "/admin/plugins/explorer/queries/#{query.id}.json", params: {
|
put "/admin/plugins/explorer/queries/#{query.id}.json",
|
||||||
"query" => {
|
params: {
|
||||||
"name" => query.name,
|
"query" => {
|
||||||
"description" => query.description,
|
"name" => query.name,
|
||||||
"sql" => query.sql,
|
"description" => query.description,
|
||||||
"user_id" => query.user_id,
|
"sql" => query.sql,
|
||||||
"created_at" => query.created_at,
|
"user_id" => query.user_id,
|
||||||
"group_ids" => [group2.id],
|
"created_at" => query.created_at,
|
||||||
"last_run_at" => query.last_run_at
|
"group_ids" => [group2.id],
|
||||||
},
|
"last_run_at" => query.last_run_at,
|
||||||
"id" => query.id }
|
},
|
||||||
|
"id" => query.id,
|
||||||
|
}
|
||||||
|
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns a proper json error for invalid updates" do
|
it "returns a proper json error for invalid updates" do
|
||||||
|
|
||||||
query = DataExplorer::Query.find(-4)
|
query = DataExplorer::Query.find(-4)
|
||||||
put "/admin/plugins/explorer/queries/#{query.id}", params: {
|
put "/admin/plugins/explorer/queries/#{query.id}",
|
||||||
"query" => {
|
params: {
|
||||||
"name" => "",
|
"query" => {
|
||||||
},
|
"name" => "",
|
||||||
"id" => query.id }
|
},
|
||||||
|
"id" => query.id,
|
||||||
|
}
|
||||||
|
|
||||||
expect(response.status).to eq(422)
|
expect(response.status).to eq(422)
|
||||||
expect(response.parsed_body["errors"]).to eq(["Name can't be blank"])
|
expect(response.parsed_body["errors"]).to eq(["Name can't be blank"])
|
||||||
|
@ -129,13 +128,13 @@ describe DataExplorer::QueryController do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can run queries" do
|
it "can run queries" do
|
||||||
query = make_query('SELECT 23 as my_value')
|
query = make_query("SELECT 23 as my_value")
|
||||||
run_query query.id
|
run_query query.id
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response_json['success']).to eq(true)
|
expect(response_json["success"]).to eq(true)
|
||||||
expect(response_json['errors']).to eq([])
|
expect(response_json["errors"]).to eq([])
|
||||||
expect(response_json['columns']).to eq(['my_value'])
|
expect(response_json["columns"]).to eq(["my_value"])
|
||||||
expect(response_json['rows']).to eq([[23]])
|
expect(response_json["rows"]).to eq([[23]])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can process parameters" do
|
it "can process parameters" do
|
||||||
|
@ -147,24 +146,24 @@ describe DataExplorer::QueryController do
|
||||||
|
|
||||||
run_query query.id, foo: 23
|
run_query query.id, foo: 23
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response_json['errors']).to eq([])
|
expect(response_json["errors"]).to eq([])
|
||||||
expect(response_json['success']).to eq(true)
|
expect(response_json["success"]).to eq(true)
|
||||||
expect(response_json['columns']).to eq(['my_value'])
|
expect(response_json["columns"]).to eq(["my_value"])
|
||||||
expect(response_json['rows']).to eq([[23]])
|
expect(response_json["rows"]).to eq([[23]])
|
||||||
|
|
||||||
run_query query.id
|
run_query query.id
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response_json['errors']).to eq([])
|
expect(response_json["errors"]).to eq([])
|
||||||
expect(response_json['success']).to eq(true)
|
expect(response_json["success"]).to eq(true)
|
||||||
expect(response_json['columns']).to eq(['my_value'])
|
expect(response_json["columns"]).to eq(["my_value"])
|
||||||
expect(response_json['rows']).to eq([[34]])
|
expect(response_json["rows"]).to eq([[34]])
|
||||||
|
|
||||||
# 2.3 is not an integer
|
# 2.3 is not an integer
|
||||||
run_query query.id, foo: '2.3'
|
run_query query.id, foo: "2.3"
|
||||||
expect(response.status).to eq(422)
|
expect(response.status).to eq(422)
|
||||||
expect(response_json['errors']).to_not eq([])
|
expect(response_json["errors"]).to_not eq([])
|
||||||
expect(response_json['success']).to eq(false)
|
expect(response_json["success"]).to eq(false)
|
||||||
expect(response_json['errors'].first).to match(/ValidationError/)
|
expect(response_json["errors"].first).to match(/ValidationError/)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't allow you to modify the database #1" do
|
it "doesn't allow you to modify the database #1" do
|
||||||
|
@ -184,9 +183,9 @@ describe DataExplorer::QueryController do
|
||||||
# This test should fail on the below check.
|
# This test should fail on the below check.
|
||||||
expect(p.cooked).to_not match(/winner/)
|
expect(p.cooked).to_not match(/winner/)
|
||||||
expect(response.status).to eq(422)
|
expect(response.status).to eq(422)
|
||||||
expect(response_json['errors']).to_not eq([])
|
expect(response_json["errors"]).to_not eq([])
|
||||||
expect(response_json['success']).to eq(false)
|
expect(response_json["success"]).to eq(false)
|
||||||
expect(response_json['errors'].first).to match(/read-only transaction/)
|
expect(response_json["errors"].first).to match(/read-only transaction/)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't allow you to modify the database #2" do
|
it "doesn't allow you to modify the database #2" do
|
||||||
|
@ -221,9 +220,9 @@ describe DataExplorer::QueryController do
|
||||||
# Afterwards, this test should fail on the below check.
|
# Afterwards, this test should fail on the below check.
|
||||||
expect(p.cooked).to_not match(/winner/)
|
expect(p.cooked).to_not match(/winner/)
|
||||||
expect(response.status).to eq(422)
|
expect(response.status).to eq(422)
|
||||||
expect(response_json['errors']).to_not eq([])
|
expect(response_json["errors"]).to_not eq([])
|
||||||
expect(response_json['success']).to eq(false)
|
expect(response_json["success"]).to eq(false)
|
||||||
expect(response_json['errors'].first).to match(/semicolon/)
|
expect(response_json["errors"].first).to match(/semicolon/)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't allow you to lock rows" do
|
it "doesn't allow you to lock rows" do
|
||||||
|
@ -233,9 +232,9 @@ describe DataExplorer::QueryController do
|
||||||
|
|
||||||
run_query query.id
|
run_query query.id
|
||||||
expect(response.status).to eq(422)
|
expect(response.status).to eq(422)
|
||||||
expect(response_json['errors']).to_not eq([])
|
expect(response_json["errors"]).to_not eq([])
|
||||||
expect(response_json['success']).to eq(false)
|
expect(response_json["success"]).to eq(false)
|
||||||
expect(response_json['errors'].first).to match(/read-only transaction/)
|
expect(response_json["errors"].first).to match(/read-only transaction/)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't allow you to create a table" do
|
it "doesn't allow you to create a table" do
|
||||||
|
@ -245,9 +244,9 @@ describe DataExplorer::QueryController do
|
||||||
|
|
||||||
run_query query.id
|
run_query query.id
|
||||||
expect(response.status).to eq(422)
|
expect(response.status).to eq(422)
|
||||||
expect(response_json['errors']).to_not eq([])
|
expect(response_json["errors"]).to_not eq([])
|
||||||
expect(response_json['success']).to eq(false)
|
expect(response_json["success"]).to eq(false)
|
||||||
expect(response_json['errors'].first).to match(/read-only transaction|syntax error/)
|
expect(response_json["errors"].first).to match(/read-only transaction|syntax error/)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't allow you to break the transaction" do
|
it "doesn't allow you to break the transaction" do
|
||||||
|
@ -257,9 +256,9 @@ describe DataExplorer::QueryController do
|
||||||
|
|
||||||
run_query query.id
|
run_query query.id
|
||||||
expect(response.status).to eq(422)
|
expect(response.status).to eq(422)
|
||||||
expect(response_json['errors']).to_not eq([])
|
expect(response_json["errors"]).to_not eq([])
|
||||||
expect(response_json['success']).to eq(false)
|
expect(response_json["success"]).to eq(false)
|
||||||
expect(response_json['errors'].first).to match(/syntax error/)
|
expect(response_json["errors"].first).to match(/syntax error/)
|
||||||
|
|
||||||
query.sql = <<~SQL
|
query.sql = <<~SQL
|
||||||
)
|
)
|
||||||
|
@ -267,9 +266,9 @@ describe DataExplorer::QueryController do
|
||||||
|
|
||||||
run_query query.id
|
run_query query.id
|
||||||
expect(response.status).to eq(422)
|
expect(response.status).to eq(422)
|
||||||
expect(response_json['errors']).to_not eq([])
|
expect(response_json["errors"]).to_not eq([])
|
||||||
expect(response_json['success']).to eq(false)
|
expect(response_json["success"]).to eq(false)
|
||||||
expect(response_json['errors'].first).to match(/syntax error/)
|
expect(response_json["errors"].first).to match(/syntax error/)
|
||||||
|
|
||||||
query.sql = <<~SQL
|
query.sql = <<~SQL
|
||||||
RELEASE SAVEPOINT active_record_1
|
RELEASE SAVEPOINT active_record_1
|
||||||
|
@ -277,13 +276,13 @@ describe DataExplorer::QueryController do
|
||||||
|
|
||||||
run_query query.id
|
run_query query.id
|
||||||
expect(response.status).to eq(422)
|
expect(response.status).to eq(422)
|
||||||
expect(response_json['errors']).to_not eq([])
|
expect(response_json["errors"]).to_not eq([])
|
||||||
expect(response_json['success']).to eq(false)
|
expect(response_json["success"]).to eq(false)
|
||||||
expect(response_json['errors'].first).to match(/syntax error/)
|
expect(response_json["errors"].first).to match(/syntax error/)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can export data in CSV format" do
|
it "can export data in CSV format" do
|
||||||
query = make_query('SELECT 23 as my_value')
|
query = make_query("SELECT 23 as my_value")
|
||||||
post "/admin/plugins/explorer/queries/#{query.id}/run.json", params: { download: 1 }
|
post "/admin/plugins/explorer/queries/#{query.id}/run.json", params: { download: 1 }
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
end
|
end
|
||||||
|
@ -302,13 +301,13 @@ describe DataExplorer::QueryController do
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
run_query query.id
|
run_query query.id
|
||||||
expect(response_json['rows'].count).to eq(2)
|
expect(response_json["rows"].count).to eq(2)
|
||||||
|
|
||||||
post "/admin/plugins/explorer/queries/#{query.id}/run.json", params: { limit: 1 }
|
post "/admin/plugins/explorer/queries/#{query.id}/run.json", params: { limit: 1 }
|
||||||
expect(response_json['rows'].count).to eq(1)
|
expect(response_json["rows"].count).to eq(1)
|
||||||
|
|
||||||
post "/admin/plugins/explorer/queries/#{query.id}/run.json", params: { limit: "ALL" }
|
post "/admin/plugins/explorer/queries/#{query.id}/run.json", params: { limit: "ALL" }
|
||||||
expect(response_json['rows'].count).to eq(3)
|
expect(response_json["rows"].count).to eq(3)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should limit the results in CSV download" do
|
it "should limit the results in CSV download" do
|
||||||
|
@ -324,11 +323,19 @@ describe DataExplorer::QueryController do
|
||||||
post "/admin/plugins/explorer/queries/#{query.id}/run.csv", params: { download: 1 }
|
post "/admin/plugins/explorer/queries/#{query.id}/run.csv", params: { download: 1 }
|
||||||
expect(response.body.split("\n").count).to eq(3)
|
expect(response.body.split("\n").count).to eq(3)
|
||||||
|
|
||||||
post "/admin/plugins/explorer/queries/#{query.id}/run.csv", params: { download: 1, limit: 1 }
|
post "/admin/plugins/explorer/queries/#{query.id}/run.csv",
|
||||||
|
params: {
|
||||||
|
download: 1,
|
||||||
|
limit: 1,
|
||||||
|
}
|
||||||
expect(response.body.split("\n").count).to eq(2)
|
expect(response.body.split("\n").count).to eq(2)
|
||||||
|
|
||||||
# The value `ALL` is not supported in csv exports.
|
# The value `ALL` is not supported in csv exports.
|
||||||
post "/admin/plugins/explorer/queries/#{query.id}/run.csv", params: { download: 1, limit: "ALL" }
|
post "/admin/plugins/explorer/queries/#{query.id}/run.csv",
|
||||||
|
params: {
|
||||||
|
download: 1,
|
||||||
|
limit: "ALL",
|
||||||
|
}
|
||||||
expect(response.body.split("\n").count).to eq(1)
|
expect(response.body.split("\n").count).to eq(1)
|
||||||
ensure
|
ensure
|
||||||
DataExplorer.send(:remove_const, "QUERY_RESULT_MAX_LIMIT")
|
DataExplorer.send(:remove_const, "QUERY_RESULT_MAX_LIMIT")
|
||||||
|
@ -343,16 +350,12 @@ describe DataExplorer::QueryController do
|
||||||
fab!(:user) { Fabricate(:user) }
|
fab!(:user) { Fabricate(:user) }
|
||||||
fab!(:group) { Fabricate(:group, users: [user]) }
|
fab!(:group) { Fabricate(:group, users: [user]) }
|
||||||
|
|
||||||
before do
|
before { sign_in(user) }
|
||||||
sign_in(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "when disabled" do
|
describe "when disabled" do
|
||||||
before do
|
before { SiteSetting.data_explorer_enabled = false }
|
||||||
SiteSetting.data_explorer_enabled = false
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'denies every request' do
|
it "denies every request" do
|
||||||
get "/g/1/reports.json"
|
get "/g/1/reports.json"
|
||||||
expect(response.status).to eq(404)
|
expect(response.status).to eq(404)
|
||||||
|
|
||||||
|
@ -365,7 +368,7 @@ describe DataExplorer::QueryController do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "cannot access admin endpoints" do
|
it "cannot access admin endpoints" do
|
||||||
query = make_query('SELECT 1 as value')
|
query = make_query("SELECT 1 as value")
|
||||||
post "/admin/plugins/explorer/queries/#{query.id}/run.json"
|
post "/admin/plugins/explorer/queries/#{query.id}/run.json"
|
||||||
expect(response.status).to eq(403)
|
expect(response.status).to eq(403)
|
||||||
end
|
end
|
||||||
|
@ -373,12 +376,12 @@ describe DataExplorer::QueryController do
|
||||||
describe "#group_reports_index" do
|
describe "#group_reports_index" do
|
||||||
it "only returns queries that the group has access to" do
|
it "only returns queries that the group has access to" do
|
||||||
group.add(user)
|
group.add(user)
|
||||||
make_query('SELECT 1 as value', { name: 'A' }, ["#{group.id}"])
|
make_query("SELECT 1 as value", { name: "A" }, ["#{group.id}"])
|
||||||
|
|
||||||
get "/g/#{group.name}/reports.json"
|
get "/g/#{group.name}/reports.json"
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response_json['queries'].length).to eq(1)
|
expect(response_json["queries"].length).to eq(1)
|
||||||
expect(response_json['queries'][0]['name']).to eq('A')
|
expect(response_json["queries"][0]["name"]).to eq("A")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns a 404 when the user should not have access to the query " do
|
it "returns a 404 when the user should not have access to the query " do
|
||||||
|
@ -398,19 +401,19 @@ describe DataExplorer::QueryController do
|
||||||
|
|
||||||
it "does not return hidden queries" do
|
it "does not return hidden queries" do
|
||||||
group.add(user)
|
group.add(user)
|
||||||
make_query('SELECT 1 as value', { name: 'A', hidden: true }, ["#{group.id}"])
|
make_query("SELECT 1 as value", { name: "A", hidden: true }, ["#{group.id}"])
|
||||||
make_query('SELECT 1 as value', { name: 'B' }, ["#{group.id}"])
|
make_query("SELECT 1 as value", { name: "B" }, ["#{group.id}"])
|
||||||
|
|
||||||
get "/g/#{group.name}/reports.json"
|
get "/g/#{group.name}/reports.json"
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response_json['queries'].length).to eq(1)
|
expect(response_json["queries"].length).to eq(1)
|
||||||
expect(response_json['queries'][0]['name']).to eq('B')
|
expect(response_json["queries"][0]["name"]).to eq("B")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#group_reports_run" do
|
describe "#group_reports_run" do
|
||||||
it "runs the query" do
|
it "runs the query" do
|
||||||
query = make_query('SELECT 1828 as value', { name: 'B' }, ["#{group.id}"])
|
query = make_query("SELECT 1828 as value", { name: "B" }, ["#{group.id}"])
|
||||||
|
|
||||||
post "/g/#{group.name}/reports/#{query.id}/run.json"
|
post "/g/#{group.name}/reports/#{query.id}/run.json"
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
|
@ -421,7 +424,7 @@ describe DataExplorer::QueryController do
|
||||||
|
|
||||||
it "returns a 404 when the user should not have access to the query " do
|
it "returns a 404 when the user should not have access to the query " do
|
||||||
group.add(user)
|
group.add(user)
|
||||||
query = make_query('SELECT 1 as value', {}, [])
|
query = make_query("SELECT 1 as value", {}, [])
|
||||||
|
|
||||||
post "/g/#{group.name}/reports/#{query.id}/run.json"
|
post "/g/#{group.name}/reports/#{query.id}/run.json"
|
||||||
expect(response.status).to eq(404)
|
expect(response.status).to eq(404)
|
||||||
|
@ -429,7 +432,7 @@ describe DataExplorer::QueryController do
|
||||||
|
|
||||||
it "return a 200 when the user has access the the query" do
|
it "return a 200 when the user has access the the query" do
|
||||||
group.add(user)
|
group.add(user)
|
||||||
query = make_query('SELECT 1 as value', {}, [group.id.to_s])
|
query = make_query("SELECT 1 as value", {}, [group.id.to_s])
|
||||||
|
|
||||||
post "/g/#{group.name}/reports/#{query.id}/run.json"
|
post "/g/#{group.name}/reports/#{query.id}/run.json"
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
|
@ -437,7 +440,7 @@ describe DataExplorer::QueryController do
|
||||||
|
|
||||||
it "return a 404 when the query is hidden" do
|
it "return a 404 when the query is hidden" do
|
||||||
group.add(user)
|
group.add(user)
|
||||||
query = make_query('SELECT 1 as value', { hidden: true }, [group.id.to_s])
|
query = make_query("SELECT 1 as value", { hidden: true }, [group.id.to_s])
|
||||||
|
|
||||||
post "/g/#{group.name}/reports/#{query.id}/run.json"
|
post "/g/#{group.name}/reports/#{query.id}/run.json"
|
||||||
expect(response.status).to eq(404)
|
expect(response.status).to eq(404)
|
||||||
|
@ -446,21 +449,21 @@ describe DataExplorer::QueryController do
|
||||||
|
|
||||||
describe "#group_reports_show" do
|
describe "#group_reports_show" do
|
||||||
it "returns a 404 when the user should not have access to the query " do
|
it "returns a 404 when the user should not have access to the query " do
|
||||||
query = make_query('SELECT 1 as value', {}, [])
|
query = make_query("SELECT 1 as value", {}, [])
|
||||||
|
|
||||||
get "/g/#{group.name}/reports/#{query.id}.json"
|
get "/g/#{group.name}/reports/#{query.id}.json"
|
||||||
expect(response.status).to eq(404)
|
expect(response.status).to eq(404)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "return a 200 when the user has access the the query" do
|
it "return a 200 when the user has access the the query" do
|
||||||
query = make_query('SELECT 1 as value', {}, [group.id.to_s])
|
query = make_query("SELECT 1 as value", {}, [group.id.to_s])
|
||||||
|
|
||||||
get "/g/#{group.name}/reports/#{query.id}.json"
|
get "/g/#{group.name}/reports/#{query.id}.json"
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "return a 404 when the query is hidden" do
|
it "return a 404 when the query is hidden" do
|
||||||
query = make_query('SELECT 1 as value', { hidden: true }, [group.id.to_s])
|
query = make_query("SELECT 1 as value", { hidden: true }, [group.id.to_s])
|
||||||
|
|
||||||
get "/g/#{group.name}/reports/#{query.id}.json"
|
get "/g/#{group.name}/reports/#{query.id}.json"
|
||||||
expect(response.status).to eq(404)
|
expect(response.status).to eq(404)
|
||||||
|
|
|
@ -1,18 +1,23 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
describe 'Data Explorer rake tasks' do
|
describe "Data Explorer rake tasks" do
|
||||||
before do
|
before do
|
||||||
Rake::Task.clear
|
Rake::Task.clear
|
||||||
Discourse::Application.load_tasks
|
Discourse::Application.load_tasks
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_query(sql, opts = {}, group_ids = [])
|
def make_query(sql, opts = {}, group_ids = [])
|
||||||
query = DataExplorer::Query.create!(id: opts[:id], name: opts[:name] || "Query number", description: "A description for query number", sql: sql, hidden: opts[:hidden] || false)
|
query =
|
||||||
group_ids.each do |group_id|
|
DataExplorer::Query.create!(
|
||||||
query.query_groups.create!(group_id: group_id)
|
id: opts[:id],
|
||||||
end
|
name: opts[:name] || "Query number",
|
||||||
|
description: "A description for query number",
|
||||||
|
sql: sql,
|
||||||
|
hidden: opts[:hidden] || false,
|
||||||
|
)
|
||||||
|
group_ids.each { |group_id| query.query_groups.create!(group_id: group_id) }
|
||||||
query
|
query
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -20,13 +25,13 @@ describe 'Data Explorer rake tasks' do
|
||||||
DataExplorer::Query.where(hidden: true).order(:id)
|
DataExplorer::Query.where(hidden: true).order(:id)
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'data_explorer' do
|
describe "data_explorer" do
|
||||||
it 'hides a single query' do
|
it "hides a single query" do
|
||||||
DataExplorer::Query.destroy_all
|
DataExplorer::Query.destroy_all
|
||||||
make_query('SELECT 1 as value', id: 1, name: 'A')
|
make_query("SELECT 1 as value", id: 1, name: "A")
|
||||||
make_query('SELECT 1 as value', id: 2, name: 'B')
|
make_query("SELECT 1 as value", id: 2, name: "B")
|
||||||
# rake data_explorer[1] => hide query with ID 1
|
# rake data_explorer[1] => hide query with ID 1
|
||||||
silence_stdout { Rake::Task['data_explorer'].invoke(1) }
|
silence_stdout { Rake::Task["data_explorer"].invoke(1) }
|
||||||
|
|
||||||
# Soft deletion: PluginStoreRow should not be modified
|
# Soft deletion: PluginStoreRow should not be modified
|
||||||
expect(DataExplorer::Query.all.length).to eq(2)
|
expect(DataExplorer::Query.all.length).to eq(2)
|
||||||
|
@ -36,14 +41,14 @@ describe 'Data Explorer rake tasks' do
|
||||||
expect(hidden_queries[0].id).to eq(1)
|
expect(hidden_queries[0].id).to eq(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'hides multiple queries' do
|
it "hides multiple queries" do
|
||||||
DataExplorer::Query.destroy_all
|
DataExplorer::Query.destroy_all
|
||||||
make_query('SELECT 1 as value', id: 1, name: 'A')
|
make_query("SELECT 1 as value", id: 1, name: "A")
|
||||||
make_query('SELECT 1 as value', id: 2, name: 'B')
|
make_query("SELECT 1 as value", id: 2, name: "B")
|
||||||
make_query('SELECT 1 as value', id: 3, name: 'C')
|
make_query("SELECT 1 as value", id: 3, name: "C")
|
||||||
make_query('SELECT 1 as value', id: 4, name: 'D')
|
make_query("SELECT 1 as value", id: 4, name: "D")
|
||||||
# rake data_explorer[1,2,4] => hide queries with IDs 1, 2 and 4
|
# rake data_explorer[1,2,4] => hide queries with IDs 1, 2 and 4
|
||||||
silence_stdout { Rake::Task['data_explorer'].invoke(1, 2, 4) }
|
silence_stdout { Rake::Task["data_explorer"].invoke(1, 2, 4) }
|
||||||
|
|
||||||
# Soft deletion: PluginStoreRow should not be modified
|
# Soft deletion: PluginStoreRow should not be modified
|
||||||
expect(DataExplorer::Query.all.length).to eq(4)
|
expect(DataExplorer::Query.all.length).to eq(4)
|
||||||
|
@ -55,15 +60,15 @@ describe 'Data Explorer rake tasks' do
|
||||||
expect(hidden_queries[2].id).to eq(4)
|
expect(hidden_queries[2].id).to eq(4)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when query does not exist in PluginStore' do
|
context "when query does not exist in PluginStore" do
|
||||||
it 'should not hide the query' do
|
it "should not hide the query" do
|
||||||
DataExplorer::Query.destroy_all
|
DataExplorer::Query.destroy_all
|
||||||
make_query('SELECT 1 as value', id: 1, name: 'A')
|
make_query("SELECT 1 as value", id: 1, name: "A")
|
||||||
make_query('SELECT 1 as value', id: 2, name: 'B')
|
make_query("SELECT 1 as value", id: 2, name: "B")
|
||||||
# rake data_explorer[3] => try to hide query with ID 3
|
# rake data_explorer[3] => try to hide query with ID 3
|
||||||
silence_stdout { Rake::Task['data_explorer'].invoke(3) }
|
silence_stdout { Rake::Task["data_explorer"].invoke(3) }
|
||||||
# rake data_explorer[3,4,5] => try to hide queries with IDs 3, 4 and 5
|
# rake data_explorer[3,4,5] => try to hide queries with IDs 3, 4 and 5
|
||||||
silence_stdout { Rake::Task['data_explorer'].invoke(3, 4, 5) }
|
silence_stdout { Rake::Task["data_explorer"].invoke(3, 4, 5) }
|
||||||
|
|
||||||
# Array of hidden queries should be empty
|
# Array of hidden queries should be empty
|
||||||
expect(hidden_queries.length).to eq(0)
|
expect(hidden_queries.length).to eq(0)
|
||||||
|
@ -71,13 +76,13 @@ describe 'Data Explorer rake tasks' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#unhide_query' do
|
describe "#unhide_query" do
|
||||||
it 'unhides a single query' do
|
it "unhides a single query" do
|
||||||
DataExplorer::Query.destroy_all
|
DataExplorer::Query.destroy_all
|
||||||
make_query('SELECT 1 as value', id: 1, name: 'A', hidden: true)
|
make_query("SELECT 1 as value", id: 1, name: "A", hidden: true)
|
||||||
make_query('SELECT 1 as value', id: 2, name: 'B', hidden: true)
|
make_query("SELECT 1 as value", id: 2, name: "B", hidden: true)
|
||||||
# rake data_explorer:unhide_query[1] => unhide query with ID 1
|
# rake data_explorer:unhide_query[1] => unhide query with ID 1
|
||||||
silence_stdout { Rake::Task['data_explorer:unhide_query'].invoke(1) }
|
silence_stdout { Rake::Task["data_explorer:unhide_query"].invoke(1) }
|
||||||
|
|
||||||
# Soft deletion: PluginStoreRow should not be modified
|
# Soft deletion: PluginStoreRow should not be modified
|
||||||
expect(DataExplorer::Query.all.length).to eq(2)
|
expect(DataExplorer::Query.all.length).to eq(2)
|
||||||
|
@ -87,14 +92,14 @@ describe 'Data Explorer rake tasks' do
|
||||||
expect(hidden_queries[0].id).to eq(2)
|
expect(hidden_queries[0].id).to eq(2)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'unhides multiple queries' do
|
it "unhides multiple queries" do
|
||||||
DataExplorer::Query.destroy_all
|
DataExplorer::Query.destroy_all
|
||||||
make_query('SELECT 1 as value', id: 1, name: 'A', hidden: true)
|
make_query("SELECT 1 as value", id: 1, name: "A", hidden: true)
|
||||||
make_query('SELECT 1 as value', id: 2, name: 'B', hidden: true)
|
make_query("SELECT 1 as value", id: 2, name: "B", hidden: true)
|
||||||
make_query('SELECT 1 as value', id: 3, name: 'C', hidden: true)
|
make_query("SELECT 1 as value", id: 3, name: "C", hidden: true)
|
||||||
make_query('SELECT 1 as value', id: 4, name: 'D', hidden: true)
|
make_query("SELECT 1 as value", id: 4, name: "D", hidden: true)
|
||||||
# rake data_explorer:unhide_query[1,2,4] => unhide queries with IDs 1, 2 and 4
|
# rake data_explorer:unhide_query[1,2,4] => unhide queries with IDs 1, 2 and 4
|
||||||
silence_stdout { Rake::Task['data_explorer:unhide_query'].invoke(1, 2, 4) }
|
silence_stdout { Rake::Task["data_explorer:unhide_query"].invoke(1, 2, 4) }
|
||||||
|
|
||||||
# Soft deletion: PluginStoreRow should not be modified
|
# Soft deletion: PluginStoreRow should not be modified
|
||||||
expect(DataExplorer::Query.all.length).to eq(4)
|
expect(DataExplorer::Query.all.length).to eq(4)
|
||||||
|
@ -104,15 +109,15 @@ describe 'Data Explorer rake tasks' do
|
||||||
expect(hidden_queries[0].id).to eq(3)
|
expect(hidden_queries[0].id).to eq(3)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when query does not exist in PluginStore' do
|
context "when query does not exist in PluginStore" do
|
||||||
it 'should not unhide the query' do
|
it "should not unhide the query" do
|
||||||
DataExplorer::Query.destroy_all
|
DataExplorer::Query.destroy_all
|
||||||
make_query('SELECT 1 as value', id: 1, name: 'A', hidden: true)
|
make_query("SELECT 1 as value", id: 1, name: "A", hidden: true)
|
||||||
make_query('SELECT 1 as value', id: 2, name: 'B', hidden: true)
|
make_query("SELECT 1 as value", id: 2, name: "B", hidden: true)
|
||||||
# rake data_explorer:unhide_query[3] => try to unhide query with ID 3
|
# rake data_explorer:unhide_query[3] => try to unhide query with ID 3
|
||||||
silence_stdout { Rake::Task['data_explorer:unhide_query'].invoke(3) }
|
silence_stdout { Rake::Task["data_explorer:unhide_query"].invoke(3) }
|
||||||
# rake data_explorer:unhide_query[3,4,5] => try to unhide queries with IDs 3, 4 and 5
|
# rake data_explorer:unhide_query[3,4,5] => try to unhide queries with IDs 3, 4 and 5
|
||||||
silence_stdout { Rake::Task['data_explorer:unhide_query'].invoke(3, 4, 5) }
|
silence_stdout { Rake::Task["data_explorer:unhide_query"].invoke(3, 4, 5) }
|
||||||
|
|
||||||
# Array of hidden queries shouldn't change
|
# Array of hidden queries shouldn't change
|
||||||
expect(hidden_queries.length).to eq(2)
|
expect(hidden_queries.length).to eq(2)
|
||||||
|
@ -120,13 +125,13 @@ describe 'Data Explorer rake tasks' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#hard_delete' do
|
describe "#hard_delete" do
|
||||||
it 'hard deletes a single query' do
|
it "hard deletes a single query" do
|
||||||
DataExplorer::Query.destroy_all
|
DataExplorer::Query.destroy_all
|
||||||
make_query('SELECT 1 as value', id: 1, name: 'A', hidden: true)
|
make_query("SELECT 1 as value", id: 1, name: "A", hidden: true)
|
||||||
make_query('SELECT 1 as value', id: 2, name: 'B', hidden: true)
|
make_query("SELECT 1 as value", id: 2, name: "B", hidden: true)
|
||||||
# rake data_explorer:hard_delete[1] => hard delete query with ID 1
|
# rake data_explorer:hard_delete[1] => hard delete query with ID 1
|
||||||
silence_stdout { Rake::Task['data_explorer:hard_delete'].invoke(1) }
|
silence_stdout { Rake::Task["data_explorer:hard_delete"].invoke(1) }
|
||||||
|
|
||||||
# Hard deletion: query list should be shorter by 1
|
# Hard deletion: query list should be shorter by 1
|
||||||
expect(DataExplorer::Query.all.length).to eq(1)
|
expect(DataExplorer::Query.all.length).to eq(1)
|
||||||
|
@ -136,14 +141,14 @@ describe 'Data Explorer rake tasks' do
|
||||||
expect(hidden_queries[0].id).to eq(2)
|
expect(hidden_queries[0].id).to eq(2)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'hard deletes multiple queries' do
|
it "hard deletes multiple queries" do
|
||||||
DataExplorer::Query.destroy_all
|
DataExplorer::Query.destroy_all
|
||||||
make_query('SELECT 1 as value', id: 1, name: 'A', hidden: true)
|
make_query("SELECT 1 as value", id: 1, name: "A", hidden: true)
|
||||||
make_query('SELECT 1 as value', id: 2, name: 'B', hidden: true)
|
make_query("SELECT 1 as value", id: 2, name: "B", hidden: true)
|
||||||
make_query('SELECT 1 as value', id: 3, name: 'C', hidden: true)
|
make_query("SELECT 1 as value", id: 3, name: "C", hidden: true)
|
||||||
make_query('SELECT 1 as value', id: 4, name: 'D', hidden: true)
|
make_query("SELECT 1 as value", id: 4, name: "D", hidden: true)
|
||||||
# rake data_explorer:hard_delete[1,2,4] => hard delete queries with IDs 1, 2 and 4
|
# rake data_explorer:hard_delete[1,2,4] => hard delete queries with IDs 1, 2 and 4
|
||||||
silence_stdout { Rake::Task['data_explorer:hard_delete'].invoke(1, 2, 4) }
|
silence_stdout { Rake::Task["data_explorer:hard_delete"].invoke(1, 2, 4) }
|
||||||
|
|
||||||
# Hard deletion: query list should be shorter by 3
|
# Hard deletion: query list should be shorter by 3
|
||||||
expect(DataExplorer::Query.all.length).to eq(1)
|
expect(DataExplorer::Query.all.length).to eq(1)
|
||||||
|
@ -153,27 +158,27 @@ describe 'Data Explorer rake tasks' do
|
||||||
expect(hidden_queries[0].id).to eq(3)
|
expect(hidden_queries[0].id).to eq(3)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when query does not exist in PluginStore' do
|
context "when query does not exist in PluginStore" do
|
||||||
it 'should not hard delete the query' do
|
it "should not hard delete the query" do
|
||||||
DataExplorer::Query.destroy_all
|
DataExplorer::Query.destroy_all
|
||||||
make_query('SELECT 1 as value', id: 1, name: 'A', hidden: true)
|
make_query("SELECT 1 as value", id: 1, name: "A", hidden: true)
|
||||||
make_query('SELECT 1 as value', id: 2, name: 'B', hidden: true)
|
make_query("SELECT 1 as value", id: 2, name: "B", hidden: true)
|
||||||
# rake data_explorer:hard_delete[3] => try to hard delete query with ID 3
|
# rake data_explorer:hard_delete[3] => try to hard delete query with ID 3
|
||||||
silence_stdout { Rake::Task['data_explorer:hard_delete'].invoke(3) }
|
silence_stdout { Rake::Task["data_explorer:hard_delete"].invoke(3) }
|
||||||
# rake data_explorer:hard_delete[3,4,5] => try to hard delete queries with IDs 3, 4 and 5
|
# rake data_explorer:hard_delete[3,4,5] => try to hard delete queries with IDs 3, 4 and 5
|
||||||
silence_stdout { Rake::Task['data_explorer:hard_delete'].invoke(3, 4, 5) }
|
silence_stdout { Rake::Task["data_explorer:hard_delete"].invoke(3, 4, 5) }
|
||||||
|
|
||||||
# Array of hidden queries shouldn't change
|
# Array of hidden queries shouldn't change
|
||||||
expect(hidden_queries.length).to eq(2)
|
expect(hidden_queries.length).to eq(2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when query is not hidden' do
|
context "when query is not hidden" do
|
||||||
it 'should not hard delete the query' do
|
it "should not hard delete the query" do
|
||||||
DataExplorer::Query.destroy_all
|
DataExplorer::Query.destroy_all
|
||||||
make_query('SELECT 1 as value', id: 1, name: 'A')
|
make_query("SELECT 1 as value", id: 1, name: "A")
|
||||||
# rake data_explorer:hard_delete[1] => try to hard delete query with ID 1
|
# rake data_explorer:hard_delete[1] => try to hard delete query with ID 1
|
||||||
silence_stdout { Rake::Task['data_explorer:hard_delete'].invoke(1) }
|
silence_stdout { Rake::Task["data_explorer:hard_delete"].invoke(1) }
|
||||||
|
|
||||||
# List of queries shouldn't change
|
# List of queries shouldn't change
|
||||||
expect(DataExplorer::Query.all.length).to eq(1)
|
expect(DataExplorer::Query.all.length).to eq(1)
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
describe 'fix query ids rake task' do
|
describe "fix query ids rake task" do
|
||||||
before do
|
before do
|
||||||
Rake::Task.clear
|
Rake::Task.clear
|
||||||
Discourse::Application.load_tasks
|
Discourse::Application.load_tasks
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:query_name) { 'Awesome query' }
|
let(:query_name) { "Awesome query" }
|
||||||
|
|
||||||
it 'fixes the ID of the query if they share the same name' do
|
it "fixes the ID of the query if they share the same name" do
|
||||||
original_query_id = 4
|
original_query_id = 4
|
||||||
create_plugin_store_row(query_name, original_query_id)
|
create_plugin_store_row(query_name, original_query_id)
|
||||||
create_query(query_name)
|
create_query(query_name)
|
||||||
|
@ -20,7 +20,7 @@ describe 'fix query ids rake task' do
|
||||||
expect(find(query_name).id).to eq(original_query_id)
|
expect(find(query_name).id).to eq(original_query_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'only fixes queries with unique name' do
|
it "only fixes queries with unique name" do
|
||||||
original_query_id = 4
|
original_query_id = 4
|
||||||
create_plugin_store_row(query_name, original_query_id)
|
create_plugin_store_row(query_name, original_query_id)
|
||||||
create_query(query_name)
|
create_query(query_name)
|
||||||
|
@ -31,7 +31,7 @@ describe 'fix query ids rake task' do
|
||||||
expect(find(query_name).id).not_to eq(original_query_id)
|
expect(find(query_name).id).not_to eq(original_query_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'skips queries that already have the same ID' do
|
it "skips queries that already have the same ID" do
|
||||||
db_query = create_query(query_name)
|
db_query = create_query(query_name)
|
||||||
last_updated_at = db_query.updated_at
|
last_updated_at = db_query.updated_at
|
||||||
create_plugin_store_row(query_name, db_query.id)
|
create_plugin_store_row(query_name, db_query.id)
|
||||||
|
@ -41,9 +41,9 @@ describe 'fix query ids rake task' do
|
||||||
expect(find(query_name).updated_at).to eq_time(last_updated_at)
|
expect(find(query_name).updated_at).to eq_time(last_updated_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'keeps queries the rest of the queries' do
|
it "keeps queries the rest of the queries" do
|
||||||
original_query_id = 4
|
original_query_id = 4
|
||||||
different_query_name = 'Another query'
|
different_query_name = "Another query"
|
||||||
create_plugin_store_row(query_name, original_query_id)
|
create_plugin_store_row(query_name, original_query_id)
|
||||||
create_query(query_name)
|
create_query(query_name)
|
||||||
create_query(different_query_name)
|
create_query(different_query_name)
|
||||||
|
@ -53,8 +53,8 @@ describe 'fix query ids rake task' do
|
||||||
expect(find(different_query_name)).not_to be_nil
|
expect(find(different_query_name)).not_to be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'works even if they are additional conflicts' do
|
it "works even if they are additional conflicts" do
|
||||||
different_query_name = 'Another query'
|
different_query_name = "Another query"
|
||||||
additional_conflict = create_query(different_query_name)
|
additional_conflict = create_query(different_query_name)
|
||||||
create_query(query_name)
|
create_query(query_name)
|
||||||
create_plugin_store_row(query_name, additional_conflict.id)
|
create_plugin_store_row(query_name, additional_conflict.id)
|
||||||
|
@ -65,7 +65,7 @@ describe 'fix query ids rake task' do
|
||||||
expect(find(query_name).id).to eq(additional_conflict.id)
|
expect(find(query_name).id).to eq(additional_conflict.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'query groups' do
|
describe "query groups" do
|
||||||
let(:group) { Fabricate(:group) }
|
let(:group) { Fabricate(:group) }
|
||||||
|
|
||||||
it "fixes the query group's query_id" do
|
it "fixes the query group's query_id" do
|
||||||
|
@ -78,8 +78,8 @@ describe 'fix query ids rake task' do
|
||||||
expect(find_query_group(original_query_id)).not_to be_nil
|
expect(find_query_group(original_query_id)).not_to be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'works with additional conflicts' do
|
it "works with additional conflicts" do
|
||||||
different_query_name = 'Another query'
|
different_query_name = "Another query"
|
||||||
additional_conflict = create_query(different_query_name, [group.id])
|
additional_conflict = create_query(different_query_name, [group.id])
|
||||||
create_query(query_name, [group.id])
|
create_query(query_name, [group.id])
|
||||||
create_plugin_store_row(query_name, additional_conflict.id, [group.id])
|
create_plugin_store_row(query_name, additional_conflict.id, [group.id])
|
||||||
|
@ -98,7 +98,7 @@ describe 'fix query ids rake task' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'changes the serial sequence for future queries' do
|
it "changes the serial sequence for future queries" do
|
||||||
original_query_id = 4
|
original_query_id = 4
|
||||||
create_plugin_store_row(query_name, original_query_id)
|
create_plugin_store_row(query_name, original_query_id)
|
||||||
create_query(query_name)
|
create_query(query_name)
|
||||||
|
@ -110,7 +110,7 @@ describe 'fix query ids rake task' do
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_task
|
def run_task
|
||||||
Rake::Task['data_explorer:fix_query_ids'].invoke
|
Rake::Task["data_explorer:fix_query_ids"].invoke
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_plugin_store_row(name, id, group_ids = [])
|
def create_plugin_store_row(name, id, group_ids = [])
|
||||||
|
@ -119,27 +119,25 @@ describe 'fix query ids rake task' do
|
||||||
PluginStore.set(
|
PluginStore.set(
|
||||||
DataExplorer.plugin_name,
|
DataExplorer.plugin_name,
|
||||||
key,
|
key,
|
||||||
attributes(name).merge(group_ids: group_ids, id: id)
|
attributes(name).merge(group_ids: group_ids, id: id),
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_query(name, group_ids = [])
|
def create_query(name, group_ids = [])
|
||||||
DataExplorer::Query.create!(attributes(name)).tap do |query|
|
DataExplorer::Query
|
||||||
group_ids.each do |group_id|
|
.create!(attributes(name))
|
||||||
query.query_groups.create!(group_id: group_id)
|
.tap { |query| group_ids.each { |group_id| query.query_groups.create!(group_id: group_id) } }
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def attributes(name)
|
def attributes(name)
|
||||||
{
|
{
|
||||||
id: DataExplorer::Query.count == 0 ? 5 : DataExplorer::Query.maximum(:id) + 1,
|
id: DataExplorer::Query.count == 0 ? 5 : DataExplorer::Query.maximum(:id) + 1,
|
||||||
name: name,
|
name: name,
|
||||||
description: 'A Query',
|
description: "A Query",
|
||||||
sql: "SELECT 1",
|
sql: "SELECT 1",
|
||||||
created_at: 3.hours.ago,
|
created_at: 3.hours.ago,
|
||||||
last_run_at: 1.hour.ago,
|
last_run_at: 1.hour.ago,
|
||||||
hidden: false
|
hidden: false,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue