????

Your IP : 3.144.230.177


Current Path : C:/inetpub/vhost/redmine.gdtvietnam.com/plugins/redmine_drive/app/models/
Upload File :
Current File : C:/inetpub/vhost/redmine.gdtvietnam.com/plugins/redmine_drive/app/models/drive_entry_query.rb

# This file is a part of Redmin Drive (redmine_drive) plugin,
# Filse storage plugin for redmine
#
# Copyright (C) 2011-2024 RedmineUP
# http://www.redmineup.com/
#
# redmine_drive is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_drive is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_drive.  If not, see <http://www.gnu.org/licenses/>.

class DriveEntryQuery < Query
  self.queried_class = DriveEntry
  self.view_permission = :view_drive_entries

  operators_by_filter_type[:drive_entry_tags] = operators_by_filter_type[:list]

  class QueryMultipleValuesColumn < QueryColumn
    def value_object(object)
      value = super
      value.respond_to?(:to_a) ? value.to_a : value
    end
  end

  self.available_columns = [
    QueryColumn.new(:filename, sortable: "#{DriveEntry.table_name}.name", frozen: true),
    QueryColumn.new(:size, sortable: "#{Attachment.table_name}.filesize", caption: :field_filesize),
    QueryColumn.new(:created_at, sortable: "#{DriveEntry.table_name}.created_at", default_order: 'desc', caption: :field_created_on),
    QueryColumn.new(:version),
  ]

  # Scope of queries that are global or on the given project
  scope :global_or_on_project, lambda { |project|
    where(project_id: (project.nil? ? nil : [nil, project.id]))
  }

  scope :sorted, lambda { order(:name, :id) }

  def initialize(attributes = nil, *args)
    super attributes
    self.filters ||= {}
  end

  def initialize_available_filters
    add_available_filter 'name', type: :text
    add_available_filter 'filesize', type: :float
    add_available_filter 'created_at', type: :date_past, label: :field_created_on
    add_available_filter 'version', type: :integer
  end

  def default_columns_names
    @default_columns_names ||= [:filename, :tags, :updated_at, :size, :downloads, :author]
  end

  def default_sort_criteria
    []
  end

  def public_columns
    columns = [:filename, :size]
    columns.collect { |name| available_columns.find { |col| col.name == name } }
  end

  def css_classes
    s = sort_criteria.first
    if s.present?
      key, asc = s
      "sort-by-#{key.to_s.dasherize} sort-#{asc}"
    end
  end

  def is_private?
    visibility == VISIBILITY_PRIVATE
  end

  def base_scope(options = {})
    scope = DriveEntry.eager_load(:project)

    scope = scope.includes(:attachment, :author, :parent, :children, :viewings)

    scope = scope.where(statement)
    scope.where(<<-SQL.squish)
      #{DriveEntry.table_name}.version = (SELECT MAX(version) FROM #{DriveEntry.table_name} AS t2 WHERE
        CONCAT_WS(',', COALESCE(#{DriveEntry.table_name}.project_id, 0), COALESCE(#{DriveEntry.table_name}.parent_id, 0), #{DriveEntry.table_name}.name) =
        CONCAT_WS(',', COALESCE(t2.project_id, 0), COALESCE(t2.parent_id, 0), t2.name))
    SQL
  end

  def drive_entries(options = {})
    scope = base_scope(options).order(options[:order])
    scope = scope.visible unless options[:public]
      scope = scope.where(parent_id: options[:parent_id])
                   .where(project_id: options[:project_id] || project.try(:id))

    scope = scope.limit(options[:limit]) if options[:limit].present?
    custom_sort(scope)
  rescue ::ActiveRecord::StatementInvalid => e
    raise StatementInvalid.new(e.message)
  end

  def sql_for_filesize_field(field, operator, value)
    slq_for_files(sql_for_field(field, operator, value, Attachment.table_name, field))
  end

  def sql_for_downloads_field(_field, operator, value)
    if operator == '*'
      return slq_for_files('1=1')
    elsif operator == '!*'
      return slq_for_files("(#{DriveEntry.table_name}.id NOT IN (SELECT viewed_id FROM viewings))")
    end

    compare_sql =
      case operator
      when '><'
        "BETWEEN #{value[0].to_i} AND #{value[1].to_i}"
      else
        "#{operator} #{value.first}"
      end

    drive_entry_ids =
      if compare_sql
        ActiveRecord::Base.connection.execute(<<-SQL.squish).map { |row| row.is_a?(Array) ? row[0] : row['viewed_id'] }
          SELECT viewed_id, COUNT(*) as downloads
          FROM viewings
          GROUP BY viewed_id
          HAVING COUNT(*) #{compare_sql}
        SQL
      end

    condition =
      if drive_entry_ids.any?
        "#{DriveEntry.table_name}.id IN (#{drive_entry_ids.join(',')})"
      else
        '1=0'
      end

    if value.first.to_i.zero? || operator == '<='
      condition << " OR #{DriveEntry.table_name}.id NOT IN (SELECT viewed_id FROM viewings)"
    end

    slq_for_files condition
  end

  private

  def slq_for_files(condition)
    "(#{Attachment.table_name}.id IS NOT NULL) AND (#{condition})"
  end

  def sort_criteria_first_key
    @sort_criteria_first_key =
      if sort_criteria.respond_to?(:first_key)
        sort_criteria.first_key
      else
        sort_criteria.first.try(:first)
      end
  end

  def first_asc?
    return sort_criteria.first_asc? if sort_criteria.respond_to?(:first_asc?)

    sort_criteria.present? && sort_criteria.first.try(:last) == 'asc'
  end

  def custom_sort(drive_entries)
    drive_entries = sort_by_size(drive_entries) if sort_criteria_first_key == 'size'
    drive_entries = sort_by_downloads(drive_entries) if sort_criteria_first_key == 'downloads'
    group_by_entry_type(drive_entries)
  end

  def group_by_entry_type(drive_entries)
    groups = drive_entries.group_by(&:entry_type)
    groups[:folder].to_a + groups[:file].to_a
  end

  def sort_by_size(drive_entries)
    drive_entries.sort do |a, b|
      first_asc? ? a.size <=> b.size : b.size <=> a.size
    end
  end

  def sort_by_downloads(drive_entries)
    drive_entries.sort do |a, b|
      if first_asc?
        a.view_count <=> b.view_count
      else
        b.view_count <=> a.view_count
      end
    end
  end

  def principals
    @principal ||= begin
      principals = []
      if project
        principals += Principal.member_of(project)
        unless project.leaf?
          principals += Principal.member_of(project.descendants.visible.all)
        end
      else
        principals += Principal.member_of(all_projects)
      end
      principals.uniq!
      principals.sort!
      principals.reject! { |p| p.is_a?(GroupBuiltin) }
      principals
    end
  end

  def users
    principals.select { |p| p.is_a?(User) }
  end

  def values_for_author_filter
    return author_values if respond_to?(:author_values)

    author_values = []
    author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
    author_values += users.collect{|s| [s.name, s.id.to_s] }
    author_values
  end
end