Class: Query
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- Query
- Includes:
- Redmine::SubclassFactory
- Defined in:
- app/models/query.rb
Overview
Direct Known Subclasses
Defined Under Namespace
Classes: StatementInvalid
Constant Summary collapse
- VISIBILITY_PRIVATE =
0
- VISIBILITY_ROLES =
1
- VISIBILITY_PUBLIC =
2
Class Method Summary collapse
- .add_available_column(column) ⇒ Object
-
.build_from_params(params, attributes = {}) ⇒ Object
Builds a new query from the given params and attributes.
-
.operators_labels ⇒ Object
Returns a hash of localized labels for all filter operators.
-
.visible(*args) ⇒ Object
Scope of visible queries, can be used from subclasses only.
Instance Method Summary collapse
-
#add_available_filter(field, options) ⇒ Object
Adds an available filter.
- #add_filter(field, operator, values = nil) ⇒ Object
- #add_filter_error(field, message) ⇒ Object
-
#add_filters(fields, operators, values) ⇒ Object
Add multiple filters using
add_filter
. - #add_short_filter(field, expression) ⇒ Object
- #all_projects ⇒ Object
- #all_projects_values ⇒ Object
- #as_params ⇒ Object
- #assigned_to_values ⇒ Object
- #author_values ⇒ Object
- #available_block_columns ⇒ Object
-
#available_filters ⇒ Object
Return a hash of available filters.
-
#available_filters_as_json ⇒ Object
Returns a representation of the available filters for JSON serialization.
- #available_inline_columns ⇒ Object
- #available_totalable_columns ⇒ Object
- #block_columns ⇒ Object
-
#build_from_params(params, defaults = {}) ⇒ Object
Builds the query from the given params.
- #column_names=(names) ⇒ Object
- #columns ⇒ Object
- #css_classes ⇒ Object
- #default_columns_names ⇒ Object
- #default_sort_criteria ⇒ Object
- #default_totalable_names ⇒ Object
-
#delete_available_filter(field) ⇒ Object
Removes an available filter.
- #editable_by?(user) ⇒ Boolean
- #fixed_version_values ⇒ Object
- #group_by_column ⇒ Object
-
#group_by_sort_order ⇒ Object
Returns the SQL sort order that should be prepended for grouping.
- #group_by_statement ⇒ Object
-
#groupable_columns ⇒ Object
Returns an array of columns that can be used to group the results.
-
#grouped? ⇒ Boolean
Returns true if the query is a grouped query.
- #has_column?(column) ⇒ Boolean
- #has_custom_field_column? ⇒ Boolean
- #has_default_columns? ⇒ Boolean
- #has_filter?(field) ⇒ Boolean
- #inline_columns ⇒ Object
-
#is_global? ⇒ Boolean
Returns true if the query is available for all projects.
- #is_private? ⇒ Boolean
- #is_public? ⇒ Boolean
-
#issue_custom_fields ⇒ Object
Returns a scope of issue custom fields that are available as columns or filters.
-
#issue_statuses_values ⇒ Object
Returns a scope of issue statuses that are available as columns for filters.
- #label_for(field) ⇒ Object
- #operator_for(field) ⇒ Object
- #principals ⇒ Object
- #project_statement ⇒ Object
-
#project_statuses_values ⇒ Object
Returns a scope of project statuses that are available as columns or filters.
- #project_values ⇒ Object
- #queried_table_name ⇒ Object
-
#result_count_by_group ⇒ Object
Returns the result count by group or nil if query is not grouped.
- #sort_clause ⇒ Object
- #sort_criteria ⇒ Object
- #sort_criteria=(arg) ⇒ Object
- #sort_criteria_key(index) ⇒ Object
- #sort_criteria_order(index) ⇒ Object
-
#sortable_columns ⇒ Object
Returns a Hash of columns and the key for sorting.
- #statement ⇒ Object
- #subproject_values ⇒ Object
-
#total_by_group_for(column) ⇒ Object
Returns a hash of the sum of the given column for each group, or nil if the query is not grouped.
-
#total_for(column) ⇒ Object
Returns the sum of values for the given column.
- #totalable_columns ⇒ Object
- #totalable_names ⇒ Object
- #totalable_names=(names) ⇒ Object
- #totals {|totals| ... } ⇒ Object
- #totals_by_group {|totals| ... } ⇒ Object
- #trackers ⇒ Object
- #type_for(field) ⇒ Object
- #users ⇒ Object
- #validate_query_filters ⇒ Object
- #value_for(field, index = 0) ⇒ Object
- #values_for(field) ⇒ Object
-
#visible?(user = User.current) ⇒ Boolean
Returns true if the query is visible to
user
or the current user. - #watcher_values ⇒ Object
Class Method Details
.add_available_column(column) ⇒ Object
672 673 674 |
# File 'app/models/query.rb', line 672 def self.add_available_column(column) self.available_columns << (column) if column.is_a?(QueryColumn) end |
.build_from_params(params, attributes = {}) ⇒ Object
Builds a new query from the given params and attributes
388 389 390 |
# File 'app/models/query.rb', line 388 def self.build_from_params(params, attributes={}) new(attributes).build_from_params(params) end |
.operators_labels ⇒ Object
Returns a hash of localized labels for all filter operators
458 459 460 |
# File 'app/models/query.rb', line 458 def self.operators_labels operators.inject({}) {|h, operator| h[operator.first] = l(*operator.last); h} end |
.visible(*args) ⇒ Object
Scope of visible queries, can be used from subclasses only. Unlike other visible scopes, a class methods is used as it let handle inheritance more nicely than scope DSL.
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
# File 'app/models/query.rb', line 301 def self.visible(*args) if self == ::Query # Visibility depends on permissions for each subclass, # raise an error if the scope is called from Query (eg. Query.visible) raise Exception.new("Cannot call .visible scope from the base Query class, but from subclasses only.") end user = args.shift || User.current base = Project.allowed_to_condition(user, , *args) scope = joins("LEFT OUTER JOIN #{Project.table_name} ON #{table_name}.project_id = #{Project.table_name}.id"). where("#{table_name}.project_id IS NULL OR (#{base})") if user.admin? scope.where("#{table_name}.visibility <> ? OR #{table_name}.user_id = ?", VISIBILITY_PRIVATE, user.id) elsif user.memberships.any? scope.where("#{table_name}.visibility = ?" + " OR (#{table_name}.visibility = ? AND #{table_name}.id IN (" + "SELECT DISTINCT q.id FROM #{table_name} q" + " INNER JOIN #{table_name_prefix}queries_roles#{table_name_suffix} qr on qr.query_id = q.id" + " INNER JOIN #{MemberRole.table_name} mr ON mr.role_id = qr.role_id" + " INNER JOIN #{Member.table_name} m ON m.id = mr.member_id AND m.user_id = ?" + " INNER JOIN #{Project.table_name} p ON p.id = m.project_id AND p.status <> ?" + " WHERE q.project_id IS NULL OR q.project_id = m.project_id))" + " OR #{table_name}.user_id = ?", VISIBILITY_PUBLIC, VISIBILITY_ROLES, user.id, Project::STATUS_ARCHIVED, user.id) elsif user.logged? scope.where("#{table_name}.visibility = ? OR #{table_name}.user_id = ?", VISIBILITY_PUBLIC, user.id) else scope.where("#{table_name}.visibility = ?", VISIBILITY_PUBLIC) end end |
Instance Method Details
#add_available_filter(field, options) ⇒ Object
Adds an available filter
597 598 599 600 601 |
# File 'app/models/query.rb', line 597 def add_available_filter(field, ) @available_filters ||= ActiveSupport::OrderedHash.new @available_filters[field] = QueryFilter.new(field, ) @available_filters end |
#add_filter(field, operator, values = nil) ⇒ Object
619 620 621 622 623 624 625 626 |
# File 'app/models/query.rb', line 619 def add_filter(field, operator, values=nil) # values must be an array return unless values.nil? || values.is_a?(Array) # check if field is defined as an available filter if available_filters.has_key? field filters[field] = {:operator => operator, :values => (values || [''])} end end |
#add_filter_error(field, message) ⇒ Object
440 441 442 443 |
# File 'app/models/query.rb', line 440 def add_filter_error(field, ) m = label_for(field) + " " + l(, :scope => 'activerecord.errors.messages') errors.add(:base, m) end |
#add_filters(fields, operators, values) ⇒ Object
Add multiple filters using add_filter
639 640 641 642 643 644 645 |
# File 'app/models/query.rb', line 639 def add_filters(fields, operators, values) if fields.present? && operators.present? fields.each do |field| add_filter(field, operators[field], values && values[field]) end end end |
#add_short_filter(field, expression) ⇒ Object
628 629 630 631 632 633 634 635 636 |
# File 'app/models/query.rb', line 628 def add_short_filter(field, expression) return unless expression && available_filters.has_key?(field) field_type = available_filters[field][:type] operators_by_filter_type[field_type].sort.reverse.detect do |operator| next unless expression =~ /^#{Regexp.escape(operator)}(.*)$/ values = $1 add_filter field, operator, values.present? ? values.split('|') : [''] end || add_filter(field, '=', expression.to_s.split('|')) end |
#all_projects ⇒ Object
483 484 485 |
# File 'app/models/query.rb', line 483 def all_projects @all_projects ||= Project.visible.to_a end |
#all_projects_values ⇒ Object
487 488 489 490 491 492 493 494 495 496 |
# File 'app/models/query.rb', line 487 def all_projects_values return @all_projects_values if @all_projects_values values = [] Project.project_tree(all_projects) do |p, level| prefix = (level > 0 ? ('--' * level + ' ') : '') values << ["#{prefix}#{p.name}", p.id.to_s] end @all_projects_values = values end |
#as_params ⇒ Object
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
# File 'app/models/query.rb', line 392 def as_params if new_record? params = {} filters.each do |field, | params[:f] ||= [] params[:f] << field params[:op] ||= {} params[:op][field] = [:operator] params[:v] ||= {} params[:v][field] = [:values] end params[:c] = column_names params[:sort] = sort_criteria.to_param params[:set_filter] = 1 params else {:query_id => id} end end |
#assigned_to_values ⇒ Object
540 541 542 543 544 545 |
# File 'app/models/query.rb', line 540 def assigned_to_values assigned_to_values = [] assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? assigned_to_values += (Setting.issue_group_assignment? ? principals : users).sort_by(&:status).collect{|s| [s.name, s.id.to_s, l("status_#{User::LABEL_BY_STATUS[s.status]}")] } assigned_to_values end |
#author_values ⇒ Object
533 534 535 536 537 538 |
# File 'app/models/query.rb', line 533 def = [] << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? += users.sort_by(&:status).collect{|s| [s.name, s.id.to_s, l("status_#{User::LABEL_BY_STATUS[s.status]}")] } end |
#available_block_columns ⇒ Object
709 710 711 |
# File 'app/models/query.rb', line 709 def available_block_columns available_columns.reject(&:inline?) end |
#available_filters ⇒ Object
Return a hash of available filters
611 612 613 614 615 616 617 |
# File 'app/models/query.rb', line 611 def available_filters unless @available_filters initialize_available_filters @available_filters ||= {} end @available_filters end |
#available_filters_as_json ⇒ Object
Returns a representation of the available filters for JSON serialization
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 |
# File 'app/models/query.rb', line 463 def available_filters_as_json json = {} available_filters.each do |field, filter| = {:type => filter[:type], :name => filter[:name]} [:remote] = true if filter.remote if has_filter?(field) || !filter.remote [:values] = filter.values if [:values] && values_for(field) missing = Array(values_for(field)).select(&:present?) - [:values].map(&:last) if missing.any? && respond_to?(method = "find_#{field}_filter_values") [:values] += send(method, missing) end end end json[field] = .stringify_keys end json end |
#available_inline_columns ⇒ Object
705 706 707 |
# File 'app/models/query.rb', line 705 def available_inline_columns available_columns.select(&:inline?) end |
#available_totalable_columns ⇒ Object
713 714 715 |
# File 'app/models/query.rb', line 713 def available_totalable_columns available_columns.select(&:totalable) end |
#block_columns ⇒ Object
701 702 703 |
# File 'app/models/query.rb', line 701 def block_columns columns.reject(&:inline?) end |
#build_from_params(params, defaults = {}) ⇒ Object
Builds the query from the given params
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
# File 'app/models/query.rb', line 369 def build_from_params(params, defaults={}) if params[:fields] || params[:f] self.filters = {} add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v]) else available_filters.each_key do |field| add_short_filter(field, params[field]) if params[field] end end query_params = params[:query] || defaults || {} self.group_by = params[:group_by] || query_params[:group_by] || self.group_by self.column_names = params[:c] || query_params[:column_names] || self.column_names self.totalable_names = params[:t] || query_params[:totalable_names] || self.totalable_names self.sort_criteria = params[:sort] || query_params[:sort_criteria] || self.sort_criteria self end |
#column_names=(names) ⇒ Object
725 726 727 728 729 730 731 732 733 734 735 736 737 738 |
# File 'app/models/query.rb', line 725 def column_names=(names) if names names = names.select {|n| n.is_a?(Symbol) || !n.blank? } names = names.collect {|n| n.is_a?(Symbol) ? n : n.to_sym } if names.delete(:all_inline) names = available_inline_columns.map(&:name) | names end # Set column_names to nil if default columns if names == default_columns_names names = nil end end write_attribute(:column_names, names) end |
#columns ⇒ Object
689 690 691 692 693 694 695 |
# File 'app/models/query.rb', line 689 def columns # preserve the column_names order cols = (has_default_columns? ? default_columns_names : column_names).collect do |name| available_columns.find { |col| col.name == name } end.compact available_columns.select(&:frozen?) | cols end |
#css_classes ⇒ Object
942 943 944 945 946 947 948 |
# File 'app/models/query.rb', line 942 def css_classes s = sort_criteria.first if s.present? key, asc = s "sort-by-#{key.to_s.dasherize} sort-#{asc}" end end |
#default_columns_names ⇒ Object
717 718 719 |
# File 'app/models/query.rb', line 717 def default_columns_names [] end |
#default_sort_criteria ⇒ Object
769 770 771 |
# File 'app/models/query.rb', line 769 def default_sort_criteria [] end |
#default_totalable_names ⇒ Object
721 722 723 |
# File 'app/models/query.rb', line 721 def default_totalable_names [] end |
#delete_available_filter(field) ⇒ Object
Removes an available filter
604 605 606 607 608 |
# File 'app/models/query.rb', line 604 def delete_available_filter(field) if @available_filters @available_filters.delete(field) end end |
#editable_by?(user) ⇒ Boolean
445 446 447 448 449 450 451 |
# File 'app/models/query.rb', line 445 def editable_by?(user) return false unless user # Admin can edit them all and regular users can edit their private queries return true if user.admin? || (is_private? && self.user_id == user.id) # Members can not edit public queries that are for all project (only admin is allowed to) is_public? && !is_global? && user.allowed_to?(:manage_public_queries, project) end |
#fixed_version_values ⇒ Object
547 548 549 550 551 552 553 554 555 |
# File 'app/models/query.rb', line 547 def fixed_version_values versions = [] if project versions = project.shared_versions.to_a else versions = Version.visible.to_a end Version.sort_by_status(versions).collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s, l("version_status_#{s.status}")] } end |
#group_by_column ⇒ Object
814 815 816 |
# File 'app/models/query.rb', line 814 def group_by_column groupable_columns.detect {|c| c.groupable && c.name.to_s == group_by} end |
#group_by_sort_order ⇒ Object
Returns the SQL sort order that should be prepended for grouping
802 803 804 805 806 807 |
# File 'app/models/query.rb', line 802 def group_by_sort_order if column = group_by_column order = (sort_criteria.order_for(column.name) || column.default_order || 'asc').try(:upcase) Array(column.sortable).map {|s| Arel.sql("#{s} #{order}")} end end |
#group_by_statement ⇒ Object
818 819 820 |
# File 'app/models/query.rb', line 818 def group_by_statement group_by_column.try(:groupable) end |
#groupable_columns ⇒ Object
Returns an array of columns that can be used to group the results
677 678 679 |
# File 'app/models/query.rb', line 677 def groupable_columns available_columns.select {|c| c.groupable} end |
#grouped? ⇒ Boolean
Returns true if the query is a grouped query
810 811 812 |
# File 'app/models/query.rb', line 810 def grouped? !group_by_column.nil? end |
#has_column?(column) ⇒ Boolean
740 741 742 743 |
# File 'app/models/query.rb', line 740 def has_column?(column) name = column.is_a?(QueryColumn) ? column.name : column columns.detect {|c| c.name == name} end |
#has_custom_field_column? ⇒ Boolean
745 746 747 |
# File 'app/models/query.rb', line 745 def has_custom_field_column? columns.any? {|column| column.is_a? QueryCustomFieldColumn} end |
#has_default_columns? ⇒ Boolean
749 750 751 |
# File 'app/models/query.rb', line 749 def has_default_columns? column_names.nil? || column_names.empty? end |
#has_filter?(field) ⇒ Boolean
647 648 649 |
# File 'app/models/query.rb', line 647 def has_filter?(field) filters and filters[field] end |
#inline_columns ⇒ Object
697 698 699 |
# File 'app/models/query.rb', line 697 def inline_columns columns.select(&:inline?) end |
#is_global? ⇒ Boolean
Returns true if the query is available for all projects
360 361 362 |
# File 'app/models/query.rb', line 360 def is_global? new_record? ? project_id.nil? : project_id_in_database.nil? end |
#is_private? ⇒ Boolean
351 352 353 |
# File 'app/models/query.rb', line 351 def is_private? visibility == VISIBILITY_PRIVATE end |
#is_public? ⇒ Boolean
355 356 357 |
# File 'app/models/query.rb', line 355 def is_public? !is_private? end |
#issue_custom_fields ⇒ Object
Returns a scope of issue custom fields that are available as columns or filters
574 575 576 577 578 579 580 |
# File 'app/models/query.rb', line 574 def issue_custom_fields if project project.rolled_up_custom_fields else IssueCustomField.all end end |
#issue_statuses_values ⇒ Object
Returns a scope of issue statuses that are available as columns for filters
558 559 560 561 562 563 564 565 |
# File 'app/models/query.rb', line 558 def issue_statuses_values if project statuses = project.rolled_up_statuses else statuses = IssueStatus.all.sorted end statuses.collect{|s| [s.name, s.id.to_s]} end |
#label_for(field) ⇒ Object
667 668 669 670 |
# File 'app/models/query.rb', line 667 def label_for(field) label = available_filters[field][:name] if available_filters.has_key?(field) label ||= queried_class.human_attribute_name(field, :default => field) end |
#operator_for(field) ⇒ Object
655 656 657 |
# File 'app/models/query.rb', line 655 def operator_for(field) has_filter?(field) ? filters[field][:operator] : nil end |
#principals ⇒ Object
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 |
# File 'app/models/query.rb', line 511 def principals @principal ||= begin principals = [] if project principals += Principal.member_of(project).visible unless project.leaf? principals += Principal.member_of(project.descendants.visible).visible end else principals += Principal.member_of(all_projects).visible end principals.uniq! principals.sort! principals.reject! {|p| p.is_a?(GroupBuiltin)} principals end end |
#project_statement ⇒ Object
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 |
# File 'app/models/query.rb', line 822 def project_statement project_clauses = [] active_subprojects_ids = [] active_subprojects_ids = project.descendants.active.map(&:id) if project if active_subprojects_ids.any? if has_filter?("subproject_id") case operator_for("subproject_id") when '=' # include the selected subprojects ids = [project.id] + values_for("subproject_id").map(&:to_i) project_clauses << "#{Project.table_name}.id IN (%s)" % ids.join(',') when '!' # exclude the selected subprojects ids = [project.id] + active_subprojects_ids - values_for("subproject_id").map(&:to_i) project_clauses << "#{Project.table_name}.id IN (%s)" % ids.join(',') when '!*' # main project only project_clauses << "#{Project.table_name}.id = %d" % project.id else # all subprojects project_clauses << "#{Project.table_name}.lft >= #{project.lft} AND #{Project.table_name}.rgt <= #{project.rgt}" end elsif Setting.display_subprojects_issues? project_clauses << "#{Project.table_name}.lft >= #{project.lft} AND #{Project.table_name}.rgt <= #{project.rgt}" else project_clauses << "#{Project.table_name}.id = %d" % project.id end elsif project project_clauses << "#{Project.table_name}.id = %d" % project.id end project_clauses.any? ? project_clauses.join(' AND ') : nil end |
#project_statuses_values ⇒ Object
Returns a scope of project statuses that are available as columns or filters
583 584 585 586 587 588 |
# File 'app/models/query.rb', line 583 def project_statuses_values project_statuses = Project::LABEL_BY_STATUS # Remove archived status from filters project_statuses.delete(9) project_statuses.stringify_keys.invert.to_a end |
#project_values ⇒ Object
498 499 500 501 502 503 504 505 |
# File 'app/models/query.rb', line 498 def project_values project_values = [] if User.current.logged? && User.current.memberships.any? project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"] end project_values += all_projects_values project_values end |
#queried_table_name ⇒ Object
364 365 366 |
# File 'app/models/query.rb', line 364 def queried_table_name @queried_table_name ||= self.class.queried_class.table_name end |
#result_count_by_group ⇒ Object
Returns the result count by group or nil if query is not grouped
911 912 913 914 915 |
# File 'app/models/query.rb', line 911 def result_count_by_group grouped_query do |scope| scope.count end end |
#sort_clause ⇒ Object
795 796 797 798 799 |
# File 'app/models/query.rb', line 795 def sort_clause if clause = sort_criteria.sort_clause(sortable_columns) clause.map {|c| Arel.sql c} end end |
#sort_criteria ⇒ Object
779 780 781 782 783 784 785 |
# File 'app/models/query.rb', line 779 def sort_criteria c = read_attribute(:sort_criteria) if c.blank? c = default_sort_criteria end Redmine::SortCriteria.new(c) end |
#sort_criteria=(arg) ⇒ Object
773 774 775 776 777 |
# File 'app/models/query.rb', line 773 def sort_criteria=(arg) c = Redmine::SortCriteria.new(arg) write_attribute(:sort_criteria, c.to_a) c end |
#sort_criteria_key(index) ⇒ Object
787 788 789 |
# File 'app/models/query.rb', line 787 def sort_criteria_key(index) sort_criteria[index].try(:first) end |
#sort_criteria_order(index) ⇒ Object
791 792 793 |
# File 'app/models/query.rb', line 791 def sort_criteria_order(index) sort_criteria[index].try(:last) end |
#sortable_columns ⇒ Object
Returns a Hash of columns and the key for sorting
682 683 684 685 686 687 |
# File 'app/models/query.rb', line 682 def sortable_columns available_columns.inject({}) {|h, column| h[column.name.to_s] = column.sortable h } end |
#statement ⇒ Object
856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 |
# File 'app/models/query.rb', line 856 def statement # filters clauses filters_clauses = [] filters.each_key do |field| next if field == "subproject_id" v = values_for(field).clone next unless v and !v.empty? operator = operator_for(field) # "me" value substitution if %w(assigned_to_id author_id user_id watcher_id updated_by last_updated_by).include?(field) if v.delete("me") if User.current.logged? v.push(User.current.id.to_s) v += User.current.group_ids.map(&:to_s) if field == 'assigned_to_id' else v.push("0") end end end if field == 'project_id' if v.delete('mine') v += User.current.memberships.map(&:project_id).map(&:to_s) end end if field =~ /^cf_(\d+)\.cf_(\d+)$/ filters_clauses << sql_for_chained_custom_field(field, operator, v, $1, $2) elsif field =~ /cf_(\d+)$/ # custom field filters_clauses << sql_for_custom_field(field, operator, v, $1) elsif field =~ /^cf_(\d+)\.(.+)$/ filters_clauses << sql_for_custom_field_attribute(field, operator, v, $1, $2) elsif respond_to?(method = "sql_for_#{field.tr('.','_')}_field") # specific statement filters_clauses << send(method, field, operator, v) else # regular field filters_clauses << '(' + sql_for_field(field, operator, v, queried_table_name, field) + ')' end end if filters and valid? if (c = group_by_column) && c.is_a?(QueryCustomFieldColumn) # Excludes results for which the grouped custom field is not visible filters_clauses << c.custom_field.visibility_by_project_condition end filters_clauses << project_statement filters_clauses.reject!(&:blank?) filters_clauses.any? ? filters_clauses.join(' AND ') : nil end |
#subproject_values ⇒ Object
507 508 509 |
# File 'app/models/query.rb', line 507 def subproject_values project.descendants.visible.collect{|s| [s.name, s.id.to_s] } end |
#total_by_group_for(column) ⇒ Object
Returns a hash of the sum of the given column for each group, or nil if the query is not grouped
924 925 926 927 928 |
# File 'app/models/query.rb', line 924 def total_by_group_for(column) grouped_query do |scope| total_with_scope(column, scope) end end |
#total_for(column) ⇒ Object
Returns the sum of values for the given column
918 919 920 |
# File 'app/models/query.rb', line 918 def total_for(column) total_with_scope(column, base_scope) end |
#totalable_columns ⇒ Object
753 754 755 756 |
# File 'app/models/query.rb', line 753 def totalable_columns names = totalable_names available_totalable_columns.select {|column| names.include?(column.name)} end |
#totalable_names ⇒ Object
765 766 767 |
# File 'app/models/query.rb', line 765 def totalable_names [:totalable_names] || default_totalable_names || [] end |
#totalable_names=(names) ⇒ Object
758 759 760 761 762 763 |
# File 'app/models/query.rb', line 758 def totalable_names=(names) if names names = names.select(&:present?).map {|n| n.is_a?(Symbol) ? n : n.to_sym} end [:totalable_names] = names end |
#totals {|totals| ... } ⇒ Object
930 931 932 933 934 |
# File 'app/models/query.rb', line 930 def totals totals = totalable_columns.map {|column| [column, total_for(column)]} yield totals if block_given? totals end |
#totals_by_group {|totals| ... } ⇒ Object
936 937 938 939 940 |
# File 'app/models/query.rb', line 936 def totals_by_group totals = totalable_columns.map {|column| [column, total_by_group_for(column)]} yield totals if block_given? totals end |
#trackers ⇒ Object
453 454 455 |
# File 'app/models/query.rb', line 453 def trackers @trackers ||= (project.nil? ? Tracker.all : project.rolled_up_trackers).visible.sorted end |
#type_for(field) ⇒ Object
651 652 653 |
# File 'app/models/query.rb', line 651 def type_for(field) available_filters[field][:type] if available_filters.has_key?(field) end |
#users ⇒ Object
529 530 531 |
# File 'app/models/query.rb', line 529 def users principals.select {|p| p.is_a?(User)} end |
#validate_query_filters ⇒ Object
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 |
# File 'app/models/query.rb', line 412 def validate_query_filters filters.each_key do |field| if values_for(field) case type_for(field) when :integer add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/\A[+-]?\d+(,[+-]?\d+)*\z/) } when :float add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/\A[+-]?\d+(\.\d*)?\z/) } when :date, :date_past case operator_for(field) when "=", ">=", "<=", "><" add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && (!v.match(/\A\d{4}-\d{2}-\d{2}(T\d{2}((:)?\d{2}){0,2}(Z|\d{2}:?\d{2})?)?\z/) || parse_date(v).nil?) } when ">t-", "<t-", "t-", ">t+", "<t+", "t+", "><t+", "><t-" add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^\d+$/) } end end end add_filter_error(field, :blank) unless # filter requires one or more values (values_for(field) and !values_for(field).first.blank?) or # filter doesn't require any value ["o", "c", "!*", "*", "t", "ld", "w", "lw", "l2w", "m", "lm", "y", "*o", "!o"].include? operator_for(field) end if filters end |
#value_for(field, index = 0) ⇒ Object
663 664 665 |
# File 'app/models/query.rb', line 663 def value_for(field, index=0) (values_for(field) || [])[index] end |
#values_for(field) ⇒ Object
659 660 661 |
# File 'app/models/query.rb', line 659 def values_for(field) has_filter?(field) ? filters[field][:values] : nil end |
#visible?(user = User.current) ⇒ Boolean
Returns true if the query is visible to user
or the current
user.
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
# File 'app/models/query.rb', line 334 def visible?(user=User.current) return true if user.admin? return false unless project.nil? || user.allowed_to?(self.class., project) case visibility when VISIBILITY_PUBLIC true when VISIBILITY_ROLES if project (user.roles_for_project(project) & roles).any? else user.memberships.joins(:member_roles).where(:member_roles => {:role_id => roles.map(&:id)}).any? end else user == self.user end end |
#watcher_values ⇒ Object
567 568 569 570 571 |
# File 'app/models/query.rb', line 567 def watcher_values watcher_values = [["<< #{l(:label_me)} >>", "me"]] watcher_values += users.sort_by(&:status).collect{|s| [s.name, s.id.to_s, l("status_#{User::LABEL_BY_STATUS[s.status]}")] } if User.current.allowed_to?(:view_issue_watchers, self.project) watcher_values end |