diff --git a/app/controllers/galleries_controller.rb b/app/controllers/galleries_controller.rb
new file mode 100644
index 0000000..9d7a574
--- /dev/null
+++ b/app/controllers/galleries_controller.rb
@@ -0,0 +1,78 @@
+class GalleriesController < ApplicationController
+ append_before_filter :fetch_image, :only => [ :show, :destroy,
+ :download_original ]
+
+ # GET /images
+ # GET /images.xml
+ def index
+ @content_title = 'Image Gallery'
+ cond_ary = []
+ cond_var = {
+ :people_id => params[:id]
+ }
+ @secondary_title = "Everybody's Images"
+ if params[:id]
+ cond_ary << 'images.people_id = :people_id'
+ @people = People.find(params[:id])
+ @secondary_title = "Images from #{@people.title}"
+ end
+ cond_ary << '1 = 1' if cond_ary.empty?
+ @pages, @images = paginate :images, :per_page => per_page,
+ :order => 'images.created_at DESC', :include => [ 'people' ],
+ :conditions => [ cond_ary.join(' AND '), cond_var ]
+ flash.now[:notice] = 'There are no images yet.' if @images.empty?
+ respond_to do |format|
+ format.html # index.rhtml
+ format.xml { render :xml => @images.to_xml }
+ end
+ end
+
+ # GET /galleries/1
+ # GET /galleries/1.xml
+ def show
+ respond_to do |format|
+ format.html # show.rhtml
+ format.xml { render :xml => @image.to_xml }
+ end
+ end
+
+ # GET /galleries/new
+ def new
+ @image = Image.new
+ end
+
+ # POST /images
+ # POST /images.xml
+ def create
+ @image = Image.new(params[:image])
+ if @image.save
+ flash[:notice] = 'Great success!'
+ redirect_to gallery_url(@image)
+ else
+ render :action => :new
+ end
+ end
+
+ # DELETE /galleries/1
+ # DELETE /galleries/1.xml
+ def destroy
+ @image.destroy
+ flash[:notice] = 'Destroyed the image.'
+ redirect_to galleries_url(:id => @image.people_id)
+ end
+
+ ##
+ # Sends a copy of the original Image to the People.
+ #
+ def download_original
+ send_file("#{RAILS_ROOT}/public/images/" +
+ @image.filename_for_version(:original),
+ :disposition => 'inline', :type => @image.content_type)
+ end
+
+ protected
+
+ def fetch_image
+ @image = Image.find(params[:id])
+ end
+end
diff --git a/app/controllers/tag_images_controller.rb b/app/controllers/tag_images_controller.rb
new file mode 100644
index 0000000..3e145fc
--- /dev/null
+++ b/app/controllers/tag_images_controller.rb
@@ -0,0 +1,88 @@
+class TagImagesController < ApplicationController
+ # GET /tag_images
+ # GET /tag_images.xml
+ def index
+ redirect_to images_url
+ end
+
+ # GET /tag_images/1
+ # GET /tag_images/1.xml
+ def show
+ @content_title = 'Tag your friends and beers!'
+ @image = Image.find(params[:id], :include => [ :tag_images ])
+ @tag_images = @image.tag_images
+ respond_to do |format|
+ format.html # show.rhtml
+ format.xml { render :xml => @tag_images.to_xml }
+ end
+ end
+
+ # POST /tag_images
+ # POST /tag_images.xml
+ def create
+ @tag_image = TagImage.new(params[:tag_image])
+ @image = @tag_image.image
+ if @tag_image.save
+ @tag_images = @image.tag_images
+ render :partial => 'tag_images'
+ else
+ render :partial => 'tag_image_errors', :status => 500
+ end
+ end
+
+ # DELETE /tag_images/1
+ # DELETE /tag_images/1.xml
+ def destroy
+ @tag_image = TagImage.find params[:id], :include => [ :image ]
+ @image = @tag_image.image
+ @tag_image.destroy
+ @image.tag_images.reload
+ @tag_images = @image.tag_images
+ render :partial => 'tag_images'
+ end
+
+ ##
+ # Searches for all known models that support image tagging. Sticks all of
+ # the matching results into a hash that is indexed by the type.
+ #
+ def taggable_search
+ @results = {}
+ cond_ary = [ 'title ILIKE :title' ]
+ cond_var = { :title => "%#{params[:name]}%" }
+ TagImage.types_for_select.flatten.each do |ctype|
+ klass = Class.class_eval(ctype)
+ @results[ctype] = klass.find :all, :order => 'title ASC',
+ :conditions => [ cond_ary.join(' AND '), cond_var ]
+ end
+ render :partial => 'taggable_results'
+ end
+
+ ##
+ # Renders an Ajax browser of all tagged Image models for any +:taggable_type+
+ #
+ def tagged_images
+ images_per_page = 4
+ @page_count, @current_page, @tagged_type, @tagged_images = nil, nil, nil, nil
+ @tagged_type = params[:tagged_type]
+ if TagImage.types_for_select.flatten.include?(@tagged_type)
+ cond_ary = [
+ 'tagged_type = :tt',
+ 'tagged_id = :tid'
+ ]
+ cond_var = { :tt => @tagged_type, :tid => params[:id] }
+ conditions = [ cond_ary.join(' AND '), cond_var ]
+ @current_page = params[:page].to_i
+ @current_page = 1 if @current_page == 0
+ image_count = TagImage.count(conditions)
+ @page_count = (image_count.to_f / per_page.to_f + 0.5).to_i
+ @page_count = 1 if @page_count == 0 and image_count >= 0
+ @tagged_images = TagImage.find :all, :limit => images_per_page,
+ :conditions => conditions, :order => 'created_at ASC',
+ :offset => ((@current_page - 1) * images_per_page),
+ :include => [ 'image' ]
+ render :partial => 'tag_images/tagged_images'
+ else
+ render :nothing => true, :status => 500
+ end
+ end
+end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 5482a33..4a2a213 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -91,4 +91,48 @@ module ApplicationHelper
res
end
end
+
+ ##
+ # Captures a block output and renders it in a partial as body
+ #
+ def block_to_partial(partial_name, options = {}, &block)
+ options.merge!(:body => capture(&block))
+ concat(render(:partial => partial_name, :locals => options), block.binding)
+ end
+
+ ##
+ # Helper to build a prototype dialog.
+ #
+ def lightbox(options = {}, &block)
+ options = {
+ :title => 'DialogTitle',
+ :window_id => 'DialogId',
+ :modal => false
+ }.merge(options)
+ block_to_partial('shared/lightbox', options, &block)
+ end
+
+ ##
+ # Pagination link image browser thingey for the tagged image lightbox.
+ #
+ def image_browser_navigation_link(image_name, page_number, total_pages,
+ tagged_class, tagged_id)
+ if page_number == 0 or
+ (page_number == 1 and total_pages == 1) or
+ (page_number > total_pages)
+ image_tag(image_name)
+ else
+ link_to_remote image_tag(image_name), :update => 'browser_box',
+ :url => { :controller => 'tag_images', :action => 'tagged_images',
+ :id => :tagged_id, :tagged_class => tagged_class }
+ end
+ end
+
+ ##
+ # Link to open the dialog box for the tagged image browser.
+ #
+ def tagged_image_browser_link
+ link_to_function 'Tagged Images',
+ "lightboxes['tagged_image_browser'].open()"
+ end
end
diff --git a/app/helpers/galleries_helper.rb b/app/helpers/galleries_helper.rb
new file mode 100644
index 0000000..23b68a6
--- /dev/null
+++ b/app/helpers/galleries_helper.rb
@@ -0,0 +1,5 @@
+module GalleriesHelper
+ def new_image_link
+ link_to 'Upload Image', new_gallery_url
+ end
+end
diff --git a/app/helpers/tag_images_helper.rb b/app/helpers/tag_images_helper.rb
new file mode 100644
index 0000000..5c023de
--- /dev/null
+++ b/app/helpers/tag_images_helper.rb
@@ -0,0 +1,2 @@
+module TagImagesHelper
+end
diff --git a/app/models/beer.rb b/app/models/beer.rb
index 8a9dab5..8ae9f04 100644
--- a/app/models/beer.rb
+++ b/app/models/beer.rb
@@ -6,6 +6,7 @@ class Beer < ActiveRecord::Base
has_one_tuxwiki_page :owner_class => 'Beer'
belongs_to :style
validates_presence_of :style_id
+ has_many_tagged_images
##
# Returns a list of attributes for the Page partial.
diff --git a/app/models/image.rb b/app/models/image.rb
new file mode 100644
index 0000000..1d0fed2
--- /dev/null
+++ b/app/models/image.rb
@@ -0,0 +1,96 @@
+require 'mini_magick'
+
+class Image < ActiveRecord::Base
+ attr_accessor :file
+ belongs_to :people
+ validates_presence_of :people_id
+ before_validation_on_create :set_people_id
+ before_create :validate_image_sanity
+ after_create :setup_directories
+ before_destroy :destroy_directories
+ has_many :tag_images, :dependent => :destroy
+ has_many :tagged_items, :through => :tag_images
+
+ ##
+ # Builds the filename for this model for a particular version of the file.
+ #
+ def filename_for_version(ver = :screen)
+ if respond_to?(ver)
+ "community/#{id}/#{self.send(ver)}"
+ else
+ "/images/image-missing.png"
+ end
+ end
+
+ protected
+
+ ##
+ # Determines the base directory for all files in this model.
+ #
+ def base_directory
+ "#{RAILS_ROOT}/public/images/community/#{id}"
+ end
+
+ ##
+ # Sets the People marker for ownership on creation.
+ #
+ def set_people_id
+ self[:people_id] = ApplicationController.current_people_id rescue nil
+ self[:people_id] ||= People.penguincoder.id rescue nil
+ end
+
+ ##
+ # Checks to make sure that the file exists and is an image.
+ #
+ def validate_image_sanity
+ if @file.nil? or @file.to_s.empty?
+ errors.add(:file, 'is not a file')
+ return false
+ end
+ errors.add(:file, 'is too big (3MB max)') if @file.size > 3 * 1048576
+ begin
+ @magick_image = MiniMagick::Image.from_blob(@file.read,
+ File.extname(@file.original_filename))
+ rescue
+ logger.debug("Caught an exception saving an image:")
+ logger.debug("* #{$!}")
+ errors.add(:file, 'is not an image')
+ end
+ return false if self.errors.size > 0
+ self.content_type = @file.content_type.chomp
+ true
+ end
+
+ ##
+ # Makes the directories and writes the different versions for the uploaded
+ # files if applicable.
+ #
+ def setup_directories
+ Dir.mkdir(base_directory) unless File.exist?(base_directory)
+ self.original = File.basename(@file.original_filename).gsub(/[^\w._-]/, '')
+ @magick_image.write("#{base_directory}/#{self.original}")
+ @magick_image.thumbnail("600x600>")
+ self.screen = "screen_#{self.original}"
+ @magick_image.write("#{base_directory}/#{self.screen}")
+ if @magick_image.output =~ / (\d+)x(\d+) /
+ self.screen_width = $1
+ self.screen_height = $2
+ end
+ @magick_image.thumbnail("50x50>")
+ self.thumbnail = "thumbnail_#{self.original}"
+ @magick_image.write("#{base_directory}/#{self.thumbnail}")
+ self.save
+ end
+
+ ##
+ # Removes the directories and files associated with this model on destroy.
+ #
+ def destroy_directories
+ return unless File.exists?(base_directory)
+ Dir.foreach(base_directory) do |file|
+ next if file =~ /^\.\.?$/
+ File.delete(base_directory + '/' + file)
+ end
+ Dir.delete(base_directory)
+ end
+end
diff --git a/app/models/people.rb b/app/models/people.rb
index 6840ab2..4069f8f 100644
--- a/app/models/people.rb
+++ b/app/models/people.rb
@@ -7,6 +7,8 @@ class People < ActiveRecord::Base
attr_protected :role_id
has_many :created_pages, :class_name => 'Page', :foreign_key => 'created_by'
has_many :updated_pages, :class_name => 'Page', :foreign_key => 'updated_by'
+ has_many :images, :dependent => :destroy
+ has_many_tagged_images
validates_uniqueness_of :title
make_authenticatable
diff --git a/app/models/tag_image.rb b/app/models/tag_image.rb
new file mode 100644
index 0000000..18a39fe
--- /dev/null
+++ b/app/models/tag_image.rb
@@ -0,0 +1,10 @@
+class TagImage < ActiveRecord::Base
+ belongs_to :image
+ belongs_to :tagged, :polymorphic => true
+ validates_presence_of :image_id, :tagged_id, :tagged_type
+ validates_uniqueness_of :tagged_id, :scope => :tagged_type
+
+ def self.types_for_select
+ [ 'Beer', 'People', 'Brewery' ].collect { |x| [x] }
+ end
+end
diff --git a/app/views/beers/show.rhtml b/app/views/beers/show.rhtml
index ecd793d..669aabb 100644
--- a/app/views/beers/show.rhtml
+++ b/app/views/beers/show.rhtml
@@ -1,7 +1,10 @@
+<%= render :partial => 'shared/tagged_image_browser', :locals => { :obj => @beer } %>
+
<%= render :partial => 'pages/page' %>
<% content_for :sidebar do -%>
<%= new_beer_link -%>
<%= edit_beer_link(@beer) -%>
<%= link_to 'Destroy', beer_path(@beer.page.title_for_url), :confirm => 'Are you sure?', :method => :delete %>
+ <% unless @beer.tagged_images.empty? -%><%= tagged_image_browser_link -%>
<% end -%>
<% end -%>
diff --git a/app/views/breweries/show.rhtml b/app/views/breweries/show.rhtml
index 872515a..e40d782 100644
--- a/app/views/breweries/show.rhtml
+++ b/app/views/breweries/show.rhtml
@@ -4,4 +4,5 @@
<%= new_brewery_link -%>
<%= edit_brewery_link(@brewery) -%>
<%= link_to 'Destroy', brewery_path(@brewery.page.title_for_url), :confirm => 'Are you sure?', :method => :delete %>
+ <%= tagged_image_browser_link -%>
<% end -%>
diff --git a/app/views/galleries/_image.rhtml b/app/views/galleries/_image.rhtml
new file mode 100644
index 0000000..66afb9f
--- /dev/null
+++ b/app/views/galleries/_image.rhtml
@@ -0,0 +1,6 @@
+
+<% version ||= :screen -%>
+
+ <%= submit_tag "Update" %> +
+<% end %> + +<%= link_to 'Show', images_path(@images) %> | +<%= link_to 'Back', images_path %> \ No newline at end of file diff --git a/app/views/galleries/index.rhtml b/app/views/galleries/index.rhtml new file mode 100644 index 0000000..0117257 --- /dev/null +++ b/app/views/galleries/index.rhtml @@ -0,0 +1,7 @@ +<%= render :partial => 'image', :collection => @images, :locals => { :version => :thumbnail } %> + +<%= render :partial => 'shared/pagination_links' %> + +<% content_for :sidebar do -%> + <%= new_image_link -%>+ <%= submit_tag "Create" %> <%= image_tag '/images/spinner.gif', :id => 'spinner', :style => 'display:none' %> +
+<% end %> + +<% content_for :sidebar do -%> + <%= new_image_link -%>