app/controllers/datasets_controller.rb
# -*- encoding : utf-8 -*-
# Datasets Controller
#
# Copyright:: (C) 2009 Knowerce, s.r.o.
#
# Author:: Vojto Rinik <vojto@rinik.net>
# Date: Sep 2009
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class DatasetsController < ApplicationController
before_filter :prepare_filters, :only => [:show, :update]
privilege_required :edit_record, :only => [:update]
helper_method :has_filters?
def index
@only_good = params[:only_good]
respond_to do |wants|
wants.html do
@dataset_categories = DatasetCategory.
order('dataset_categories.position, dataset_descriptions.position').
includes(:dataset_descriptions => :translations).
where('dataset_descriptions.is_active = 1')
if @only_good
@dataset_categories.where('dataset_description.bad_quality = false')
end
end
wants.xml { render :xml => DatasetDescription.active }
end
end
def show
@dataset_description = DatasetDescription.find(params[:id])
@field_descriptions = @dataset_description.visible_field_descriptions.includes(:data_format)
@dataset_class = @dataset_description.dataset_model
@title = @dataset_description.title
render_404 and return unless @dataset_description.is_active? || has_privilege?(:view_hidden_records)
@sortable_columns = @dataset_class.columns.map(&:name)
unless @dataset_class.table_exists?
logger.error "Dataset table doesn't exist for #{@dataset_description.title} (#{@dataset_class.table_name})"
flash[:error] = I18n.t("dataset.internal_dataset_error", :title => @dataset_description.title)
return redirect_to datasets_path
end
# Favorite if there's one
@favorite = current_user.favorite_for!(@dataset_description, @record) if current_user
# Add pagination stuff to those options
paginate_options = {max_matches: 10_000}
params[:page] = nil if params[:page].blank?
paginate_options[:page] = params[:page] if params[:page]#? params[:page] : nil
paginate_options[:per_page] = current_user ? current_user.records_per_page : params[:records_per_page] || RECORDS_PER_PAGE
# paginate_options[:total_entries] = ((params[:page].to_i||1)+9) * paginate_options[:per_page]
# check if sort is valid
if params[:sort]
if @sortable_columns.exclude? params[:sort]
redirect_to dataset_path(@dataset_description) and return
end
end
if params[:sort]
paginate_options[:order] = sanitize_sort_column(params[:sort], @sortable_columns).to_sym
paginate_options[:sort_mode] = sanitize_sort_direction(params[:dir]).to_sym
end
paginate_options[:conditions], paginate_options[:with], paginate_options[:without] = {},{},{}
paginate_options[:sphinx_select] = "*"
sphinx_search = ""
paginate_options[:match_mode] = :extended
if @filters
paginate_options[:conditions] ||= {}
filters = @filters.find_all{|key,value|!value.blank?}
filters.each do |key, value|
paginate_options[:conditions].merge!({key.to_sym => value})
end
paginate_options[:conditions].merge!({:record_status => "#{Dataset::RecordStatus.find(:published)}|#{Dataset::RecordStatus.find(:morphed)}"}) unless current_user && current_user.has_privilege?(:power_user)
# raise select_options.to_yaml
end
if params[:search_id].blank?
sort_direction = sanitize_sort_direction(params[:dir])
if params[:sort] && params[:page]
# This ugly thing is here because mysql is lame and doesn't use indexes when there is just an order and a limit on the select (pagination with ordering)...
total_entries = @dataset_class.count
page = params[:page].to_i
per_page = paginate_options[:per_page].to_i
@records = @dataset_class.select('*').
from(prepare_subselect(@dataset_class.table_name, @sortable_columns, params, paginate_options)).
joins("JOIN `#{@dataset_class.table_name}` `t` on `q`.`_record_id` = `t`.`_record_id`")
if !current_user || !current_user.has_privilege?(:power_user)
@records = @records.where('t.record_status in (?)', [Dataset::RecordStatus.find(:published), Dataset::RecordStatus.find(:morphed)])
elsif @filters
@dataset_class = @dataset_class.where('t.record_status = ?', @filters['record_status']) if @filters['record_status'].present?
if @filters['quality_status'].present?
if @filters['quality_status'] == 'absent'
@dataset_class = @dataset_class.where('t.quality_status IS NULL OR t.quality_status = ?', @filters['quality_status'])
else
@dataset_class = @dataset_class.where('t.quality_status = ?', @filters['quality_status'])
end
end
end
records = @records
@records = WillPaginate::Collection.create(page, per_page, total_entries) do |pager|
pager.replace(records)
end
else
if params[:sort]
@dataset_class = @dataset_class.order("`#{sanitize_sort_column(params[:sort], @sortable_columns)}` #{sort_direction}")
else
@dataset_class.order('created_at DESC, _record_id DESC')
end
if !current_user || !current_user.has_privilege?(:power_user)
@dataset_class = @dataset_class.where(:record_status => Dataset::RecordStatus.find(:published))
elsif @filters
@dataset_class = @dataset_class.where(:record_status => @filters['record_status']) if @filters['record_status'].present?
if @filters['quality_status'].present?
if @filters['quality_status'] == 'absent'
@dataset_class = @dataset_class.where('quality_status IS NULL OR quality_status = ?', @filters['quality_status'])
else
@dataset_class = @dataset_class.where(quality_status: @filters['quality_status'])
end
end
end
@records = @dataset_class.paginate(:page => params[:page], :per_page => paginate_options[:per_page])
end
else
show_search_results_for_dataset(paginate_options, sphinx_search)
end
respond_to do |wants|
wants.html
wants.xml { render :xml => @records }
wants.json { render :json => @records }
wants.js do
if current_user && current_user.has_privilege?(:power_user)
render :template => 'datasets/admin/show'
else
render :action => 'show'
end
end
end
end
def show_search_results_for_dataset(paginate_options, sphinx_search)
paginate_options[:order] = "#{paginate_options[:order]} #{paginate_options[:sort_mode]}"
sphinx_search = {options: paginate_options, query: sphinx_search}
@search = Search.find(params[:search_id])
sphinx_search = @dataset_description.build_sphinx_search(@search, sphinx_search) # TODO: move to SearchEngine
sphinx_search[:options].merge!(populate: true, :conditions => { record_status: Dataset::RecordStatus.find(:published)})
@records = @dataset_class.search(sphinx_search[:query], sphinx_search[:options])
@query_string = @search.query_string
end
# Batch update
def update
@dataset_description = DatasetDescription.find_by_id(params[:id])
@dataset_class = @dataset_description.dataset_model
if params[:record].blank?
flash[:error] = I18n.t("dataset.not_enough_records_selected")
return redirect_to(dataset_path(@dataset_description))
end
# Conditions for update
update_conditions = {}
if params[:selection] == "selected"
# The easier case. User used checkboxes to choose what
# records they want to edit.
update_conditions[:_record_id] = params[:record].map(&:to_i)
@count_updated = params[:record].count
elsif params[:selection] == "all"
if params[:search_id].present?
# Case when all search matching records should be edited.
# We wanna get all the ids of matching records and
# pass them to update statement.
# FIXME: THIS IS A NO OP!?
else
# User has chosen to edit all records and to search is
# specified. We just won't pass any options to update statement
# and just update whole dataset.
@dataset_class = @dataset_class.where(:record_status => @filters['record_status']) if @filters['record_status'].present?
@dataset_class = @dataset_class.where(:quality_status => @filters['quality_status']) if @filters['quality_status'].present?
@count_updated = @dataset_class.count
end
end
updates = {}
updates[:record_status] = params[:status] if params[:status].present?
updates[:quality_status] = params[:quality] if params[:quality].present?
# Update attributes (only if using batch edit form)
if params[:update_attribute].present? && params[:attribute_value].present?
params[:update_attribute].each do |attr_name|
updates[attr_name] = params[:attribute_value][attr_name]
end
end
update_count = @dataset_class.update_all(updates, update_conditions)
Change.create(change_type: Change::BATCH_UPDATE, user: current_user, change_details: {updates: updates, update_conditions: update_conditions, update_count: update_count})
flash[:notice] = I18n.t("dataset.batch_updated", :count => @count_updated)
params.delete(:search_id) if params[:search_id].blank? #FIXME: ewww ugly!
params.delete :page if params[:page].blank?
redirect_to(dataset_path(@dataset_description, :search_id => params[:search_id], :page => params[:page]))
end
def batch_edit
@dataset_description = DatasetDescription.find_by_id(params[:id])
@dataset_class = @dataset_description.dataset_model
@field_descriptions = @dataset_description.visible_field_descriptions
end
def sitemap
# TODO implement .. somehow ..
end
protected
def prepare_filters
if params[:clear_filters]
@filters = {}
else
@filters = params[:filters] || {}
end
session[:filters] = @filters
end
def has_filters?
@filters && !@filters.empty?
end
def prepare_subselect(table_name, sortable_columns, params, paginate_options)
subselect_parameters = {
table_name: table_name,
sort_by: sanitize_sort_column(params[:sort], sortable_columns),
sort_direction: sanitize_sort_direction(params[:dir]),
offset: (params[:page].to_i-1) * paginate_options[:per_page].to_i,
limit: paginate_options[:per_page].to_i
}
"(SELECT `_record_id` from `%{table_name}` ORDER BY `%{table_name}`.`%{sort_by}` %{sort_direction} LIMIT %{offset}, %{limit}) q" % subselect_parameters
end
def sanitize_sort_column(column, available_columns)
available_columns.include?(column) ? column : "_record_id"
end
def sanitize_sort_direction(direction)
direction.to_s.downcase == "desc" ? "desc" : "asc"
end
end