lfzawacki/musical-artifacts

View on GitHub
app/models/artifact.rb

Summary

Maintainability
A
3 hrs
Test Coverage
A
97%
require 'digest/sha2'

class Artifact < ActiveRecord::Base
    include AutoHtml

    # TODO: extract out to another file?
    # Collect activity from creates, edits and deletions
    include PublicActivity::Model
    tracked owner: Proc.new { |ctrl, model| model.set_owner_from_current_user(ctrl) },
      params: {
        changed: Proc.new { |ctrl, model| model.track_updated_parameters(ctrl) },
        name: Proc.new { |ctrl, model| model.name }
      }

    # Only track activity in these parameters
    def self.tracked_parameters
      %w{name description author file mirrors more_info_urls tag_list software_list file_format_list license}
    end

    scope :approved, -> { where(approved: true) }

    acts_as_taggable_on :software, :tags, :file_formats

    serialize :mirrors
    serialize :more_info_urls

    after_create :enqueue_notification

    # Automatically set some app_tags based on
    # the format of the uploaded file
    after_create :set_app_tags_from_format
    def set_app_tags_from_format
      apps = App.tagged_with(file_format, on: 'file_formats')
      app_tags = apps.map(&:software_list).flatten

      self.software_list.push(*app_tags)
    end

    # The creator of the artifact on the site, not the author
    belongs_to :user
    def owned_by?(user)
      self.user_id.present? && user.try(:id) == user_id
    end

    has_many :favorites

    has_many :stored_files

    validates :name, presence: true, uniqueness: true
    validates :author, presence: true

    validates :license, presence: true
    belongs_to :license

    # Search fields to be used in views, controllers, ...
    def self.search_fields
      ['license', 'tags', 'apps', 'hash', 'formats']
    end

    # If a user has had 3 or more artifacts approved it cnn be auto approved
    # TODO: Not sure if we'll keep this system, but it's here for now
    def self.approved_count_for_trust
      3
    end

    before_save :generate_file_hash
    def generate_file_hash
      if file.present? && file_hash.blank?
        self.file_hash = Digest::SHA256.hexdigest(file.file.read)
      end
      true
    end

    before_save :save_new_file
    def save_new_file
      if @new_file
        # TODO: prevent update activity on creation of artifact
        stored_files.last.save
        file_format_list.add stored_files.last.format
      end
    end

    def file= file_io
      @new_file = true
      stored_files << StoredFile.new(file: file_io)
    end

    def file
      stored_files.last.try(:file)
    end

    # Returns true if a new file has been uploaded to the artifact
    def file_changed?
      @new_file.present?
    end

    def get_file_by_name filename
      stored_files.where(file: filename).order('created_at DESC').first
    end

    def file_name
      stored_files.last.name
    end

    def file_format
      file_format_list.first
    end

    def file_format= format
      file_format_list.add format
    end

    def mirrors=m
      if m.kind_of?(String)
        write_attribute(:mirrors, m.split(/[,;]/))
      else
        write_attribute(:mirrors, m)
      end
    end

    def more_info_urls=m
      if m.kind_of?(String)
        write_attribute(:more_info_urls, m.split(/[,;]/))
      else
        write_attribute(:more_info_urls, m)
      end
    end

    def mirrors
      read_attribute(:mirrors) || []
    end

    def more_info_urls
      read_attribute(:more_info_urls) || []
    end

    # Get a markdown generated HTML from the artifact description
    def description_html
      auto_html(description) {
        html_escape
        redcarpet
        js_email
        link
      }
    end

    # Get an html escaped version but transform links into tags
    def extra_license_text_html
      auto_html(extra_license_text) {
        html_escape
        link
      }
    end

    # Get the links which can be shown as multimedia content
    def multimedia_content
      return [] if more_info_urls.blank?

      multimedia = more_info_urls.map do |link|
        auto_html(link) {
          youtube(width: 360)
          vimeo
          audio
          soundcloud(width: '100%', height: 315, show_artwork: true, show_comments: true)
          image
        }
      end

      # Links with multimedia without the normal links
      multimedia -= more_info_urls
    end

    def related max=5
      self.class
      .tagged_with(software_list | tag_list , any: true)
      .where('id NOT in(?)', self.id)
      .limit(max)
    end

    def download_path
      if stored_files.last.present?
        "/artifacts/#{to_param}/#{stored_files.last.name}"
      end
    end

    def set_owner_from_current_user controller
      controller.try(:current_user) || self.user
    end

    # Returns and array of the parameters which were just updated in this object
    def track_updated_parameters controller
      if controller.present? && controller.action_name == 'update'
        changed = self.changes.keys & Artifact.tracked_parameters

        # file is not really an artifact attribute, so adding it separetely
        changed << 'file' if self.file_changed?

        changed
      end
    end

    private

    def enqueue_notification
      Resque.enqueue(ArtifactCreatedNotificationWorker, self.id)
    end
end