Skip to content

Instantly share code, notes, and snippets.

@walterdavis
Created May 3, 2015 16:52
Show Gist options
  • Save walterdavis/3184e5eca1ffc2c3420c to your computer and use it in GitHub Desktop.
Save walterdavis/3184e5eca1ffc2c3420c to your computer and use it in GitHub Desktop.
class Asset < ActiveRecord::Base
versioned :if => :really_create_a_version?
belongs_to :user
belongs_to :project, touch: true
has_many :notes, dependent: :destroy
has_many :slides, dependent: :destroy
has_many :approvals, dependent: :destroy, inverse_of: :asset
belongs_to :last_editor, class_name: 'User'
has_many :cart_items, dependent: :destroy, as: 'item'
has_attached_file :blob,
:url => "/system/blobs/:id/:style/:basename-:version.:extension",
:path => ":rails_root/public:url",
:preserve_files => true,
:styles => Proc.new { |a| a.instance.file_styles(a.instance) }, :processors => Proc.new { |a| a.processors(a) },
:convert_options => {
:thumb => "-quality 75 -strip" }
validates_attachment_content_type :blob, :content_type => /\A.*\Z/
validates_with AttachmentPresenceValidator, :attributes => :blob
def really_create_a_version?
self.blob.dirty?
end
before_save :extract_dimensions
before_create :set_key
after_save :set_up_approvals
def set_up_approvals
project.approvers.each do |a|
approval = self.approvals.find_or_create_by(version_number: version, initials: a.initials, name: a.name, user_id: a.id)
approval.status = nil
approval.save
end
end
def search_label
@search_label ||= "<b>Asset: #{label}</b>#{project.campaign.name} / #{project.name} (#{user.name})".html_safe
end
def file_styles(a)
if a.video?
return { :thumb => { :geometry => "200x200>", :format => 'jpg', :time => 1 }, :medium => { :geometry => "1280x720>", :format => 'jpg', :time => 1 }, :mp4 => { :geometry => "1280x720>", :format => :mp4, :streaming => true } }
end
if a.photo?
return { :thumb => ["200x200>", :png], :medium => ["1500x1500>", :jpg] }
end
if a.audio?
return { :wav => ['audio', :wav], :mp3 => ['audio', :mp3] }
end
{}
end
def template
return 'assets/video' if video?
return 'assets/audio' if audio?
return 'assets/photo' if photo?
return 'assets/flash' if flash?
return 'assets/binary'
end
def icon
return blob.url(:thumb, timestamp: false) if video?
return blob.url(:thumb, timestamp: false) if photo?
return '/assets/icons/audio.png' if audio?
return '/assets/icons/flash.png' if flash?
return '/assets/icons/generic.png'
end
def ext
@ext ||= blob_file_name.split('.').last.upcase
end
def processors(a)
if a.photo?
return [ :thumbnail ]
end
if a.video?
return [:ffmpeg, :qtfaststart]
end
if a.audio?
return [ :audio ]
end
[]
end
def video?
[ 'application/x-mp4', 'video/mpeg', 'video/quicktime',
'video/x-la-asf', 'video/x-ms-asf', 'video/x-msvideo',
'video/x-sgi-movie', 'video/x-flv', 'video/x-m4v',
'flv-application/octet-stream', 'video/3gpp', 'video/3gpp2',
'video/3gpp-tt', 'video/bmpeg', 'video/bt656', 'video/celb',
'video/dv', 'video/h261', 'video/h263', 'video/h263-1998',
'video/h263-2000', 'video/h264', 'video/jpeg', 'video/mj2',
'video/mp1s', 'video/mp2p', 'video/mp2t', 'video/mp4',
'video/mp4v-es', 'video/mpv', 'video/mpeg4', 'video/mpeg4-generic',
'video/nv', 'video/parityfec', 'video/pointer',
'video/raw', 'video/rtx' ].include?(blob_content_type.to_s.downcase)
end
def photo?
[ 'application/pdf',
'application/postscript',
'application/x-photoshop' ].include?(blob_content_type.to_s.downcase) || blob_content_type.to_s.downcase.include?( 'image' )
end
def audio?
['audio/mpeg', 'audio/x-wav', 'audio/x-aiff', 'audio/ogg'].include?(blob_content_type.to_s.downcase)
end
def flash?
blob_content_type.to_s.downcase.match(/(shockwave|flash)/)
end
def zip?
blob_content_type.to_s.downcase.match(/zip/)
end
def public_url
blob.url(:original, timestamp: false)
end
def blob_remote_url=(url_value)
self.blob = URI.parse(url_value)
# Assuming url_value is http://example.com/photos/face.png
# avatar_file_name == "face.png"
# avatar_content_type == "image/png"
@blob_remote_url = url_value
end
def label
@label ||= begin
return title if title.present?
File.basename(blob_file_name.to_s, '.*').gsub('_', ' ')
end
end
def to_param
key
end
def max_version
@max_version ||= versions.length + 1
end
def prev_version
@prev_version ||= versions.where('number < ?', version).order(:number).last.number rescue 1
end
def next_version
@next_version ||= versions.where('number > ?', version).order(:number).first.number rescue false
end
private
Paperclip.interpolates :version do |attachment, style|
attachment.instance.version
end
# Retrieves dimensions for image assets
# @note Do this after resize operations to account for auto-orientation.
def extract_dimensions
return unless (photo? || video? || flash?)
tempfile = blob.queued_for_write[:original]
unless tempfile.nil?
if flash?
# extract dimensions from filename
blob_file_name.match(/(\d+?)x(\d+?)[^\d]/) do
self.blob_width = "#{$1}".to_i
self.blob_height = "#{$2}".to_i
end
else
geometry = Paperclip::Geometry.from_file(tempfile)
self.blob_width = geometry.width.to_i
self.blob_height = geometry.height.to_i
end
end
end
def set_key
self.key = begin
loop do
token = Devise.friendly_token
break token unless Asset.where(key: token).first
end
end
end
end
class AssetsController < ApplicationController
before_action :set_asset, only: [:show, :version, :download, :edit, :update, :destroy]
after_action :add_to_user_projects, only: [:create, :update]
respond_to :html, :js
def index
@assets = Asset.all
respond_with(@assets)
end
def show
@notes = @asset.notes.order('created_at desc')
@note = Note.new(asset: @asset, asset_version: @asset.version)
@lightboxes = Lightbox.user_list(current_user) if user_signed_in?
@approvals = @asset.approvals.where('version_number = ?', @asset.version)
respond_with(@asset)
end
def version
@notes = @asset.notes.order('created_at desc')
@asset.revert_to(params[:v].to_i)
@approvals = @asset.approvals.where('version_number = ?', @asset.version)
@note = Note.new(asset: @asset, asset_version: @asset.version)
@lightboxes = Lightbox.user_list(current_user)
respond_with(@asset)
end
def download
@asset.revert_to(params[:v])
require 'open-uri'
data = open(@asset.blob.url).read
send_data data, :disposition => :attachment, :filename => @asset.blob_file_name
end
def new
@asset = Asset.new(project_id: params[:project_id])
respond_with(@asset)
end
def edit
end
def create
@asset = Asset.new(asset_params)
@asset.user = current_user
@asset.last_editor_id = current_user.id
@asset.save
respond_with(@asset)
end
def update
@asset.last_editor_id = current_user.id
@asset.update(asset_params)
respond_with(@asset)
end
def destroy
@asset.destroy
respond_with(@asset.project)
end
private
def add_to_user_projects
@project_ids = current_user.project_ids.push(@asset.project_id).uniq
current_user.project_ids = []
current_user.project_ids = @project_ids
end
def set_asset
@asset = Asset.includes(:project).find_by!(key: params[:id])
end
def asset_params
params.require(:asset).permit(:blob, :user_id, :project_id, :title, :description, :version)
end
end
class Project < ActiveRecord::Base
belongs_to :user
belongs_to :campaign
has_many :assets, dependent: :destroy
has_many :notes, dependent: :destroy
has_many :current_projects, dependent: :destroy
has_many :users, through: :current_projects
has_many :authorities
has_many :approvers, through: :authorities
before_save :add_extra_users
validates_presence_of :name, :on => :create, :message => "can't be blank"
def search_label
@search_label ||= "<b>Project: #{name}</b>#{project_type}".html_safe
end
def label
@label ||= name
end
def public_url
Rails.application.routes.url_helpers.url_for(
controller: 'projects',
action: 'show',
id: id,
only_path: false
)
end
def icon
@icon ||= begin
if assets.first && assets.first.blob.present?
assets.first.blob.url(:thumb, timestamp: false)
else
Rails.application.routes.url_helpers.url_for(
action: :show, controller: :assets,
id: 'spike.png', only_path: false
)
end
end
end
def add_extra_users
proxy_ids = self.approvers.map(&:proxy_ids).flatten.uniq
@list = (self.user_ids + self.approver_ids + proxy_ids + [self.user_id]).uniq
self.user_ids = []
self.user_ids = @list
assets.each do |a|
a.send :set_up_approvals
end
end
end
Rails.application.routes.draw do
resource :cart, only: [:show, :update, :destroy, :share, :download] do
collection do
get 'download'
get 'share'
post 'remove_all'
end
end
resources :notes, only: [:create]
resources :slides
resources :lightboxes do
member do
post 'sort', to: 'lightboxes#sort'
post 'add_slides', to: 'lightboxes#add_slides'
end
end
resources :shared_items, only: [:new, :create, :share, :destroy, :download, :show] do
member do
post 'share'
get 'download'
end
end
devise_for :users, :controllers => { :invitations => 'users/invitations' }
match 'users/:id/projects', to: 'projects#user', via: 'get', as: 'user_projects'
resources :users, :only => [:edit, :show, :destroy, :update, :index, :lookup, :dashboard] do
collection do
get 'dashboard'
end
end
get 'messages/feedback', to: 'messages#feedback', as: 'feedback'
post 'messages/send_feedback', to: 'messages#send_feedback'
get 'messages/link', to: 'messages#link', as: 'link'
post 'messages/send_link', to: 'messages#send_link', as: 'send_link'
get 'messages/multiple', to: 'messages#multiple', as: 'multiple'
post 'messages/send_multiple', to: 'messages#send_multiple', as: 'send_multiple'
post 'messages/person/:id', to: 'messages#person', as: 'messages_person'
resources :search, only: 'index'
resources :assets do
member do
get 'version/:v', to: 'assets#version', as: 'version'
get 'download/:v', to: 'assets#download', as: 'download'
end
resources :notes
end
post 'approvals/:id', to: 'approvals#update', as: 'approve'
resources :campaigns do
resources :projects, shallow: true
collection do
get 'archives'
end
end
root :to => redirect('/users/dashboard')
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment