beef-has_assets 0.5.0 → 0.6.1

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.
data/Rakefile CHANGED
@@ -4,14 +4,14 @@ require 'rake'
4
4
  begin
5
5
  require 'jeweler'
6
6
  Jeweler::Tasks.new do |gem|
7
- gem.name = "has_assets"
7
+ gem.name = "beef-has_assets"
8
8
  gem.summary = %Q{Rails Engine. Adds uploadable assets to a model and admin area for files}
9
9
  gem.email = "steve@wearebeef.co.uk"
10
10
  gem.homepage = "http://github.com/beef/assets"
11
11
  gem.authors = ["Steve England"]
12
12
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
13
13
  end
14
-
14
+ Jeweler::GemcutterTasks.new
15
15
  rescue LoadError
16
16
  puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
17
17
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.0
1
+ 0.6.1
@@ -39,6 +39,16 @@ class Admin::AssetsController < Admin::BaseController
39
39
  format.js { render :action => 'index'}
40
40
  end
41
41
  end
42
+
43
+ def category
44
+ @assets = Asset.all(:conditions => ["category = ?",params[:category]])
45
+
46
+ respond_to do |format|
47
+ format.html { render :layout => false}
48
+ format.xml { @assets.to_xml }
49
+ format.js { render :layout => false}
50
+ end
51
+ end
42
52
 
43
53
  def descriptions
44
54
  @descriptions = Asset.not_thumbnails.find(:all, :select => 'description', :group => 'description', :order => 'description', :conditions => 'description IS NOT NULL')
@@ -14,13 +14,15 @@ class Admin::FlickrsController < Admin::BaseController
14
14
  end
15
15
 
16
16
  def index
17
- @flickr_result = {}
18
- if defined?(Flickr) and File.exists?("#{RAILS_ROOT}/config/flickr.yml")
19
- flickr = Flickr.new("#{RAILS_ROOT}/config/flickr.yml")
20
- flickr_params = { :per_page => '12', :page => params[:page], :user_id => Settings.flickr_user_id, :sort => 'date-taken-desc', :tag_mode => 'all' }
21
- flickr_params[:tags] = params[:tags] unless params[:tags].blank?
22
- @flickr_result = flickr.photos.search(flickr_params)
17
+ respond_to do |format|
18
+ format.js do
19
+ if defined?(Flickr) and File.exists?("#{RAILS_ROOT}/config/flickr.yml")
20
+ flickr = Flickr.new("#{RAILS_ROOT}/config/flickr.yml")
21
+ flickr_params = { :per_page => '12', :page => params[:page], :user_id => Settings.flickr_user_id, :sort => 'date-taken-desc', :tag_mode => 'all' }
22
+ flickr_params[:tags] = params[:tags] unless params[:tags].blank?
23
+ @flickr_result = flickr.photos.search(flickr_params)
24
+ end
25
+ end
23
26
  end
24
- render :layout => false
25
27
  end
26
28
  end
@@ -10,7 +10,8 @@ module Admin::AssetsHelper
10
10
  def asset_browser(for_content = false)
11
11
  render :partial => '/admin/assets/browser',
12
12
  :locals => { :asset_types => Asset.grouped_by_category,
13
- :for_content => for_content }
13
+ :for_content => for_content,
14
+ :ajaxify => true }
14
15
  end
15
16
 
16
17
  def asset_upload_form
@@ -34,21 +35,20 @@ module Admin::AssetsHelper
34
35
 
35
36
 
36
37
  def lastest_flickr
37
- return unless defined?(Flickr) and File.exists?("#{RAILS_ROOT}/config/flickr.yml")
38
+ return unless defined?(Flickr) and File.exists?("#{RAILS_ROOT}/config/flickr.yml") and !Settings.flickr_user_id.blank?
38
39
  flickr = Flickr.new("#{RAILS_ROOT}/config/flickr.yml")
39
40
  flickr_params = { :per_page => '5', :page => params[:page], :user_id => Settings.flickr_user_id, :sort => 'date-taken-desc', :tag_mode => 'all' }
40
41
  flickr_params[:tags] = params[:tags] unless params[:tags].blank?
41
42
  flickr_result = flickr.photos.search(flickr_params)
42
43
  render :partial => 'admin/shared/flickr_latest.html.erb', :locals => { :flickr_images => flickr_result }
44
+ rescue RuntimeError => e
45
+ logger.warn "Flickr error: #{e}"
46
+ return
43
47
  end
44
48
 
45
49
 
46
50
  def flickr_select
47
- return unless defined?(Flickr) and File.exists?("#{RAILS_ROOT}/config/flickr.yml")
48
- flickr = Flickr.new("#{RAILS_ROOT}/config/flickr.yml")
49
- flickr_params = { :per_page => '12', :page => params[:page], :user_id => Settings.flickr_user_id, :sort => 'date-taken-desc', :tag_mode => 'all' }
50
- flickr_params[:tags] = params[:tags] unless params[:tags].blank?
51
- flickr_result = flickr.photos.search(flickr_params)
52
- render :partial => 'admin/shared/flickr.html.erb', :locals => { :flickr_images => flickr_result }
51
+ return unless defined?(Flickr) and File.exists?("#{RAILS_ROOT}/config/flickr.yml") and !Settings.flickr_user_id.blank?
52
+ render :partial => 'admin/flickrs/selector'
53
53
  end
54
54
  end
@@ -8,18 +8,10 @@
8
8
  <dd id="<%= asset_type.parameterize %>-description">
9
9
  <h3 class="type-heading"><%= asset_type %></h3>
10
10
  <ul id="<%= asset_type.parameterize %>-list" class="asset-list">
11
- <% for asset in assets -%>
12
- <li class="<%= asset.content_type.gsub('/', ' ') %>" id="browser-asset-<%= asset.id %>">
13
- <% if asset.content_type =~ /image/ -%>
14
- <%= render :partial => "admin/assets/image", :locals => { :asset => asset, :for_content => for_content } %>
15
- <% else -%>
16
- <%= render :partial => "admin/assets/document", :locals => { :asset => asset, :for_content => for_content } %>
17
- <% end -%>
18
- </li>
19
- <% end -%>
11
+ <%= render :partial => "admin/assets/category_contents", :locals => { :assets => assets, :for_content => for_content } unless ajaxify %>
20
12
  </ul>
21
13
  </dd>
22
14
  <% end -%>
23
15
  </dl>
24
- <%= javascript_tag "new AssetBrowser('#{@grouping}', '#{params[:folder]}');" %>
16
+ <%= javascript_tag "new AssetBrowser('#{@grouping}', '#{params[:folder]}', #{for_content.to_s}, #{ajaxify.to_s});" %>
25
17
 
@@ -0,0 +1,9 @@
1
+ <% for asset in assets -%>
2
+ <li class="<%= asset.content_type.gsub('/', ' ') %>" id="browser-asset-<%= asset.id %>">
3
+ <% if asset.content_type =~ /image/ -%>
4
+ <%= render :partial => "admin/assets/image", :locals => { :asset => asset, :for_content => for_content } %>
5
+ <% else -%>
6
+ <%= render :partial => "admin/assets/document", :locals => { :asset => asset, :for_content => for_content } %>
7
+ <% end -%>
8
+ </li>
9
+ <% end -%>
@@ -0,0 +1 @@
1
+ <%= render :partial => "admin/assets/category_contents", :locals => { :ajaxify => true, :assets => @assets, :for_content => (params[:for_content] == "true" || false) } %>
@@ -1,7 +1,7 @@
1
1
  <h1>Browse for Files</h1>
2
2
  <%= toggle_grouping_links %>
3
3
  <div id="main-browser">
4
- <%= render :partial => 'browser', :locals => { :asset_types => @asset_types, :for_content => false } %>
4
+ <%= render :partial => 'browser', :locals => { :ajaxify => true, :asset_types => @asset_types, :for_content => false } %>
5
5
  </div>
6
6
 
7
7
  <% content_for :sub_content do %>
@@ -1 +1 @@
1
- page.replace 'asset-browser', :partial => '/admin/assets/browser', :locals => { :asset_types => @asset_types, :for_content => (params[:for_content] == 'true' )}
1
+ page.replace 'asset-browser', :partial => '/admin/assets/browser', :locals => { :ajaxify => true, :asset_types => @asset_types, :for_content => (params[:for_content] == 'true' )}
@@ -0,0 +1 @@
1
+ <%= link_to "#{image_tag photo.url(:square), :alt => photo.description}", "#{photo.url(:large)}", :title => "#{photo.title}", :onclick => "addLinkedImage('#{photo.url(:medium)}',this.title); return false;" %>
@@ -3,8 +3,7 @@
3
3
  <% form_remote_tag( :url => admin_flickr_path, :method => :get ) do -%>
4
4
  <p><label for="tags">Search by tag:</label>
5
5
  <%= text_field_tag :tags, params[:tags] %> &nbsp; <%= submit_tag "go" %></p>
6
- <% for photo in flickr_images %>
7
- <%= link_to "#{image_tag photo.url(:square)}", "#{photo.url(:large)}", :title => "#{photo.title}", :onclick => "addLinkedImage('#{photo.url(:medium)}',this.title); return false;" %>
8
- <% end -%>
6
+
7
+ <div id="flickr-image-container">Loading Flickr images</div>
9
8
  <% end -%>
10
9
  </div>
@@ -0,0 +1,3 @@
1
+ page.replace_html 'flickr-image-container', :partial => 'admin/flickrs/photo', :collection => @flickr_result
2
+ page.insert_html :bottom, 'flickr-image-container', link_to_remote( '< Previous', :url => admin_flickrs_path(:page => @flickr_result.page - 1), :method => :get) unless @flickr_result.page == 1
3
+ page.insert_html :bottom, 'flickr-image-container', link_to_remote( 'Next >', :url => admin_flickrs_path(:page => @flickr_result.page + 1), :method => :get) unless @flickr_result.page == @flickr_result.pages
@@ -4,12 +4,12 @@
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
- s.name = %q{has_assets}
8
- s.version = "0.5.0"
7
+ s.name = %q{beef-has_assets}
8
+ s.version = "0.6.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Steve England"]
12
- s.date = %q{2009-09-25}
12
+ s.date = %q{2009-10-27}
13
13
  s.email = %q{steve@wearebeef.co.uk}
14
14
  s.extra_rdoc_files = [
15
15
  "LICENSE",
@@ -29,24 +29,26 @@ Gem::Specification.new do |s|
29
29
  "app/models/asset.rb",
30
30
  "app/models/asseting.rb",
31
31
  "app/views/admin/assets/_browser.html.erb",
32
+ "app/views/admin/assets/_category_contents.html.erb",
32
33
  "app/views/admin/assets/_document.html.erb",
33
34
  "app/views/admin/assets/_file_info.html.erb",
34
35
  "app/views/admin/assets/_form.html.erb",
35
36
  "app/views/admin/assets/_image.html.erb",
36
37
  "app/views/admin/assets/_list.html.erb",
37
38
  "app/views/admin/assets/_toggle.html.erb",
39
+ "app/views/admin/assets/category.html.erb",
38
40
  "app/views/admin/assets/index.html.erb",
39
41
  "app/views/admin/assets/index.js.rjs",
40
42
  "app/views/admin/assets/rename_category.js.rjs",
41
43
  "app/views/admin/assets/show.html.erb",
42
44
  "app/views/admin/assets/show.js.rjs",
45
+ "app/views/admin/flickrs/_flickr_latest.html.erb",
46
+ "app/views/admin/flickrs/_photo.html.erb",
43
47
  "app/views/admin/flickrs/_selector.html.erb",
44
- "app/views/admin/flickrs/index.html.erb",
48
+ "app/views/admin/flickrs/index.js.rjs",
45
49
  "app/views/admin/flickrs/show.html.erb",
46
50
  "app/views/admin/flickrs/show.js.rjs",
47
- "app/views/admin/shared/_flickr.html.erb",
48
- "app/views/admin/shared/_flickr_image.html.erb",
49
- "app/views/admin/shared/_flickr_latest.html.erb",
51
+ "beef-has_assets.gemspec",
50
52
  "config/routes.rb",
51
53
  "generators/asset_migration/asset_migration_generator.rb",
52
54
  "generators/asset_migration/templates/migration.rb",
@@ -56,8 +58,6 @@ Gem::Specification.new do |s|
56
58
  "generators/assets_admin_files/templates/public/javascripts/admin/assets.js",
57
59
  "generators/assets_admin_files/templates/public/javascripts/swfupload.js",
58
60
  "generators/assets_admin_files/templates/public/javascripts/upload_progress.js",
59
- "has_assets.gemspec",
60
- "lib/flickr.rb",
61
61
  "lib/has_assets.rb",
62
62
  "lib/has_assets/custom_redcloth_tags.rb",
63
63
  "lib/has_assets/flash_sesion_cookie_middleware.rb",
@@ -74,8 +74,8 @@ Gem::Specification.new do |s|
74
74
  s.rubygems_version = %q{1.3.5}
75
75
  s.summary = %q{Rails Engine. Adds uploadable assets to a model and admin area for files}
76
76
  s.test_files = [
77
- "test/test_helper.rb",
78
- "test/has_assets_test.rb"
77
+ "test/has_assets_test.rb",
78
+ "test/test_helper.rb"
79
79
  ]
80
80
 
81
81
  if s.respond_to? :specification_version then
data/config/routes.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  ActionController::Routing::Routes.draw do |map|
2
2
  map.namespace(:admin) do |admin|
3
3
  admin.resources :flickrs
4
- admin.resources :assets, :collection => { :by_content_type => :get, :descriptions => :get, :by_category => :get, :categories => :get }, :member => { :set_lead => :put, :rename_category => :post }
4
+ admin.resources :assets, :collection => { :by_content_type => :get, :descriptions => :get, :by_category => :get, :categories => :get, :category => :get }, :member => { :set_lead => :put, :rename_category => :post }
5
5
  end
6
6
  end
@@ -12,6 +12,10 @@ var AssetBrowser = Class.create({
12
12
  dt.dd.hide();
13
13
  dt.onclick = function() {
14
14
  AssetBrowser.closeInfo();
15
+
16
+ if(AssetBrowser.ajax && !this.dd.visible() && !dt.dd.down('ul li'))
17
+ AssetBrowser.loadFilesByFolder(dt.innerHTML, dt.dd.down('ul').id);
18
+
15
19
  this.dd.toggle();
16
20
  if (AssetBrowser.current_content != this.dd) {
17
21
  if (AssetBrowser.current_content != null && AssetBrowser.current_content.visible()) {
@@ -74,7 +78,15 @@ Object.extend(AssetBrowser, {
74
78
  this.destroyAsset(asset);
75
79
  }
76
80
  },
77
-
81
+
82
+ loadFilesByFolder: function(folder_name, folder_id){
83
+ new Ajax.Request('/admin/assets/category', { method: 'get',
84
+ asynchronous:true,
85
+ parameters: { for_content: AssetBrowser.for_content, format: 'html', category: folder_name, authenticity_token: AJ.authenticity_token() },
86
+ onSuccess: function(response){ $(folder_id).update(response.responseText); } } );
87
+
88
+ },
89
+
78
90
  destroyAsset: function(asset) {
79
91
  if (confirm('Are you sure you wish to delete the asset \'' + asset.filename + ' \'?')) {
80
92
  new Ajax.Request('/admin/assets/'+ asset.id, { method: 'delete',
@@ -134,6 +146,8 @@ Object.extend(AssetBrowser, {
134
146
  this.contentNodeForm = $(id);
135
147
  if (this.contentNodeForm) {
136
148
  this.contentNodeForm.model_name = this.contentNodeForm.className.split('_').slice(1,this.contentNodeForm.className.split('_').length).join('_');
149
+ this.contentNodeForm.model_title = '';
150
+ this.contentNodeForm.className.split('_').slice(1,this.contentNodeForm.className.split('_').length).each(function(e){ this.contentNodeForm.model_title = this.contentNodeForm.model_title + e.charAt(0).toUpperCase() + e.slice(1).toLowerCase(); });
137
151
  this.setUpAssetList();
138
152
  this.contentNodeForm.addAssetIDs = function() {
139
153
  $$('input.asset_id').invoke('remove');
@@ -391,22 +405,64 @@ var Renameable = Class.create(Holdable, {
391
405
  }
392
406
  });
393
407
 
408
+ /**
409
+ * Ajax.Request.abort
410
+ * extend the prototype.js Ajax.Request object so that it supports an abort method
411
+ */
412
+ Ajax.Request.prototype.abort = function() {
413
+ // prevent and state change callbacks from being issued
414
+ this.transport.onreadystatechange = Prototype.emptyFunction;
415
+ // abort the XHR
416
+ this.transport.abort();
417
+ // update the request counter
418
+ Ajax.activeRequestCount--;
419
+ };
420
+
421
+
422
+
423
+
394
424
  var flickr_comms_ref = false;
395
425
  var flickr_before_handler = function(){
396
426
  if(false != flickr_comms_ref)
397
- flickr_comms_ref;
427
+ flickr_comms_ref.abort();
398
428
  $('flickr_loading').show();
429
+ };
430
+
431
+ var current_page = 1;
432
+ var flickr_get_next_page = function(button){
433
+ flickr_get_page(current_page+=1);
434
+ }
435
+ var flickr_get_prev_page = function(button){
436
+ current_page = Math.max(1,current_page-1)
437
+ flickr_get_page(current_page);
438
+ }
439
+
440
+ var flickr_get_page = function(num){
441
+ flickr_before_handler();
442
+
443
+ //if we have this page already
444
+ if(page_div = $('flickr-page-' + num)){
445
+ $$('.flickr-page').invoke('hide');
446
+ page_div.show();
447
+ $('flickr_loading').hide();
448
+ }
449
+ //get it
450
+ else{
451
+ flickr_comms_ref = new Ajax.Request('/admin/flickrs', {
452
+ method: 'get',
453
+ parameters: { page: num, format: 'html' },
454
+ onSuccess: function(response){ $$('.flickr-page').invoke('hide');flickr_display_images(response, num); }
455
+ });
456
+ }
457
+
399
458
  };
400
- var flickr_display_images = function(response){
459
+ var flickr_display_images = function(response, page){
401
460
  $('flickr_loading').hide();
402
- $('flickr-image-container').update(response.responseText)
403
- }
461
+ $('flickr-image-container').insert('<div class="flickr-page" id="flickr-page-' + page + '">' +response.responseText+ '</div>')
462
+ };
404
463
  var flickr_load_select = function(){
405
- flickr_before_handler();
406
- flickr_comms_ref = new Ajax.Request('/admin/flickrs', {
407
- method: 'get',
408
- parameters: { format: 'html', authenticity_token: AJ.authenticity_token() },
409
- onSuccess: flickr_display_images
410
- });
411
- }
464
+ if($('flickr-image-container')) {
465
+ new Ajax.Request('/admin/flickrs', {method: 'get'});
466
+ }
467
+ };
412
468
  document.observe('dom:loaded', flickr_load_select);
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beef-has_assets
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve England
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-09-25 00:00:00 -07:00
12
+ date: 2009-10-27 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -36,24 +36,26 @@ files:
36
36
  - app/models/asset.rb
37
37
  - app/models/asseting.rb
38
38
  - app/views/admin/assets/_browser.html.erb
39
+ - app/views/admin/assets/_category_contents.html.erb
39
40
  - app/views/admin/assets/_document.html.erb
40
41
  - app/views/admin/assets/_file_info.html.erb
41
42
  - app/views/admin/assets/_form.html.erb
42
43
  - app/views/admin/assets/_image.html.erb
43
44
  - app/views/admin/assets/_list.html.erb
44
45
  - app/views/admin/assets/_toggle.html.erb
46
+ - app/views/admin/assets/category.html.erb
45
47
  - app/views/admin/assets/index.html.erb
46
48
  - app/views/admin/assets/index.js.rjs
47
49
  - app/views/admin/assets/rename_category.js.rjs
48
50
  - app/views/admin/assets/show.html.erb
49
51
  - app/views/admin/assets/show.js.rjs
52
+ - app/views/admin/flickrs/_flickr_latest.html.erb
53
+ - app/views/admin/flickrs/_photo.html.erb
50
54
  - app/views/admin/flickrs/_selector.html.erb
51
- - app/views/admin/flickrs/index.html.erb
55
+ - app/views/admin/flickrs/index.js.rjs
52
56
  - app/views/admin/flickrs/show.html.erb
53
57
  - app/views/admin/flickrs/show.js.rjs
54
- - app/views/admin/shared/_flickr.html.erb
55
- - app/views/admin/shared/_flickr_image.html.erb
56
- - app/views/admin/shared/_flickr_latest.html.erb
58
+ - beef-has_assets.gemspec
57
59
  - config/routes.rb
58
60
  - generators/asset_migration/asset_migration_generator.rb
59
61
  - generators/asset_migration/templates/migration.rb
@@ -63,8 +65,6 @@ files:
63
65
  - generators/assets_admin_files/templates/public/javascripts/admin/assets.js
64
66
  - generators/assets_admin_files/templates/public/javascripts/swfupload.js
65
67
  - generators/assets_admin_files/templates/public/javascripts/upload_progress.js
66
- - has_assets.gemspec
67
- - lib/flickr.rb
68
68
  - lib/has_assets.rb
69
69
  - lib/has_assets/custom_redcloth_tags.rb
70
70
  - lib/has_assets/flash_sesion_cookie_middleware.rb
@@ -74,9 +74,10 @@ files:
74
74
  - rails/init.rb
75
75
  - test/has_assets_test.rb
76
76
  - test/test_helper.rb
77
- has_rdoc: false
77
+ has_rdoc: true
78
78
  homepage: http://github.com/beef/assets
79
- licenses:
79
+ licenses: []
80
+
80
81
  post_install_message:
81
82
  rdoc_options:
82
83
  - --charset=UTF-8
@@ -102,5 +103,5 @@ signing_key:
102
103
  specification_version: 3
103
104
  summary: Rails Engine. Adds uploadable assets to a model and admin area for files
104
105
  test_files:
105
- - test/test_helper.rb
106
106
  - test/has_assets_test.rb
107
+ - test/test_helper.rb
@@ -1 +0,0 @@
1
- <%= render :partial => 'admin/shared/flickr_image.html.erb', :collection => @flickr_result -%>
@@ -1,17 +0,0 @@
1
-
2
- <div id="flickr-select">
3
- <% form_remote_tag( :method => :get, :url => admin_flickrs_path, :before => "flickr_before_handler()", :success => "flickr_display_images(request);" ) do -%>
4
- <p><label for="tags">Search by tag:</label>
5
- <%= text_field_tag :tags, params[:tags] %> &nbsp; <%= submit_tag "go" %> <span id="flickr_loading">Loading Flickr images</span></p>
6
-
7
- <% end -%>
8
-
9
- <div id="flickr-image-container">
10
- <% #= render :partial => 'admin/shared/flickr_image.html.erb', :collection => flickr_images -%>
11
- </div>
12
-
13
- <ul id="flickr_nav">
14
- <li class="first"><a href="#" onclick="flickr_get_prev_page();return false;">previous</a></li>&nbsp;|&nbsp;
15
- <li class="last"><a href="#" onclick="flickr_get_next_page();return false;">next</a></li>
16
- </ul>
17
- </div>
@@ -1 +0,0 @@
1
- <img src="<%= flickr_image.url(:square) %>" alt="<%= flickr_image.description || flickr_image.title %>" title="<%= flickr_image.title %>" onclick="addLinkedImage('<%= flickr_image.url(:medium) %>',this.alt)"/>
data/lib/flickr.rb DELETED
@@ -1,386 +0,0 @@
1
- # = Flickr
2
- # An insanely easy interface to the Flickr photo-sharing service. By Scott Raymond.
3
- # Modified by Steve England www.wearebeef.co.uk
4
-
5
- # Now using ObjectiveFlickr gem as it makes auth easy
6
- # gem 'objectiveflickr'
7
- require 'objectiveflickr'
8
-
9
- class Flickr
10
-
11
- def self.connect(api_key, secret, auth_token = nil)
12
- API.connect(api_key, secret, auth_token)
13
- self
14
- end
15
-
16
- class Error < StandardError ; end
17
-
18
- # Essentially a standard RuntimeError that can include the response as an
19
- # REXML object reference.
20
- class APIError < Error
21
- attr_reader :response
22
-
23
- # Creates a new exception.
24
- def initialize(response)
25
- super
26
- @response = response
27
- end
28
-
29
- # The error string returned by the API call.
30
- def to_s
31
- response['message']
32
- end
33
- end
34
-
35
- # Flickr client class. Requires an API key, and optionally takes an email and password for authentication
36
- class API
37
- class << self
38
-
39
- # Replace this API key with your own (see http://www.flickr.com/services/api/misc.api_keys.html)
40
- def connect(api_key, secret, auth_token = nil)
41
- @api_key = api_key
42
- @auth_token = auth_token
43
- @fi = FlickrInvocation.new(api_key,secret)
44
- self
45
- end
46
-
47
- def fi
48
- raise Error.new('API not connected') if @fi.nil?
49
- @fi
50
- end
51
-
52
- def login_url(permission='read')
53
- fi.login_url(permission)
54
- end
55
-
56
- def unauthorised?
57
- params = { :api_key => @api_key, :auth_token => @auth_token }
58
- logger.debug params
59
- data = fi.call('flickr.auth.checkToken',params).data
60
- logger.debug data
61
- return data['message'] if data['stat'] != 'ok'
62
- false
63
- end
64
-
65
- def authorise(frob)
66
- @auth_token = request('flickr.auth.getToken', { :api_key => @api_key, :frob => frob } )['auth']['token']['_content']
67
- end
68
-
69
- # Implements flickr.urls.lookupGroup and flickr.urls.lookupUser
70
- def find_by_url(url)
71
- response = urls_lookupUser('url'=>url) rescue urls_lookupGroup('url'=>url) rescue nil
72
- (response['user']) ? User.new(response['user']['id']) : Group.new(response['group']['id']) unless response.nil?
73
- end
74
-
75
- # Implements flickr.photos.getRecent and flickr.photos.search, returns PhotoList object so
76
- # that page_count, total etc. are avaiable for pagination.
77
- def photos(params = {})
78
- photos = (params.empty?) ? photos_getRecent['photos'] : photos_search(params)['photos']
79
- PhotoList.new(photos, self)
80
- end
81
-
82
- # Implements flickr.people.getOnlineList, flickr.people.findByEmail, and flickr.people.findByUsername
83
- def users(lookup=nil)
84
- if(lookup)
85
- user = people_findByEmail('find_email'=>lookup)['user'] rescue people_findByUsername('username'=>lookup)['user']
86
- return User.find(user['nsid'])
87
- else
88
- return people_getOnlineList['online']['user'].collect { |person| User.new(person['nsid']) }
89
- end
90
- end
91
-
92
- # Implements flickr.groups.getActiveList
93
- def groups
94
- groups_getActiveList['activegroups']['group'].collect { |group| Group.new(group['nsid']) }
95
- end
96
-
97
- # Implements flickr.tags.getRelated
98
- def related_tags(tag)
99
- tags_getRelated('tag_id'=>tag)['tags']['tag']
100
- end
101
-
102
- # Implements flickr.photos.licenses.getInfo
103
- def licenses
104
- photos_licenses_getInfo['licenses']['license']
105
- end
106
-
107
- # Todo:
108
- # logged_in?
109
- # if logged in:
110
- # flickr.blogs.getList
111
- # flickr.favorites.add
112
- # flickr.favorites.remove
113
- # flickr.groups.browse
114
- # flickr.photos.getCounts
115
- # flickr.photos.getNotInSet
116
- # flickr.photos.getUntagged
117
- # flickr.photosets.create
118
- # flickr.photosets.orderSets
119
- # flickr.tags.getListUserPopular
120
- # flickr.test.login
121
- # uploading
122
-
123
- private
124
-
125
- def logger
126
- RAILS_DEFAULT_LOGGER
127
- end
128
-
129
- # Takes a Flickr API method name and set of parameters
130
- def request(method, params = {}, auth = true)
131
- params[:auth] = auth
132
- params[:auth_token] = @auth_token unless @auth_token.nil?
133
- logger.debug params.inspect
134
-
135
-
136
- data = fi.call(method,params).data
137
- logger.debug data.inspect
138
- raise APIError.new(data) if data['stat'] != 'ok'
139
- data
140
- end
141
-
142
- # Implements everything else.
143
- # Any method not defined explicitly will be passed on to the Flickr API,
144
- # and return an XmlSimple document. For example, Flickr#test_echo is not defined,
145
- # so it will pass the call to the flickr.test.echo method.
146
- # e.g., Flickr#test_echo['stat'] should == 'ok'
147
- def method_missing(method_id, *params)
148
- request('flickr.' + method_id.id2name.gsub(/_/, '.'), params[0])
149
- end
150
-
151
- end
152
-
153
- end
154
-
155
- class ApiObject
156
-
157
- protected
158
-
159
- def initialize(hash)
160
- hash.each do |key, value|
161
- instance_variable_set '@' + key, value
162
- end
163
- end
164
-
165
- def self.find(*args)
166
- case args.first
167
- when :first then find_initial(args[1])
168
- when :all then find_every(args[1])
169
- else find_by_id(args)
170
- end
171
- end
172
-
173
- end
174
-
175
- class Person < ApiObject
176
-
177
- attr_reader :nsid, :username, :name, :location, :count, :firstdate, :firstdatetaken
178
-
179
- def self.find_by_id(id)
180
- self.new(API.people_getInfo('user_id'=>id)['person'])
181
- end
182
-
183
- def self.find_by_email(email)
184
- id = API.people_findByEmail('find_email'=>email)['user']['nsid']
185
- find(id)
186
- end
187
-
188
- # Implements flickr.people.getPublicGroups
189
- def groups
190
- API.people_getPublicGroups('user_id'=>@nsid)['groups']['group'].collect { |group| Group.new(group['nsid']) }
191
- end
192
-
193
- def photos(params = {})
194
- @photolist ||= API.photos(params.merge('user_id'=>@nsid, 'sort'=>'date-taken-desc'))
195
- end
196
-
197
- # Implements flickr.photosets.getList
198
- def photosets
199
- if @photosets.nil?
200
- photosets = API.photosets_getList('user_id'=>@nsid)['photosets']
201
- if photosets.empty?
202
- @photosets = []
203
- else
204
- @photosets = photosets['photoset'].collect { |photoset| Photoset.new(photoset) }
205
- end
206
- else
207
- @photosets
208
- end
209
- end
210
-
211
- # Implements flickr.contacts.getPublicList and flickr.contacts.getList
212
- def contacts
213
- API.contacts_getPublicList('user_id'=>@nsid)['contacts']['contact'].collect { |contact| User.new(contact['nsid']) }
214
- end
215
-
216
- # Implements flickr.favorites.getPublicList and flickr.favorites.getList
217
- def favorites
218
- API.favorites_getPublicList('user_id'=>@nsid)['photos']['photo'].collect { |photo| Photo.new(photo) }
219
- #or
220
- end
221
-
222
- # Implements flickr.tags.getListUser
223
- def tags
224
- API.tags_getListUser('user_id'=>@nsid)['who']['tags']['tag'].collect { |tag| tag }
225
- end
226
-
227
- # Implements flickr.photos.getContactsPublicPhotos and flickr.photos.getContactsPhotos
228
- def contactsPhotos
229
- API.photos_getContactsPublicPhotos('user_id'=>@nsid)['photos']['photo'].collect { |photo| Photo.new(photo) }
230
- # or
231
- #API.photos_getContactsPhotos['photos']['photo'].collect { |photo| Photo.new(photo['id']) }
232
- end
233
-
234
- def to_s
235
- @name
236
- end
237
-
238
- end
239
-
240
- class Photoset < ApiObject
241
- attr_reader :id, :title, :description
242
-
243
- def find_by_id(id)
244
- self.new(photosets_getInfo('photoset_id'=>id)['photoset'])
245
- end
246
-
247
- def total
248
- @photos
249
- end
250
-
251
- def photos
252
- photo = API.photosets_getPhotos('photoset_id'=>id)['photoset']['photo']
253
- return [] if photo.nil?
254
- return [Photo.new(photo, self)] if photo.is_a? Hash
255
- photo.collect { |photo| Photo.new(photo) }
256
- end
257
- end
258
-
259
- class Photo < ApiObject
260
-
261
- attr_reader :id, :title, :owner_id, :server, :isfavourite, :license, :rotation, :description, :notes
262
- attr_writer :owner
263
-
264
- def self.find_by_id(id)
265
- self.new(API.photos_getInfo('photo_id'=>id)['photo'])
266
- end
267
-
268
- # Implements flickr.photos.getRecent and flickr.photos.search, returns PhotoList object so
269
- # that page_count, total etc. are avaiable for pagination.
270
- def self.find_every(params = {})
271
- photos = (params.empty?) ? API.photos_getRecent['photos'] : API.photos_search(params)['photos']
272
- PhotoList.new(photos)
273
- end
274
-
275
- def self.find_initial(params = {})
276
- params[:per_page] = 1
277
- find_every(params = {})
278
- end
279
-
280
- # Returns the URL for the photo page (default or any specified size)
281
- def url(size='Medium')
282
- if size=='Medium'
283
- "http://flickr.com/photos/#{owner.username}/#{@id}"
284
- else
285
- sizes(size)['url']
286
- end
287
- end
288
-
289
- # Returns the URL for the image (default or any specified size)
290
- def source(size=nil)
291
- url = "http://static.flickr.com/#{@server}/#{@id}_#{@secret}"
292
- url << "_#{size}" unless size.nil?
293
- url + ".jpg"
294
- end
295
-
296
- # Returns the photo file data itself, in any specified size. Example: File.open(photo.title, 'w') { |f| f.puts photo.file }
297
- def file(size=nil)
298
- Net::HTTP.get_response(URI.parse(source(size))).body
299
- end
300
-
301
- # Unique filename for the image, based on the Flickr NSID
302
- def filename
303
- "#{@id}.jpg"
304
- end
305
-
306
- # Implements flickr.photos.getContext
307
- def context
308
- context = API.photos_getContext('photo_id'=>@id)
309
- @previousPhoto = Photo.new(context['prevphoto']['id'])
310
- @nextPhoto = Photo.new(context['nextphoto']['id'])
311
- return [@previousPhoto, @nextPhoto]
312
- end
313
-
314
- # Implements flickr.photos.getExif
315
- def exif
316
- API.photos_getExif('photo_id'=>@id)['photo']
317
- end
318
-
319
- # Implements flickr.photos.getPerms
320
- def permissions
321
- API.photos_getPerms('photo_id'=>@id)['perms']
322
- end
323
-
324
- # Implements flickr.photos.getSizes
325
- def sizes(size=nil)
326
- sizes = API.photos_getSizes('photo_id'=>@id)['sizes']['size']
327
- sizes = sizes.find{|asize| asize['label']==size} if size
328
- return sizes
329
- end
330
-
331
- # flickr.tags.getListPhoto
332
- def tags
333
- API.tags_getListPhoto('photo_id'=>@id)['photo']['tags']
334
- end
335
-
336
- # Implements flickr.blogs.postPhoto
337
- def postToBlog(blog_id, title='', description='')
338
- API.blogs_postPhoto('photo_id'=>@id, 'title'=>title, 'description'=>description)
339
- end
340
-
341
- # Converts the Photo to a string by returning its title
342
- def to_s
343
- @title
344
- end
345
-
346
- end
347
-
348
- # Todo:
349
- # flickr.groups.pools.add
350
- # flickr.groups.pools.getContext
351
- # flickr.groups.pools.getGroups
352
- # flickr.groups.pools.getPhotos
353
- # flickr.groups.pools.remove
354
- class Group < ApiObject
355
- attr_reader :id, :client, :name, :members, :online, :privacy, :chatid, :chatcount, :url
356
-
357
- def self.find_by_id(id)
358
- self.new(API.groups_getInfo('user_id'=>id)['person'])
359
- end
360
-
361
- def self.photos(id, params = {})
362
- params['group_id'] = id
363
- PhotoList.new(API.groups_pools_getPhotos(params)['photos'])
364
- end
365
-
366
-
367
- end
368
-
369
- # Extended from array to allow perpage etc.
370
- class PhotoList < Array
371
- attr_reader :page, :pages, :perpage, :total
372
-
373
- def initialize(flickr_response)
374
- @page = flickr_response['page'].to_i
375
- @perpage = flickr_response['perpage'].to_i
376
- @total = flickr_response['total'].to_i
377
- @pages = flickr_response['pages'].to_i
378
-
379
- @photo = flickr_response['photo']
380
-
381
- super Photo.new(@photo, self) if @photo.is_a? Hash
382
- super @photo.collect { |photo| Photo.new(photo) }
383
- end
384
- end
385
-
386
- end