app/controllers/media_resources_controller.rb

Summary

Maintainability
B
5 hrs
Test Coverage
# -*- encoding : utf-8 -*-

##
# MediaResources are the core content of MAdeK. They are seperated in MediaEntries and MediaSets (Collection of MediaResources).
# 
class MediaResourcesController < ApplicationController

  include Concerns::PreviousIdRedirect
  include Concerns::CustomUrls

  before_filter :except => [:index, :collection, :destroy] do
    unless (params[:media_resource_id] ||= params[:id] || params[:media_resource_ids] || params[:collection_id]).blank?
      action = case request[:action].to_sym
        when :edit
          :edit
        else
          :view
      end
      begin
        @media_resource = if params[:collection_id]
          MediaResource.accessible_by_user(current_user, action).find(MediaResource.by_collection(params[:collection_id]))
        else
          MediaResource.accessible_by_user(current_user, action).find(params[:media_resource_id])
        end
      rescue
        raise UserForbiddenError unless current_user.login.nil?
        raise UserUnauthorizedError
      end
    end
  end


  def index()

    with_filter = params[:with_filter]
    with = params[:with] || {}
    sort = params[:sort]
    page = params[:page]
    per_page = [(params[:per_page] || PER_PAGE.first).to_i.abs, PER_PAGE.last].min

    @filter = MediaResource.get_filter_params params

    respond_to do |format|
      format.html { @media_resources_count = MediaResource.accessible_by_user(current_user,:view).count }
      format.json {
        resources = MediaResource.filter(current_user, @filter).ordered_by(sort)

        h = case with_filter

            when "true"
              view_context.hash_for_media_resources_with_pagination(resources, \
                      {:page => page, :per_page => per_page}, with, false) \
                      .merge({:filter => view_context.hash_for_filter(resources)})

            when "only"
              {:filter => view_context.hash_for_filter(resources)}
          
            else
              view_context.hash_for_media_resources_with_pagination(resources, \
                {:page => page, :per_page => per_page}, with, false)

          end

        render json: h.merge(:current_filter => @filter).to_json
      }
    end
  end

  def show
    flash.keep
    case @media_resource
    when FilterSet
      redirect_to filter_set_path(@media_resource)
    when MediaEntry, MediaEntryIncomplete
      redirect_to media_entry_path(@media_resource)
    when MediaSet
      redirect_to media_set_path(@media_resource)
    else
      raise "missing dispatch on #{@media_resource.type}"
    end
  end

  def browse
    @browsable_meta_terms = []
    @media_resource.meta_data.for_meta_terms.each do |meta_datum|
      meta_datum.value.each do |meta_term|
        count = MediaResource.filter(current_user, {:meta_data => {meta_datum.meta_key.label.to_sym => {:ids => [meta_term.id]}}}).where("media_resources.id != ?", @media_resource.id).count
        if count > 0
          data = {:meta_term => meta_term, :meta_datum => meta_datum, :count => count}
          if @media_resource.individual_contexts[0] and @media_resource.individual_contexts[0].meta_keys.where(:id => meta_datum.meta_key).exists?
            @browsable_meta_terms.unshift data
          else
            @browsable_meta_terms.push data
          end
        end
      end
    end
  end

  def edit
    @contexts =
      case @media_resource
      when MediaEntry
        Context.defaults + @media_resource.individual_contexts
      when MediaSet, FilterSet
        [Context.find_by_id(:media_set)]
      else
        raise "Add the class #{@media_resource.class} to dispatching"
      end

    @meta_data = {}
    @contexts.each {|context| @meta_data[context.id] = @media_resource.meta_data.for_context(context) }
  end


  def destroy
    begin
      ActiveRecord::Base.transaction do
        if MediaResource.where(id: params[:id]).empty?
          render json: {}, status: 204
        elsif (media_resource=MediaResource.find(params[:id])) and current_user.authorized?(:delete, media_resource)
          media_resource.destroy
          render json: {}, status: 204
        else 
          render json: {}, status: 403
        end
      end
    rescue Exception => e
      logger.error Formatter.error_to_s e
      render json: {}, status: 422 
    end
  end

  ########################################################################

  def collection(ids = params[:ids] || raise("ids are required"),
                 relation = params[:relation],
                 collection_id = params[:collection_id])
    if request.post? and ids
      ids = case relation
        when "parents"
          MediaResource.where(:id => ids).flat_map do |child|
            child.parent_sets.accessible_by_user(current_user,:view).pluck("media_resources.id")
          end.uniq
        else
          ids
      end

      collection = Collection.add ids, collection_id
    end

    respond_to do |format|
      format.json { render json: {collection_id: collection[:id]} }
    end
  end

###################################################################################

  def toggle_favorites
    current_user.favorites.toggle(@media_resource)
    respond_to do |format|
      format.js { render :partial => "favorite_link", :locals => {:media_resource => @media_resource} }
    end
  end

  # NOTE: "204 No content" with not body would be correct,
  # but it triggers a bug in firefox.
  # workaorund: always include dummy json so we can send '200'
  # https://bugzilla.mozilla.org/show_bug.cgi?id=521301
  # (Also, disfavor should be DELETE but the bug would be same)
  def favor
    current_user.favorites.favor(@media_resource)
    respond_to do |format|
      format.json { render :json => {ok: true}, :status => 200 }
    end
  end

  def disfavor
    current_user.favorites.disfavor(@media_resource)
    respond_to do |format|
      format.json { render :json => {ok: true}, :status => 200 }
    end
  end


  def parents()

    parent_media_set_ids = params[:parent_media_set_ids]
    parent_media_sets = MediaSet.accessible_by_user(current_user, :edit).find(parent_media_set_ids)
    child_resources = Array(@media_resource)

    child_resources.each do |resource|
      if request.post?
        (parent_media_sets - resource.parent_sets).each do |parent_media_set|
          resource.parent_sets << parent_media_set
          if resource.is_a? MediaSet
            individual_contexts = parent_media_set.individual_contexts.reject{|context| resource.individual_contexts.include? context}
            resource.individual_contexts << individual_contexts unless individual_contexts.blank?
          end
        end
      elsif request.delete?
        parent_media_sets.each do |parent_media_set|
          resource.parent_sets.delete(parent_media_set)
          if resource.is_a? MediaSet
            resource.individual_contexts = resource.individual_contexts.reject{|context| not resource.inheritable_contexts.include? context}
          end
        end
      end
    end
    flash[:notice] = "Zusammenhänge aktualisiert."
    respond_to do |format|
      format.json {
        render :json => view_context.json_for(child_resources, {:parents => true})
      }
    end
  end

###################################################################################


  def image(size = (params[:size] || :large).to_sym)

    if size == :maximum and not current_user.authorized? :download, @media_resource
      size = :x_large
    end

    # TODO dry => Resource#thumb_base64 and Download audio/video
    media_file = @media_resource.get_media_file(current_user)

    if (not media_file) and @media_resource.is_a? MediaSet or (not media_file)
      # empty gif pixel
      output = "R0lGODlhAQABAIAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==\n"
      send_data Base64.decode64(output), :type => "image/gif", :disposition => 'inline'
    else
      preview = media_file.get_preview(size, "image/jpeg")
      if preview and File.exist?(file = File.join(THUMBNAIL_STORAGE_DIR, media_file.shard, preview.filename))
        output = File.read(file)
        send_data output, :type => preview.content_type, :disposition => 'inline'
      else
        output = media_file.thumb_placeholder(size)
        send_data output, :type => "image/png", :disposition => 'inline'
      end
    end
  end  

end