chili_videos 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. data.tar.gz.sig +1 -0
  2. data/.autotest +5 -0
  3. data/Gemfile +13 -0
  4. data/Gemfile.lock +33 -0
  5. data/History.txt +4 -0
  6. data/LICENSE +20 -0
  7. data/Manifest.txt +63 -0
  8. data/README.md +169 -0
  9. data/Rakefile +45 -0
  10. data/app/controllers/videos_controller.rb +72 -0
  11. data/app/helpers/videos_helper.rb +34 -0
  12. data/app/models/assembly.rb +62 -0
  13. data/app/models/assembly_observer.rb +6 -0
  14. data/app/models/assembly_processor.rb +16 -0
  15. data/app/models/video.rb +24 -0
  16. data/app/views/settings/_settings.html.erb +13 -0
  17. data/app/views/videos/edit.html.erb +32 -0
  18. data/app/views/videos/index.html.erb +37 -0
  19. data/app/views/videos/new.html.erb +41 -0
  20. data/app/views/videos/plugin_not_configured.html.erb +6 -0
  21. data/app/views/videos/show.html.erb +40 -0
  22. data/app/views/videos/upload_complete.html.erb +7 -0
  23. data/assets/player.swf +0 -0
  24. data/assets/readme.html +84 -0
  25. data/assets/stylesheets/forms.css +7 -0
  26. data/assets/stylesheets/videos.css +76 -0
  27. data/assets/swfobject.js +8 -0
  28. data/assets/yt.swf +0 -0
  29. data/autotest/discover.rb +4 -0
  30. data/bin/delayed_job +23 -0
  31. data/config/locales/en.yml +15 -0
  32. data/config/routes.rb +3 -0
  33. data/db/migrate/20110301025054_create_videos.rb +15 -0
  34. data/db/migrate/20110309060901_create_assemblies.rb +14 -0
  35. data/db/migrate/20110314022354_create_delayed_jobs.rb +21 -0
  36. data/db/migrate/20110402043115_create_slugs.rb +18 -0
  37. data/db/migrate/20110402053931_add_slug_cache_to_videos.rb +11 -0
  38. data/init.rb +63 -0
  39. data/lang/en.yml +16 -0
  40. data/lib/chili_videos.rb +18 -0
  41. data/lib/chili_videos/config.rb +40 -0
  42. data/lib/chili_videos/error.rb +5 -0
  43. data/lib/tasks/chili_videos_tasks.rb +112 -0
  44. data/lib/tasks/contributor_tasks.rb +64 -0
  45. data/lib/tasks/delayed_job.rake +6 -0
  46. data/lib/tasks/friendly_id.rake +19 -0
  47. data/lib/video_project_patch.rb +10 -0
  48. data/lib/video_user_patch.rb +10 -0
  49. data/lib/video_version_patch.rb +9 -0
  50. data/rails/delayed_job +25 -0
  51. data/rails/init.rb +1 -0
  52. data/test/fixtures/incomplete_assembly.json +9 -0
  53. data/test/fixtures/single_video_processed_assembly.json +9 -0
  54. data/test/fixtures/standard_transloadit_response.json +6 -0
  55. data/test/functional/videos_controller_test.rb +232 -0
  56. data/test/integration/project_video_list_test.rb +104 -0
  57. data/test/integration/project_video_uploading_test.rb +56 -0
  58. data/test/integration/viewing_project_video_test.rb +74 -0
  59. data/test/test_helper.rb +77 -0
  60. data/test/unit/assembly_processor_test.rb +57 -0
  61. data/test/unit/assembly_test.rb +95 -0
  62. data/test/unit/chili_video_plugin/config_test.rb +49 -0
  63. data/test/unit/chili_video_plugin_test.rb +30 -0
  64. data/test/unit/video_test.rb +26 -0
  65. metadata +279 -0
  66. metadata.gz.sig +0 -0
@@ -0,0 +1,8 @@
1
+ /**
2
+ * SWFObject v1.5: Flash Player detection and embed - http://blog.deconcept.com/swfobject/
3
+ *
4
+ * SWFObject is (c) 2007 Geoff Stearns and is released under the MIT License:
5
+ * http://www.opensource.org/licenses/mit-license.php
6
+ *
7
+ */
8
+ if(typeof deconcept=="undefined"){var deconcept=new Object();}if(typeof deconcept.util=="undefined"){deconcept.util=new Object();}if(typeof deconcept.SWFObjectUtil=="undefined"){deconcept.SWFObjectUtil=new Object();}deconcept.SWFObject=function(_1,id,w,h,_5,c,_7,_8,_9,_a){if(!document.getElementById){return;}this.DETECT_KEY=_a?_a:"detectflash";this.skipDetect=deconcept.util.getRequestParameter(this.DETECT_KEY);this.params=new Object();this.variables=new Object();this.attributes=new Array();if(_1){this.setAttribute("swf",_1);}if(id){this.setAttribute("id",id);}if(w){this.setAttribute("width",w);}if(h){this.setAttribute("height",h);}if(_5){this.setAttribute("version",new deconcept.PlayerVersion(_5.toString().split(".")));}this.installedVer=deconcept.SWFObjectUtil.getPlayerVersion();if(!window.opera&&document.all&&this.installedVer.major>7){deconcept.SWFObject.doPrepUnload=true;}if(c){this.addParam("bgcolor",c);}var q=_7?_7:"high";this.addParam("quality",q);this.setAttribute("useExpressInstall",false);this.setAttribute("doExpressInstall",false);var _c=(_8)?_8:window.location;this.setAttribute("xiRedirectUrl",_c);this.setAttribute("redirectUrl","");if(_9){this.setAttribute("redirectUrl",_9);}};deconcept.SWFObject.prototype={useExpressInstall:function(_d){this.xiSWFPath=!_d?"expressinstall.swf":_d;this.setAttribute("useExpressInstall",true);},setAttribute:function(_e,_f){this.attributes[_e]=_f;},getAttribute:function(_10){return this.attributes[_10];},addParam:function(_11,_12){this.params[_11]=_12;},getParams:function(){return this.params;},addVariable:function(_13,_14){this.variables[_13]=_14;},getVariable:function(_15){return this.variables[_15];},getVariables:function(){return this.variables;},getVariablePairs:function(){var _16=new Array();var key;var _18=this.getVariables();for(key in _18){_16[_16.length]=key+"="+_18[key];}return _16;},getSWFHTML:function(){var _19="";if(navigator.plugins&&navigator.mimeTypes&&navigator.mimeTypes.length){if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","PlugIn");this.setAttribute("swf",this.xiSWFPath);}_19="<embed type=\"application/x-shockwave-flash\" src=\""+this.getAttribute("swf")+"\" width=\""+this.getAttribute("width")+"\" height=\""+this.getAttribute("height")+"\" style=\""+this.getAttribute("style")+"\"";_19+=" id=\""+this.getAttribute("id")+"\" name=\""+this.getAttribute("id")+"\" ";var _1a=this.getParams();for(var key in _1a){_19+=[key]+"=\""+_1a[key]+"\" ";}var _1c=this.getVariablePairs().join("&");if(_1c.length>0){_19+="flashvars=\""+_1c+"\"";}_19+="/>";}else{if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","ActiveX");this.setAttribute("swf",this.xiSWFPath);}_19="<object id=\""+this.getAttribute("id")+"\" classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" width=\""+this.getAttribute("width")+"\" height=\""+this.getAttribute("height")+"\" style=\""+this.getAttribute("style")+"\">";_19+="<param name=\"movie\" value=\""+this.getAttribute("swf")+"\" />";var _1d=this.getParams();for(var key in _1d){_19+="<param name=\""+key+"\" value=\""+_1d[key]+"\" />";}var _1f=this.getVariablePairs().join("&");if(_1f.length>0){_19+="<param name=\"flashvars\" value=\""+_1f+"\" />";}_19+="</object>";}return _19;},write:function(_20){if(this.getAttribute("useExpressInstall")){var _21=new deconcept.PlayerVersion([6,0,65]);if(this.installedVer.versionIsValid(_21)&&!this.installedVer.versionIsValid(this.getAttribute("version"))){this.setAttribute("doExpressInstall",true);this.addVariable("MMredirectURL",escape(this.getAttribute("xiRedirectUrl")));document.title=document.title.slice(0,47)+" - Flash Player Installation";this.addVariable("MMdoctitle",document.title);}}if(this.skipDetect||this.getAttribute("doExpressInstall")||this.installedVer.versionIsValid(this.getAttribute("version"))){var n=(typeof _20=="string")?document.getElementById(_20):_20;n.innerHTML=this.getSWFHTML();return true;}else{if(this.getAttribute("redirectUrl")!=""){document.location.replace(this.getAttribute("redirectUrl"));}}return false;}};deconcept.SWFObjectUtil.getPlayerVersion=function(){var _23=new deconcept.PlayerVersion([0,0,0]);if(navigator.plugins&&navigator.mimeTypes.length){var x=navigator.plugins["Shockwave Flash"];if(x&&x.description){_23=new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/,"").replace(/(\s+r|\s+b[0-9]+)/,".").split("."));}}else{if(navigator.userAgent&&navigator.userAgent.indexOf("Windows CE")>=0){var axo=1;var _26=3;while(axo){try{_26++;axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+_26);_23=new deconcept.PlayerVersion([_26,0,0]);}catch(e){axo=null;}}}else{try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");}catch(e){try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");_23=new deconcept.PlayerVersion([6,0,21]);axo.AllowScriptAccess="always";}catch(e){if(_23.major==6){return _23;}}try{axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");}catch(e){}}if(axo!=null){_23=new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));}}}return _23;};deconcept.PlayerVersion=function(_29){this.major=_29[0]!=null?parseInt(_29[0]):0;this.minor=_29[1]!=null?parseInt(_29[1]):0;this.rev=_29[2]!=null?parseInt(_29[2]):0;};deconcept.PlayerVersion.prototype.versionIsValid=function(fv){if(this.major<fv.major){return false;}if(this.major>fv.major){return true;}if(this.minor<fv.minor){return false;}if(this.minor>fv.minor){return true;}if(this.rev<fv.rev){return false;}return true;};deconcept.util={getRequestParameter:function(_2b){var q=document.location.search||document.location.hash;if(_2b==null){return q;}if(q){var _2d=q.substring(1).split("&");for(var i=0;i<_2d.length;i++){if(_2d[i].substring(0,_2d[i].indexOf("="))==_2b){return _2d[i].substring((_2d[i].indexOf("=")+1));}}}return "";}};deconcept.SWFObjectUtil.cleanupSWFs=function(){var _2f=document.getElementsByTagName("OBJECT");for(var i=_2f.length-1;i>=0;i--){_2f[i].style.display="none";for(var x in _2f[i]){if(typeof _2f[i][x]=="function"){_2f[i][x]=function(){};}}}};if(deconcept.SWFObject.doPrepUnload){if(!deconcept.unloadSet){deconcept.SWFObjectUtil.prepUnload=function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){};window.attachEvent("onunload",deconcept.SWFObjectUtil.cleanupSWFs);};window.attachEvent("onbeforeunload",deconcept.SWFObjectUtil.prepUnload);deconcept.unloadSet=true;}}if(!document.getElementById&&document.all){document.getElementById=function(id){return document.all[id];};}var getQueryParamValue=deconcept.util.getRequestParameter;var FlashObject=deconcept.SWFObject;var SWFObject=deconcept.SWFObject;
Binary file
@@ -0,0 +1,4 @@
1
+ Autotest.add_discovery do
2
+ "rails"
3
+ end
4
+
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- ruby -*-
3
+ require 'rubygems'
4
+ require 'daemon_spawn'
5
+
6
+ class DelayedJobWorker < DaemonSpawn::Base
7
+ def start(args)
8
+ ENV['RAILS_ENV'] ||= args.first || 'development'
9
+ Dir.chdir ENV['RAILS_ROOT']
10
+ require File.join('config', 'environment')
11
+
12
+ Delayed::Worker.new.start
13
+ end
14
+
15
+ def stop
16
+ system("kill `cat #{ENV['RAILS_ROOT']}/tmp/pids/delayed_job.pid`")
17
+ end
18
+ end
19
+
20
+ DelayedJobWorker.spawn!(:log_file => File.join(ENV['RAILS_ROOT'], "log", "delayed_job.log"),
21
+ :pid_file => File.join(ENV['RAILS_ROOT'], 'tmp', 'pids', 'delayed_job.pid'),
22
+ :sync_log => true,
23
+ :working_dir => ENV['RAILS_ROOT'])
@@ -0,0 +1,15 @@
1
+ # English strings go here for Rails i18n
2
+ en:
3
+ permission_view_video_list: View video list
4
+ permission_view_specific_video: View specific video
5
+ permission_modify_videos: Modify videos
6
+ permission_delete_video: Delete videos
7
+ permission_add_video: Add videos
8
+ transloadit_video_directions: Enter the Transload.it API key and the workflow you would like to use below.
9
+ transloadit_api_key_label: Transload.it API key
10
+ transloadit_workflow_label: Workflow
11
+ new_video_label: Add video
12
+ delete_video_label: Delete this video
13
+ edit_video_label: Edit this video
14
+ confirm_video_deletion: Are you sure you want to delete this video?
15
+ video_deleted_message: "Booyah! The requested video has been deleted."
@@ -0,0 +1,3 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.resources :videos, :name_prefix => 'project_', :path_prefix => '/projects/:project_id', :collection => {:upload_complete => :get}
3
+ end
@@ -0,0 +1,15 @@
1
+ class CreateVideos < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :videos do |t|
4
+ t.column :title, :string
5
+ t.column :description, :text
6
+ t.column :url, :text
7
+ t.integer :project_id, :user_id, :version_id, :duration, :height, :width
8
+ t.timestamps
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ drop_table :videos
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ class CreateAssemblies < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :assemblies do |t|
4
+ t.integer :project_id, :unsigned => true
5
+ t.integer :user_id, :unsigned => true
6
+ t.string :assembly_id, :assembly_url
7
+ t.boolean :processed
8
+ end
9
+ end
10
+
11
+ def self.down
12
+ drop_table :assemblies
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ class CreateDelayedJobs < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :delayed_jobs, :force => true do |table|
4
+ table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue
5
+ table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually.
6
+ table.text :handler # YAML-encoded string of the object that will do work
7
+ table.text :last_error # reason for last failure (See Note below)
8
+ table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
9
+ table.datetime :locked_at # Set when a client is working on this object
10
+ table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
11
+ table.string :locked_by # Who is working on this object (if locked)
12
+ table.timestamps
13
+ end
14
+
15
+ add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority'
16
+ end
17
+
18
+ def self.down
19
+ drop_table :delayed_jobs
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ class CreateSlugs < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :slugs do |t|
4
+ t.string :name
5
+ t.integer :sluggable_id
6
+ t.integer :sequence, :null => false, :default => 1
7
+ t.string :sluggable_type, :limit => 40
8
+ t.string :scope
9
+ t.datetime :created_at
10
+ end
11
+ add_index :slugs, :sluggable_id
12
+ add_index :slugs, [:name, :sluggable_type, :sequence, :scope], :name => "index_slugs_on_n_s_s_and_s", :unique => true
13
+ end
14
+
15
+ def self.down
16
+ drop_table :slugs
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ class AddSlugCacheToVideos < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :videos, :cached_slug, :string
4
+ add_index :videos, :cached_slug, :unique => true
5
+ end
6
+
7
+ def self.down
8
+ remove_index :videos, :column => :cached_slug
9
+ remove_column :videos, :cached_slug
10
+ end
11
+ end
data/init.rb ADDED
@@ -0,0 +1,63 @@
1
+ require 'redmine'
2
+ require 'chili_videos'
3
+
4
+ # Patches to the Redmine core.
5
+ require 'dispatcher'
6
+ require 'videos_helper'
7
+
8
+ Dispatcher.to_prepare :question_plugin do
9
+ require_dependency 'project'
10
+ Project.send(:include, VideoProjectPatch) unless Project.included_modules.include? VideoProjectPatch
11
+
12
+ require_dependency 'user'
13
+ User.send(:include, VideoUserPatch) unless User.included_modules.include? VideoUserPatch
14
+
15
+ require_dependency 'version'
16
+ Version.send(:include, VideoVersionPatch) unless Version.included_modules.include? VideoVersionPatch
17
+ end
18
+
19
+
20
+ Redmine::Plugin.register :chili_videos do
21
+ name 'Chili Videos plugin'
22
+ author 'Tom Kersten'
23
+ description 'Adds support for using the Transload.it service to transcode videos and associate them with projects.'
24
+ version ChiliVideos::VERSION
25
+ url 'http://example.com/path/to/plugin'
26
+ author_url 'http://tomkersten.com/'
27
+
28
+ project_module :videos do
29
+ permission :view_video_list, :videos => :index
30
+ permission :view_specific_video, :videos => :show
31
+ permission :modify_videos, :videos => [:edit,:update]
32
+ permission :delete_video, :videos => :destroy
33
+ permission :add_video, :videos => [:new, :create, :upload_complete]
34
+ end
35
+
36
+ settings :default => {:transloadit_api_key => '', :transloadit_workflow => ''}, :partial => 'settings/settings'
37
+
38
+ menu :project_menu, :videos, { :controller => 'videos', :action => 'index' }, :caption => 'Videos', :param => :project_id
39
+
40
+ ActiveRecord::Base.observers << :assembly_observer
41
+ end
42
+
43
+ Redmine::WikiFormatting::Macros.register do
44
+ desc "Embeds a flv file into flash video player.\n" +
45
+ "Usage examples:\n\n" +
46
+ " !{{video(id)}}\n"
47
+ macro :video do |o, args|
48
+ video_id = args[0]
49
+ size = args[1] || :standard
50
+
51
+ video = Video.find(video_id)
52
+ if video
53
+ file_url = video.url
54
+ else
55
+ file_url = "im_not_a_video"
56
+ end
57
+
58
+ <<END
59
+ <div class="video-cell large" id="video_#{video.to_param}"></div>
60
+ #{VideosHelper.video_embed_code(video, size)}
61
+ END
62
+ end
63
+ end
@@ -0,0 +1,16 @@
1
+
2
+
3
+ permission_view_video_list: View video list
4
+ permission_view_specific_video: View specific video
5
+ permission_modify_videos: Modify videos
6
+ permission_delete_video: Delete videos
7
+ permission_add_video: Add videos
8
+ transloadit_video_directions: Enter the Transload.it API key and the workflow you would like to use below.
9
+ transloadit_api_key_label: Transload.it API key
10
+ transloadit_workflow_label: Workflow
11
+ default_video_title: (none provided)
12
+ new_video_label: Add video
13
+ delete_video_label: Delete this video
14
+ edit_video_label: Edit this video
15
+ confirm_video_deletion: Are you sure you want to delete this video?
16
+ video_deleted_message: "Booyah! The requested video has been deleted."
@@ -0,0 +1,18 @@
1
+ require 'httparty'
2
+ require 'hashie'
3
+ require 'friendly_id'
4
+
5
+ require 'delayed_job'
6
+ Delayed::Worker.backend = :active_record
7
+
8
+ require 'chili_videos/config'
9
+
10
+ module ChiliVideos
11
+ extend self
12
+
13
+ VERSION = '0.1.0' unless defined?(ChiliVideos::VERSION)
14
+
15
+ def configured?
16
+ !Config.api_key.blank? && !Config.workflow.blank?
17
+ end
18
+ end
@@ -0,0 +1,40 @@
1
+ module ChiliVideos
2
+ module Config
3
+ extend self
4
+
5
+ PLUGIN_KEYNAME = 'plugin_chili_videos'
6
+ API_KEY_KEYNAME = 'transloadit_api_key'
7
+ WORKFLOW_KEYNAME = 'transloadit_workflow'
8
+
9
+ def api_key
10
+ plugin_settings[API_KEY_KEYNAME]
11
+ end
12
+
13
+ def workflow
14
+ plugin_settings[WORKFLOW_KEYNAME]
15
+ end
16
+
17
+ # Accepts anything which responds to '[]' and '.has_key?' # (Hash-like objects)
18
+ #
19
+ # Requires & utilizes the following keys
20
+ # - :api_key
21
+ # - :workflow
22
+ def update(options)
23
+ unless options.has_key?(:api_key) && options.has_key?(:workflow)
24
+ raise ArgumentError, "Missing key(s) in: #{options.inspect}"
25
+ end
26
+ Setting[PLUGIN_KEYNAME] = formatted_hash(options[:api_key], options[:workflow])
27
+ true
28
+ end
29
+
30
+ private
31
+ def plugin_settings
32
+ Setting[PLUGIN_KEYNAME]
33
+ end
34
+
35
+ def formatted_hash(api_key, workflow)
36
+ HashWithIndifferentAccess.new({API_KEY_KEYNAME => api_key,
37
+ WORKFLOW_KEYNAME => workflow})
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,5 @@
1
+ module ChiliVideos
2
+ module Error
3
+ class IncompleteAssembly < RuntimeError; end
4
+ end
5
+ end
@@ -0,0 +1,112 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+
4
+ class ChiliVideosTasks < Rake::TaskLib
5
+ VALID_DJ_ACTIONS = %w(start restart stop status)
6
+
7
+ def initialize
8
+ define
9
+ end
10
+
11
+ def define
12
+ namespace :chili_videos do
13
+ desc "Install ChiliVideos plugin (migrate database, include assets, etc)"
14
+ task :install => [:migrate_db, :symlink_assets]
15
+
16
+ desc "Uninstalls ChiliVideos plugin (removes database modifications, removes assets, etc)"
17
+ task :uninstall => [:environment] do
18
+ puts "Removing ChiliVideos database modifications..."
19
+ migrate_db(:to_version => 0)
20
+
21
+ puts "Removing link to ChiliVideo assets (stylesheets, js, etc)..."
22
+ remove_symlink asset_destination_dir
23
+
24
+ puts post_uninstall_steps
25
+ end
26
+
27
+ desc "Manage delayed_job...requires argument [ACTION=(#{VALID_DJ_ACTIONS.join('|')})]"
28
+ task :delayed_job, :action, :needs => [:environment] do |task, args|
29
+ unless(args[:action] && VALID_DJ_ACTIONS.include?(args[:action]))
30
+ puts "'ACTION' is a required parameter. Valid values are: #{VALID_DJ_ACTIONS.join(', ')}"
31
+ exit(1)
32
+ end
33
+
34
+ shell_command = "RAILS_ROOT='#{application_root}' RAILS_ENV=#{RAILS_ENV} #{File.expand_path(delayed_job_path)} #{args[:action]}"
35
+ puts "Issuing '#{args[:action]}' command to delayed_job executable (bundled with ChiliVideos)"
36
+ sh shell_command do |ok, status|
37
+ ok || fail("Command failed (status: #{status}) (command: '#{shell_command}')")
38
+ end
39
+ end
40
+
41
+ task :migrate_db => [:environment] do
42
+ puts "Migrating chili_videos-#{ChiliVideos::VERSION}..."
43
+ ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
44
+ ActiveRecord::Migrator.migrate(gem_db_migrate_dir, ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
45
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
46
+ end
47
+
48
+ task :symlink_assets => [:environment] do
49
+ # HACK: Symlinks the files from plugindir/assets to the appropriate place in
50
+ # the rails application
51
+ puts "Symlinking assets (stylesheets, etc)..."
52
+ add_symlink asset_source_dir, asset_destination_dir
53
+ end
54
+ end
55
+ end
56
+
57
+ private
58
+ def application_root
59
+ File.expand_path(RAILS_ROOT)
60
+ end
61
+
62
+ def gem_root
63
+ @gem_root ||= File.expand_path(File.dirname(__FILE__) + "/../..")
64
+ end
65
+
66
+ def asset_destination_dir
67
+ @destination_dir ||= File.expand_path("#{application_root}/public/plugin_assets/chili_videos")
68
+ end
69
+
70
+ def asset_source_dir
71
+ @source_dir ||= File.expand_path(gem_root + "/assets")
72
+ end
73
+
74
+ def gem_db_migrate_dir
75
+ @gem_db_migrate_dir ||= File.expand_path(gem_root + "/db/migrate")
76
+ end
77
+
78
+ def delayed_job_path
79
+ @delayed_job_path ||= File.expand_path(gem_root + "/bin/delayed_job")
80
+ end
81
+
82
+ def remove_symlink(symlink_file)
83
+ system("unlink #{symlink_file}") if File.exists?(symlink_file)
84
+ end
85
+
86
+ def add_symlink(source, destination)
87
+ remove_symlink destination
88
+ system("ln -s #{source} #{destination}")
89
+ end
90
+
91
+ def migrate_db(options = {})
92
+ ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
93
+ ActiveRecord::Migrator.migrate(gem_db_migrate_dir, options[:to_version])
94
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
95
+ end
96
+
97
+ def post_uninstall_steps
98
+ [
99
+ "!!!!! MANUAL STEPS !!!!!",
100
+ "\t1. In your 'config/environment.rb', remove:",
101
+ "\t\tconfig.gem 'chili_videos'",
102
+ "",
103
+ "\t2. In your 'Rakefile', remove:",
104
+ "\t\trequire 'chili_videos'",
105
+ "\t\trequire 'tasks/chili_videos_tasks'",
106
+ "\t\tChiliVideosTasks.new",
107
+ "",
108
+ "\t3. Cycle your application server (mongrel, unicorn, etc)",
109
+ "\n",
110
+ ].join("\n")
111
+ end
112
+ end
@@ -0,0 +1,64 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+
4
+ class ContributorTasks < Rake::TaskLib
5
+ def initialize
6
+ define
7
+ end
8
+
9
+ def define
10
+ desc "Update contributors list in README"
11
+ task :update_contributors do
12
+ if new_contributors?
13
+ puts "New contributors!"
14
+ new_contributors.each {|name| puts "- #{name}"}
15
+ puts ""
16
+
17
+ print "Updating the 'Contributors' section of README..."
18
+
19
+ File.open("README.md", "w+") do |file|
20
+ file.puts readme_without_contributors_section
21
+ file.puts "## Contributors (sorted alphabetically)"
22
+ file.puts ""
23
+ committers.each {|name| file.puts "* #{name}"}
24
+ end
25
+ puts "done!"
26
+ else
27
+ puts "No new contributors."
28
+ end
29
+ end
30
+ end
31
+
32
+ private
33
+ def all_committers
34
+ all_names = `git shortlog -s |cut -s -f2`
35
+ all_names.gsub!(/\sand\s/, "\n").split("\n").uniq!.sort!
36
+ end
37
+
38
+ def committers
39
+ excluded_committers = ["Tom Kersten"]
40
+ @committers ||= all_committers - excluded_committers
41
+ end
42
+
43
+ def readme_file_contents
44
+ @readme_contents ||= `cat README.md`
45
+ end
46
+
47
+ def existing_contributors
48
+ existing_contributors = readme_file_contents[/## Contributors(.|\n)*/].strip.split("\n* ")
49
+ existing_contributors.shift # remove "Contributors..." line
50
+ existing_contributors
51
+ end
52
+
53
+ def new_contributors
54
+ @new_contributors ||= committers - existing_contributors
55
+ end
56
+
57
+ def new_contributors?
58
+ !new_contributors.empty?
59
+ end
60
+
61
+ def readme_without_contributors_section
62
+ readme_file_contents.sub(/## Contributors(.|\n)*/, '')
63
+ end
64
+ end