adding tuxbliki application

master
Coleman 2008-06-26 23:13:15 -05:00
parent d3817d4db0
commit 12c98077ee
221 changed files with 13303 additions and 0 deletions

61
Rakefile Normal file
View File

@ -0,0 +1,61 @@
require 'rubygems'
Gem.clear_paths
Gem.path.unshift(File.join(File.dirname(__FILE__), "gems"))
require 'rake'
require 'rake/rdoctask'
require 'rake/testtask'
require 'spec/rake/spectask'
require 'fileutils'
require 'merb-core'
require 'rubigen'
$RAKE_ENV = true
Merb.load_dependencies
include FileUtils
# # # Get Merb plugins and dependencies
Merb::Plugins.rakefiles.each {|r| require r }
#
#desc "Packages up Merb."
#task :default => [:package]
desc "load merb_init.rb"
task :merb_init do
require 'merb-core'
require File.dirname(__FILE__)+'/config/init.rb'
end
task :uninstall => [:clean] do
sh %{sudo gem uninstall #{NAME}}
end
desc 'Run all tests, specs and finish with rcov'
task :aok do
sh %{rake rcov}
sh %{rake specs}
end
unless Gem.cache.search("haml").empty?
namespace :haml do
desc "Compiles all sass files into CSS"
task :compile_sass do
gem 'haml'
require 'sass'
puts "*** Updating stylesheets"
Sass::Plugin.update_stylesheets
puts "*** Done"
end
end
end
##############################################################################
# SVN
##############################################################################
desc "Add new files to subversion"
task :svn_add do
system "svn status | grep '^\?' | sed -e 's/? *//' | sed -e 's/ /\ /g' | xargs svn add"
end

60
app/controllers/albums.rb Normal file
View File

@ -0,0 +1,60 @@
class Albums < Application
def index
@albums = Album.find(:all)
@tags = Album.popular_tags(30)
display @albums
end
def show
@album = Album.find_by_name(params[:id].gsub(/_/, ' '))
raise NotFound unless @album
display @album
end
def new
only_provides :html
@secondary_title = 'Create an album'
@album = Album.new(params[:album])
render
end
def create
@album = Album.new(params[:album])
if @album.save
redirect url(:album, @album.name.gsub(/ /, '_'))
else
@secondary_title = 'Create an album'
render :new
end
end
def edit
only_provides :html
@album = Album.find_by_name(params[:id].gsub(/_/, ' '))
@secondary_title = 'Update an album'
raise NotFound unless @album
render
end
def update
@album = Album.find_by_name(params[:id].gsub(/_/, ' '))
raise NotFound unless @album
@secondary_title = 'Update an album'
if @album.update_attributes(params[:album])
redirect url(:album, @album.name.gsub(/ /, '_'))
else
raise BadRequest
end
end
def delete
@album = Album.find_by_name(params[:id].gsub(/_/, ' '))
raise NotFound unless @album
if @album.destroy
redirect url(:albums)
else
raise BadRequest
end
end
end

View File

@ -0,0 +1,24 @@
class Application < Merb::Controller
cattr_accessor :current_author_id
before :set_current_author_id
def logged_in?
!session[:author_id].nil?
end
def set_current_author_id
self.current_author_id = session[:author_id]
end
def get_photo_version(width, height)
key = "photo_#{@photo.id}_#{width}_#{height}"
img = Cache.get(key)
File.open("#{@photo.base_directory}/#{@photo.filename}", "r") do |f|
img = Magick::Image.from_blob(f.read).first.resize_to_fit(width, height)
Cache.put(key, img)
end if img.nil?
img
end
end

View File

@ -0,0 +1,69 @@
class Authors < Application
def index
@authors = Author.find :all, :order => 'name ASC'
@secondary_title = 'Authors'
display @authors
end
def show
@author = Author.find_by_name(params[:id])
raise NotFound unless @author
@secondary_title = "#{@author.name}'s page"
display @author
end
def new
only_provides :html
@author = Author.new
@secondary_title = "It's better than herpes!"
render
end
def edit
only_provides :html
@author = Author.find_by_name(params[:id])
raise NotFound unless @author
render
end
def create
@author = Author.new(params[:author])
@invitation = Invitation.find_by_code params[:invitation_code]
if @invitation.nil?
flash[:notice] = 'You are not invited, you will need to try again later.'
render :new
elsif @author.save
flash[:notice] = 'Great success!'
@invitation.destroy
redirect url(:author, :id => @author.name)
else
render :new
end
end
def update
@author = Author.find_by_name(params[:id])
raise NotFound unless @author
if @author.update_attributes(params[:author])
flash[:notice] = 'Great success!'
redirect url(:author, :id => @author.name)
else
raise BadRequest
end
end
def delete
@author = Author.find_by_name(params[:id])
raise NotFound unless @author
if @author.destroy!
flash[:notice] = 'The author was destroyed.'
if @author.id == session[:author_id]
redirect url(:delete_session, :id => session[:author_id])
else
redirect url(:author)
end
else
raise BadRequest
end
end
end

View File

@ -0,0 +1,34 @@
class Comments < Application
def new
only_provides :html
@page = Page.find_by_name(params[:page_id].gsub(/_/, ' '))
raise NotFound unless @page
@comment = Comment.new
render
end
def create
@page = Page.find_by_name(params[:page_id].gsub(/_/, ' '))
raise NotFound unless @page
@comment = Comment.new(params[:comment])
@comment.page_id = @page.id
if @comment.save
flash[:notice] = 'Great success!'
redirect url(:page, :id => params[:page_id])
else
render :new
end
end
def delete
@comment = Comment.find(params[:id])
raise NotFound unless @comment
@page = @comment.page
if @comment.destroy!
flash[:notice] = 'Comment was destroyed.'
redirect url(:page, :id => @page.name.gsub(/ /, '_'))
else
raise BadRequest
end
end
end

View File

@ -0,0 +1,15 @@
class Exceptions < Application
# handle NotFound exceptions (404)
def not_found
@page_title = 'Error 404'
@secondary_title = 'Document Not Found'
render :format => :html
end
# handle NotAcceptable exceptions (406)
def not_acceptable
@page_title = 'Error 500'
@secondary_title = 'Application Exception'
render :format => :html
end
end

View File

@ -0,0 +1,24 @@
class Invitations < Application
def new
only_provides :html
@invitation = Invitation.new(params[:invitation])
@secondary_title = 'Invite your friends!'
render
end
def create
@invitation = Invitation.new(params[:invitation])
if @invitation.save
m = Merb::Mailer.new :to => @invitation.recipient,
:from => 'invitations@penguincoder.org',
:subject => 'TuxBliki Invitation!',
:body => partial('invitation', :format => 'text')
m.deliver!
flash[:notice] = "You just sent an invitation!"
redirect url(:authors)
else
@secondary_title = 'Invite your friends!'
render :new
end
end
end

14
app/controllers/news.rb Normal file
View File

@ -0,0 +1,14 @@
class News < Application
def index
ncount = Page.count :conditions => [ 'published = ?', true ]
@page = params[:page].to_i
per_page = 5
@page_count = (ncount.to_f / per_page.to_f).ceil.to_i
@page = 0 if @page >= @page_count
@page_title = 'Blogging!'
@news = Page.find :all, :limit => per_page, :offset => (@page * per_page), :conditions => [ 'published = ?', true ], :order => 'created_at DESC'
@oldest_date = Page.find(:first, :order => 'created_at ASC').created_at rescue nil
@tags = Page.popular_tags(30)
render
end
end

15
app/controllers/node.rb Normal file
View File

@ -0,0 +1,15 @@
class Node < Application
def index
redirect('/')
end
def show
page = Page.find_by_nid(params[:id])
raise NotFound unless page
purl = url(:page, :id => page.name.gsub(/ /, '_'))
Merb.logger.info("Permenant Redirect Drupal Node to #{purl}")
self.status = 301
headers['Location'] = purl
return "<html><body>You are being <a href=\"#{purl}\">redirected</a>.</body></html>"
end
end

72
app/controllers/pages.rb Normal file
View File

@ -0,0 +1,72 @@
class Pages < Application
def index
@pages = Page.find :all, :order => 'name ASC', :conditions => [ 'published = ?', false ]
@secondary_title = 'Wiki Pages. En Masse.'
@tags = Page.popular_tags(30)
display @pages
end
def show
@page = Page.find_by_name(params[:id].gsub(/_/, ' '))
if @page.nil?
flash[:error] = "That page does not exist. You can now create it."
redirect url(:new_page, :new_name => params[:id])
else
@comments = @page.comments
@secondary_title = @page.name
display @page
end
end
def new
@page_title = 'Make a new page'
only_provides :html
@page = Page.new
if params[:new_name]
flash.now[:notice] = 'That page does not exist, but you can create it.'
@page.name = params[:new_name].gsub(/_/, ' ')
end
render
end
def edit
@page_title = 'Update page'
only_provides :html
@page = Page.find_by_name(params[:id].gsub(/_/, ' '))
raise NotFound unless @page
render
end
def create
@page = Page.new(params[:page])
if @page.save
flash[:notice] = "Great success!"
redirect url(:page, :id => @page.name.gsub(/ /, '_'))
else
render :new
end
end
def update
@page = Page.find_by_name(params[:id].gsub(/_/, ' '))
raise NotFound unless @page
if @page.update_attributes(params[:page])
flash[:notice] = "Great success!"
redirect url(:page, :id => @page.name.gsub(/ /, '_'))
else
render :edit
end
end
def delete
@page = Page.find_by_name(params[:id].gsub(/_/, ' '))
raise NotFound unless @page
if @page.destroy!
flash[:notice] = "The page was successfully destroyed."
redirect url(:page)
else
raise BadRequest
end
end
end

View File

@ -0,0 +1,26 @@
class Permissions < Application
def show
@author = Author.find(params[:id])
raise NotFound unless @author
@permissions = @author.permissions
@secondary_title = "Permissions for #{@author.name}"
render
end
def edit
only_provides :html
@author = Author.find(params[:id])
raise NotFound unless @author
@permissions = Permission.find :all, :order => 'name ASC'
@secondary_title = "Change permissions for #{@author.name}"
render
end
def update
@author = Author.find(params[:id])
raise NotFound unless @author
@permissions = Permission.find(params[:permissions])
@author.permissions = @permissions
redirect url(:permission, @author)
end
end

View File

@ -0,0 +1,41 @@
class PhotoTags < Application
def index
redirect url(:tags)
end
def show
@photo = Photo.find(params[:id])
@editable = !params[:editable].nil?
partial 'photo_tags'
end
def create
@photo = Photo.find(params[:photo_tag][:photo_id]) rescue nil
raise NotFound unless @photo
params[:tags].split.each do |tag_name|
t = Tag.find_by_name(tag_name) rescue nil
t ||= Tag.create :name => tag_name
pt = PhotoTag.new(params[:photo_tag])
pt.tag = t
pt.save
end
@editable = true
partial 'photo_tags'
end
def destroy
@photo_tag = PhotoTag.find(params[:id])
raise NotFound unless @photo_tag
@photo = @photo_tag.photo
raise NotFound unless @photo
if @photo_tag.destroy
@editable = true
partial 'photo_tags'
else
render :text => @photo_tag.errors.collect { |e| e.to_s }.join(', '),
:status => 500
end
end
end

88
app/controllers/photos.rb Normal file
View File

@ -0,0 +1,88 @@
class Photos < Application
def index
redirect url(:albums)
end
def show
@photo = Photo.find_by_id(params[:id])
raise NotFound unless @photo
@secondary_title = h(@photo.filename)
img = get_photo_version(600, 600)
@width = img.columns
@height = img.rows
render
end
def new
only_provides :html
@photo = Photo.new(params[:photo])
render
end
def create
@photo = Photo.new(params[:photo])
if params[:photo][:album_id].to_i == 0
album = (Album.find_by_name(params[:photo][:album_id]) rescue nil)
raise NotFound unless album
@photo.album = album
end
if @photo.save
redirect url(:photo, @photo)
else
render :new
end
end
def edit
only_provides :html
@photo = Photo.find_by_id(params[:id])
raise NotFound unless @photo
render
end
def update
@photo = Photo.find_by_id(params[:id])
raise NotFound unless @photo
@photo.attributes = params[:photo]
if params[:photo][:album_id].to_i == 0
album = (Album.find_by_name(params[:photo][:album_id]) rescue nil)
raise NotFound unless album
@photo.album = album
end
if @photo.save
redirect url(:photo, @photo)
else
raise BadRequest
end
end
def delete
@photo = Photo.find_by_id(params[:id])
raise NotFound unless @photo
if @photo.destroy
redirect url(:photos)
else
raise BadRequest
end
end
def thumbnail
only_provides :html
@photo = Photo.find(params[:id])
raise NotFound unless @photo
send_data get_photo_version(150, 150).to_blob,
:filename => @photo.filename, :disposition => 'inline',
:type => @photo.content_type
end
def screen
only_provides :html
@photo = Photo.find(params[:id])
raise NotFound unless @photo
send_data get_photo_version(600, 600).to_blob,
:filename => @photo.filename, :disposition => 'inline',
:type => @photo.content_type
end
end

View File

@ -0,0 +1,28 @@
class Sessions < Application
def new
only_provides :html
render
end
def create
author = Author.authenticate(params[:username], params[:password])
if author
session[:author_id] = author.id
flash[:notice] = "Welcome back #{author.name}"
redirect '/'
else
flash[:error] = 'Login failed.'
render :new
end
end
def update
redirect '/'
end
def delete
session[:author_id] = nil
flash[:notice] = "You have logged out"
redirect '/'
end
end

61
app/controllers/tags.rb Normal file
View File

@ -0,0 +1,61 @@
class Tags < Application
def index
@tags = Tag.popular_tags
@secondary_title = 'Tag Cloud'
display @tags
end
def show
@tag = Tag.find_by_name(params[:id])
raise NotFound unless @tag
@pages = @tag.pages
@albums = @tag.albums
@secondary_title = "Content tagged with #{@tag.name}"
display @tag
end
def new
redirect '/'
end
def edit
only_provides :html
@tag = Tag.find_by_name(params[:id])
raise NotFound unless @tag
render
end
def create
redirect '/'
end
def update
@tag = Tag.find_by_name(params[:id])
raise NotFound unless @tag
if @tag.update_attributes(params[:tag])
flash[:notice] = 'The tag was updated.'
redirect url(:tag, :id => @tag.name)
else
raise BadRequest
end
end
def delete
@tag = Tag.find_by_name(params[:id])
raise NotFound unless @tag
if @tag.destroy
flash[:notice] = "The tag #{@tag.name} was destroyed."
redirect url(:tag)
else
raise BadRequest
end
end
def auto_complete
@phrase = params[:id].split.last
@tags = Tag.find :all, :limit => 15, :order => 'name ASC',
:conditions => [ 'name LIKE ?', "%#{@phrase}%" ]
@tags.<< Tag.new(:name => @phrase) unless @tags.detect { |t| t.name == @phrase }
partial 'tags/tag_autocomplete_results', :read_only => true
end
end

View File

@ -0,0 +1,5 @@
module Merb
module AlbumsHelper
end
end

View File

@ -0,0 +1,5 @@
module Merb
module AuthorsHelper
end
end

View File

@ -0,0 +1,5 @@
module Merb
module CommentsHelper
end
end

View File

@ -0,0 +1,105 @@
module Merb
module GlobalHelpers
def nl2br(str)
str.gsub(/\n/, '<br />')
end
def error_messages_for(obj)
obj = instance_variable_get("@#{obj.to_s}") if obj.is_a?(Symbol)
return nil if obj.errors.nil? or obj.errors.empty?
res = []
res << "<br /><div id='errorExplanation'>"
res << "<p>The following errors prevented the model from being saved:</p>"
res << "<ol>"
obj.errors.each do |field, msg|
res << "<li>#{msg}</li>"
end
res << "</ol>"
res << "</div>"
res << "<br />"
res.join
end
def show_page_description(page)
page_cache = Cache.get(page.cache_name)
if page_cache.nil?
redcloth_opts = [
:textile,
:block_textile_prefix,
:block_textile_lists,
:inline_textile_code,
:inline_textile_link,
:inline_textile_image,
:inline_textile_span,
:glyphs_textile
]
desc = h(page.description.to_s).to_s.gsub(/\&quot\;/, '"')
# i need pre/code block together... because i code :)
desc.gsub!("&lt;pre&gt;&lt;code&gt;", "<pre><code>")
desc.gsub!("&lt;/pre&gt;&lt;/code&gt;", "</pre></code>")
rc = RedCloth.new(desc)
rc.no_span_caps = true
rc.filter_styles = true
page_cache = rc.to_html(redcloth_opts).gsub(Page.wiki_word_pattern) do |match|
pg_name = $1
if Page.exists?(pg_name)
"<a class='wiki_link' style='color: #00F;' href='#{url(:page, pg_name.gsub(/ /, '_'))}'>#{pg_name}</a>"
else
"<a class='missing_wiki_link' rel='nofollow' style='color: #00F;' href='#{url(:new_page, :new_name => pg_name.gsub(/ /, '_'))}'>#{pg_name}</a>?"
end
end
Cache.put(page.cache_name, page_cache)
end
page_cache
end
def show_page_link(page)
"<a href='#{url(:page, :id => page.name.gsub(/ /, '_'))}'>#{page.name}</a>"
end
def tag_cloud(tags)
max = 0
tags.each { |tag| max = tag.count.to_i if tag.count.to_i > max }
min = max
tags.each { |tag| min = tag.count.to_i if tag.count.to_i < min }
divisor = ((max - min) / tag_cloud_styles.size) + 1
tags.collect { |t| "<span class='#{tag_cloud_styles[(t.count.to_i - min) / divisor]}'><a href='#{url(:tag, :id => t.name)}'>#{t.name}</a></span>" }.join(' ')
end
def tag_cloud_styles
%w(tag_cloud_1 tag_cloud_2 tag_cloud_3 tag_cloud_4 tag_cloud_5 tag_cloud_6 tag_cloud_7 tag_cloud_8 tag_cloud_9 tag_cloud_10 tag_cloud_11 tag_cloud_12)
end
def allowed_to?(name, obj = nil)
return false if session[:author_id].nil?
@author_for_permissions ||= Author.find(session[:author_id])
has_base = Permission.author_has_permission_to?(name, @author_for_permissions)
if obj and obj.respond_to?('author_id') and obj.author_id != session[:author_id]
has_base and Permission.author_has_permission_to?("any_#{name}", @author_for_permissions)
else
has_base
end
end
def block_to_partial(partial_name, options = {}, &block)
options.merge!(:body => capture(&block))
concat(partial(partial_name, :locals => options), block.binding)
end
def photo_url(photo)
"/photos/#{photo.id}/#{photo.filename}"
end
def screen_photo_url(photo)
url(:controller => 'photos', :action => 'screen', :id => photo.id)
end
def thumbnail_photo_url(photo)
url(:controller => 'photos', :action => 'thumbnail', :id => photo.id)
end
def indicator
"<img src='/images/ajax-loader.gif' id='indicator' alt='indicator' style='display: none;' />"
end
end
end

View File

@ -0,0 +1,5 @@
module Merb
module InvitationsHelper
end
end

View File

@ -0,0 +1,4 @@
module Merb
module NewsHelper
end
end

View File

@ -0,0 +1,7 @@
module Merb
module PagesHelper
def edit_page_link(page)
"<a href='#{url(:page, :id => page.name.gsub(/ /, '_'))}' title='#{h(page.name)}'>#{h(page.name)}</a>"
end
end
end

View File

@ -0,0 +1,5 @@
module Merb
module PermissionsHelper
end
end

View File

@ -0,0 +1,5 @@
module Merb
module PhotoTagsHelper
end
end

View File

@ -0,0 +1,5 @@
module Merb
module PhotosHelper
end
end

View File

@ -0,0 +1,5 @@
module Merb
module SessionsHelper
end
end

View File

@ -0,0 +1,12 @@
module Merb
module TagsHelper
def highlight(text, phrase)
if text.blank? || phrase.blank?
text
else
match = Array(phrase).map { |p| Regexp.escape(p) }.join('|')
text.gsub(/(#{match})/i, '<strong class="highlight">\1</strong>')
end
end
end
end

46
app/models/album.rb Normal file
View File

@ -0,0 +1,46 @@
class Album < ActiveRecord::Base
validates_presence_of :name
validates_uniqueness_of :name
validates_format_of :name, :with => /^[\w ]+$/
has_and_belongs_to_many :tags, :order => 'tags.name ASC'
has_many :photos
after_create :save_tags
def tag_names
self.tags.collect { |t| t.name }.join(' ')
end
def tag_names=(newtags)
tag_name_ary = newtags.split if newtags.is_a?(String)
tag_name_ary ||= newtags
new_tags = []
tag_name_ary.each do |tname|
t = Tag.find_by_name tname
t ||= Tag.create :name => tname
new_tags << t
end
self.tags = new_tags
end
def album_thumbnail
self.photos.first
end
def self.for_select
self.find(:all, :select => 'name', :order => 'name ASC').collect do |a|
a.name
end
end
def self.popular_tags(limit = nil)
query = "SELECT tags.id, tags.name, count(*) AS count FROM albums_tags, tags, albums WHERE tags.id = tag_id AND albums_tags.album_id = albums.id GROUP BY tags.id, tags.name ORDER BY tags.name ASC"
query << " LIMIT #{limit}" unless limit.nil?
Tag.find_by_sql(query)
end
protected
def save_tags
self.tags.each { |x| x.save }
end
end

45
app/models/author.rb Normal file
View File

@ -0,0 +1,45 @@
require 'digest/sha1'
class Author < ActiveRecord::Base
validates_uniqueness_of :name
validates_presence_of :name
validates_format_of :name, :with => /^\w+$/
attr_accessor :password, :password_confirmation
attr_protected :encrypted_password, :salt
has_and_belongs_to_many :permissions
has_many :pages
before_save :encrypt_password
def self.authenticate(username, password)
user = self.find_by_name(username)
return nil if user.nil?
user.matches_password?(password) ? user : nil
end
def matches_password?(cleartext_password)
self.encrypted_password == Digest::SHA1.hexdigest("---#{cleartext_password}---#{self.salt}---")
end
protected
def encrypt_password
skip = false
if self.password.to_s.empty? or self.password_confirmation.to_s.empty?
if self.encrypted_password.to_s.empty?
self.errors.add(:password, 'cannot be blank')
else
skip = true
end
elsif self.password != self.password_confirmation
self.errors.add(:passwords, 'do not match')
end
return false unless self.errors.empty?
return if skip
self.salt = Digest::SHA1.hexdigest("---#{Time.now}---#{rand.to_s}---")
self.encrypted_password = Digest::SHA1.hexdigest("---#{self.password}---#{self.salt}---")
self.encrypted_password
end
end

12
app/models/comment.rb Normal file
View File

@ -0,0 +1,12 @@
class Comment < ActiveRecord::Base
belongs_to :page
belongs_to :author
def name
if self.author
self.author.name
else
self.user
end
end
end

19
app/models/invitation.rb Normal file
View File

@ -0,0 +1,19 @@
class Invitation < ActiveRecord::Base
before_create :set_invitation_code
validates_presence_of :recipient
validates_format_of :recipient, :with => /^.+\@.+\.\w{2,3}$/,
:message => 'appears to be a fake'
attr_accessor :recipient
protected
def set_invitation_code
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
check = nil
begin
check = ''
1.upto(32) { |k| check << chars[rand(chars.size - 1)] }
end while Invitation.find_by_code(check)
self.code = check
end
end

69
app/models/page.rb Normal file
View File

@ -0,0 +1,69 @@
class Page < ActiveRecord::Base
validates_format_of :name, :with => /^[\w ]+$/
validates_uniqueness_of :name
validates_format_of :department, :with => /^[\w]+$/, :allow_nil => true, :allow_blank => true
has_many :comments, :order => 'created_at ASC'
has_and_belongs_to_many :tags, :order => 'tags.name ASC'
belongs_to :author
attr_protected :author_id
has_and_belongs_to_many :pages, :join_table => 'wiki_words', :foreign_key => :source_id, :class_name => 'Page', :association_foreign_key => :destination_id
has_and_belongs_to_many :pages_that_link_to_me, :join_table => 'wiki_words', :foreign_key => :destination_id, :association_foreign_key => :source_id, :class_name => 'Page'
before_create :set_author_id
after_save :update_wiki_words
after_save :destroy_cache
def self.exists?(name)
!self.find_by_name(name).nil?
end
def tag_names
self.tags.collect { |t| t.name }.join(' ')
end
def tag_names=(newtags)
tag_name_ary = newtags.split if newtags.is_a?(String)
tag_name_ary ||= newtags
new_tags = []
tag_name_ary.each do |tname|
t = Tag.find_by_name tname
t ||= Tag.create :name => tname
new_tags << t
end
self.tags = new_tags
end
def self.popular_tags(limit = nil)
query = "SELECT tags.id, tags.name, count(*) AS count FROM pages_tags, tags, pages WHERE tags.id = tag_id AND pages_tags.page_id = pages.id GROUP BY tags.id, tags.name ORDER BY tags.name ASC"
query << " LIMIT #{limit}" unless limit.nil?
Tag.find_by_sql(query)
end
def cache_name
"RedCloth_#{self.id}"
end
def self.wiki_word_pattern
/\[\[([A-Za-z0-9 ]+)\]\]/
end
protected
def set_author_id
self.author_id ||= Application.current_author_id
end
def update_wiki_words
self.pages.clear
self.description.gsub(Page.wiki_word_pattern) do |match|
p = Page.find_by_name($1) rescue nil
WikiWord.create :source_id => self.id, :destination_id => p.id if p
end
end
def destroy_cache
Cache.delete(self.cache_name)
self.pages_that_link_to_me.each { |p| Cache.delete(p.cache_name) }
end
end

12
app/models/permission.rb Normal file
View File

@ -0,0 +1,12 @@
class Permission < ActiveRecord::Base
has_and_belongs_to_many :authors
validates_presence_of :name
validates_uniqueness_of :name
def self.author_has_permission_to?(name, author = nil)
p = self.find_by_name(name.to_s)
p ||= self.create :name => name.to_s # auto-create permission if necessary
p.authors.include?(author)
end
end

97
app/models/photo.rb Normal file
View File

@ -0,0 +1,97 @@
class Photo < ActiveRecord::Base
attr_accessor :file
validates_presence_of :author_id, :album_id
belongs_to :album
belongs_to :author
has_many :photo_tags, :dependent => :destroy
has_many :tags, :through => :photo_tags
before_validation_on_create :set_author_id
before_create :validate_image_sanity
after_create :create_directories
before_destroy :destroy_directories
attr_protected :author_id
##
# Determines the base directory for all files in this model.
#
def base_directory
"#{Merb.root}/public/photos/#{id}"
end
def self.popular_tags(limit = nil)
query = "SELECT tags.id, tags.name, count(*) AS count FROM photo_tags, tags, photos WHERE tags.id = tag_id AND photo_tags.photo_id = photos.id GROUP BY tags.id, tags.name ORDER BY tags.name ASC"
query << " LIMIT #{limit}" unless limit.nil?
Tag.find_by_sql(query)
end
protected
##
# Sets the Author marker for ownership on creation.
#
def set_author_id
self.author_id ||= Application.current_author_id
end
##
# Checks to make sure that the file exists and is an image.
#
def validate_image_sanity
if self.file[:tempfile].nil?
self.errors.add(:file, 'File is not a file')
end
if self.file[:content_type] !~ /image\/\w+/
self.errors.add(:file, 'File is not a supported type')
end
if self.file[:size] > 3 * 1048576
self.errors.add(:file, 'File is too big (3MB max)')
end
return false unless self.errors.empty?
begin
@fstr = self.file[:tempfile].read
iary = Magick::Image.from_blob(@fstr)
self.filename = File.basename(self.file[:filename]).gsub(/[^\w._-]/, '')
if iary.first.to_s =~ / (\d+)x(\d+) /
self.width = $1
self.height = $2
end
rescue
$stderr.puts("Caught an exception saving an image:")
$stderr.puts("* #{$!}")
self.errors.add(:file, 'File could not be read as an image')
return false
end
self.content_type = self.file[:content_type]
true
end
##
# Makes the directories and writes the file to disk.
#
def create_directories
File.umask(0022)
Dir.mkdir(base_directory) unless File.exist?(base_directory)
File.open("#{base_directory}/#{self.filename}", "w") do |f|
f.puts(@fstr)
end
File.chmod(0644, "#{base_directory}/#{self.filename}")
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

5
app/models/photo_tag.rb Normal file
View File

@ -0,0 +1,5 @@
class PhotoTag < ActiveRecord::Base
belongs_to :photo
belongs_to :tag
validates_presence_of :photo_id, :tag_id, :x, :y
end

28
app/models/tag.rb Normal file
View File

@ -0,0 +1,28 @@
class Tag < ActiveRecord::Base
validates_format_of :name, :with => /^\w+$/
validates_uniqueness_of :name
has_and_belongs_to_many :pages, :order => 'pages.name ASC'
has_and_belongs_to_many :albums, :order => 'albums.name ASC'
has_many :photo_tags, :dependent => :destroy
has_many :photos, :through => :photo_tags
def self.popular_tags
tags = Page.popular_tags
a_tags = Album.popular_tags
p_tags = Photo.popular_tags
[ a_tags, p_tags ].each do |ary|
ary.each do |tag|
t = tags.detect { |t2| t2.name == tag.name }
if t
t.count = t.count.to_i + tag.count.to_i
else
tags << tag
end
end
end
tags.sort { |a,b| a.name <=> b.name }
end
end

2
app/models/wiki_word.rb Normal file
View File

@ -0,0 +1,2 @@
class WikiWord < ActiveRecord::Base
end

View File

@ -0,0 +1,34 @@
<fieldset>
<legend>Album Details</legend>
<p>
<%= text_control :name, :label => 'Name: ' %>
</p>
<h3>Tags</h3>
<p>
<p><a href="#" onclick="$('album[tag_names]').value = ''; return false;"><img src="/images/edit-clear.png" style="vertical-align: top;" /></a> <%= text_control 'tag_names', :size => 30 -%></p>
<div id="tag_auto_complete" class="auto_complete"></div>
</p>
</fieldset>
<script type="text/javascript">
//<![CDATA[
new Ajax.Autocompleter(
'album_tag_names',
'tag_auto_complete',
'/tags/auto_complete',
{
paramName: 'id',
updateElement: function(tag_name)
{
var new_tag = tag_name.innerHTML.gsub(/\<[^>]+\>/, '');
var existing_tags = $('album_tag_names').value.gsub(/( |^)[^ ]+$/, '');
var plus_space = (existing_tags.length == 0 ? '' : ' ');
$('album_tag_names').value = existing_tags + plus_space + new_tag;
$('album_tag_names').focus();
}
}
);
//]]>
</script>

View File

@ -0,0 +1,12 @@
<% throw_content :for_sidebar do -%>
<a href="<%= url(:album, :id => @album.name.gsub(/ /, '_')) -%>"><img src="/images/camera-photo.png" /> Back to <%= @album.name -%></a><br />
<% end -%>
<%= error_messages_for :album %>
<% form_for :album, :action => url(:album, :id => @album.name.gsub(/ /, '_')) do %>
<%= partial :album_form %>
<p>
<%= submit_button 'Update' %>
</p>
<% end -%>

View File

@ -0,0 +1,40 @@
<% throw_content :for_sidebar do -%>
<% if allowed_to?(:create_albums) -%><a href="<%= url(:new_album) -%>"><img src="/images/folder-new.png" alt="Create Album" /> Create An Album</a><br /><% end -%>
<% if allowed_to?(:upload_images) -%><a href="<%= url(:new_photo) -%>"><img src="/images/emblem-photos.png" /> Upload Image</a><br /><% end %>
<div id="tag_cloud">
<p>Popular Tags</p>
<%= tag_cloud @tags %>
</div>
<% end -%>
<% throw_content :for_stylesheet do -%>
.photo_collection {
word-wrap: break-word;
}
.photo_collection_item {
float: right;
width: 170px;
min-height: 140px;
max-height: 200px;
margin: 5px;
padding: 5px;
text-align: center;
border: 1px solid #BBB;
}
<% end -%>
<% if @albums.empty? -%>
<p><em><strong>There were no albums found!</strong></em></p>
<% else -%>
<div class="photo_collection">
<% @albums.each do |album| -%>
<div class="photo_collection_item">
<p><a href="<%= url(:album, :id => album.name.gsub(/ /, '_')) -%>"><%= album.name -%></a> (<%= album.photos.size -%> photos)</p>
<% if album.album_thumbnail -%><a href="<%= url(:album, :id => album.name.gsub(/ /, '_')) -%>"><img src="<%= thumbnail_photo_url(album.album_thumbnail) -%>" /></a><% end -%>
</div>
<% end -%>
</div>
<% end -%>

View File

@ -0,0 +1,8 @@
<%= error_messages_for :album %>
<% form_for :album, :action => url(:album) do %>
<%= partial :album_form %>
<p>
<%= submit_button 'Create' %>
</p>
<% end -%>

View File

@ -0,0 +1,30 @@
<% throw_content :for_sidebar do -%>
<% if allowed_to?(:edit_album) -%><a href="<%= url(:edit_album, :id => @album.name.gsub(/ /, '_')) -%>" rel="nofollow"><img src="/images/document-save.png" /> Edit Album</a><br /><% end %>
<% if allowed_to?(:delete_albums) -%><a href="<%= url(:delete_album, :id => @album.name.gsub(/ /, '_')) -%>" onclick="if(!confirm('Are you sure you want to delete this album?')){return false;}"><img src="/images/edit-delete.png" /> Destroy Album</a><br /><% end %>
<% if allowed_to?(:upload_images) -%><a href="<%= url(:new_photo, :photo => { :album_id => @album.id }) -%>"><img src="/images/emblem-photos.png" /> Upload Image</a><br /><% end %>
<% end -%>
<% throw_content :for_stylesheet do -%>
.photo {
margin: 10px;
}
<% end -%>
<div class="hentry">
<h1><%= @album.name -%></h1>
<% @album.photos.each_with_index do |photo, idx| -%>
<% if (idx + 1) % 3 == 1 -%><p><% end -%>
<span class="photo"><a href="<%= url(:photo, photo) -%>" rel="nofollow" onclick="window.open(this.href);return false;"><img src="<%= thumbnail_photo_url(photo) -%>" /></a></span>
<% if (idx + 1) % 3 == 0 or @album.photos.size == (idx + 1) -%></p><% end -%>
<% end -%>
<% unless @album.tags.empty? -%>
<br style="clear: both;" />
<ul class="meta">
<li>Tags: <%= @album.tags.collect { |t| "<a href='#{url(:tag, :id => t.name)}' title='#{t.name}'>#{t.name}</a>" }.join(' ') -%></li>
</ul>
<% end -%>
</div>

View File

@ -0,0 +1,18 @@
<fieldset>
<legend>Create an author</legend>
<p>
<%= text_control :name, :label => 'Name: ' %>
</p>
<p>
Invitation Code: <strong><em><%= (params[:invitation_code].to_s.empty? ? 'None! This will not work!' : params[:invitation_code]) -%><%= hidden_field :name => 'invitation_code', :value => params[:invitation_code] -%></em></strong>
</p>
<p>
<%= text_control :url, :label => 'Home URL: ' %>
</p>
<p>
<%= password_control :password, :label => 'Password: ', :size => 40 %>
</p>
<p>
<%= password_control :password_confirmation, :label => 'Password (Confirm): ', :size => 40 %>
</p>
</fieldset>

View File

@ -0,0 +1,8 @@
<%= error_messages_for :author %>
<% form_for :author, :action => url(:author, :id => @author.name) do -%>
<%= partial :author_form %>
<p>
<%= submit_button 'Update' %>
</p>
<% end -%>

View File

@ -0,0 +1,14 @@
<% throw_content :for_sidebar do -%>
<% if allowed_to?(:send_invitations) -%><a href="<%= url(:new_invitation) -%>"><img src="/images/mail-message-new.png" alt="Send Invitation" /> Send Invitation</a><br /><% end -%>
<% unless logged_in? -%><a href="<%= url(:new_author) -%>"><img src="/images/contact-new.png" /> Sign up!</a><br /><% end -%>
<% end -%>
<% if @authors.empty? -%>
<p><em><strong>There were no authors found!</strong></em></p>
<% else -%>
<ol>
<% @authors.each do |author| -%>
<li><a href="<%= url(:author, :id => author.name) -%>"><%= author.name -%></a></li>
<% end -%>
</ol>
<% end -%>

View File

@ -0,0 +1,8 @@
<%= error_messages_for :author %>
<% form_for :author, :action => url(:author) do %>
<%= partial :author_form %>
<p>
<%= submit_button 'Create' %>
</p>
<% end -%>

View File

@ -0,0 +1,8 @@
<% throw_content :for_sidebar do -%>
<% if @author.id == session[:author_id] or allowed_to?(:edit_author, @author) -%><a href="<%= url(:edit_author, :id => @author.name) -%>" rel="nofollow"><img src="/images/document-save.png" /> Edit Author</a><br /><% end %>
<% if allowed_to?(:delete_authors) -%><a href="<%= url(:delete_author, :id => @author.name) -%>" onclick="if(!confirm('Are you sure you want to delete this author?')){return false;}"><img src="/images/edit-delete.png" /> Destroy Author</a><br /><% end %>
<% unless @author.url.to_s.empty? -%><a href="<%= h(@author.url) -%>" target="new"><img src="/images/go-home.png" /> Home URL</a><br /><% end -%>
<% if allowed_to?(:change_permissions) -%><a href="<%= url(:edit_permission, :id => @author.id) -%>"><img src="/images/preferences-system.png" /> Change Permissions</a><br /><% end %>
<% end -%>
<h1><%= @author.name -%></h1>

View File

@ -0,0 +1,21 @@
<fieldset>
<legend>Post a comment on <em><%= @page.name -%></em></legend>
<%= hidden_field :name => 'page_id', :value => @page.name.gsub(/ /, '_') %>
<% if logged_in? -%>
<p>
Author: <%= Author.find(session[:author_id]).name -%><%= hidden_field :name => 'comment[author_id]', :value => session[:author_id] -%>
</p>
<% else -%>
<p>
<%= text_control :user, :label => 'Name: ', :size => 32 %>
</p>
<% end -%>
<p>
<%= text_control :url, :label => 'URL: ', :size => 60, :max_size => 256 %>
</p>
<p>
<%= text_area_control :comment, :label => 'Comment: ', :rows => 8, :cols => 60 %>
</p>
</fieldset>

View File

@ -0,0 +1,12 @@
<% throw_content :for_sidebar do -%>
<a href="<%= url(:page, :id => @page.name.gsub(/ /, '_')) -%>"><img src="/images/text-html.png" alt="Return to page" /> Return to <%= @page.name -%></a><br />
<% end -%>
<%= error_messages_for :comment %>
<% form_for :comment, :action => url(:comment) do %>
<%= partial :comment_form %>
<p>
<%= submit_button 'Create' %>
</p>
<% end -%>

View File

@ -0,0 +1,216 @@
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title><%= @exception_name %></title>
<style type="text/css" media="screen">
body {
font-family:arial;
font-size:11px;
}
h1 {
font-size:48px;
letter-spacing:-4px;
margin:0;
line-height:36px;
color:#333;
}
h1 sup {
font-size: 0.5em;
}
h1 sup.error_500, h1 sup.error_400 {
color:#990E05;
}
h1 sup.error_100, h1 sup.error_200 {
color:#00BF10;
}
h1 sup.error_300 {
/* pretty sure you cant 'see' status 300
errors but if you could I think they
would be blue */
color:#1B2099;
}
h2 {
font-size:36px;
letter-spacing:-3px;
margin:0;
line-height:28px;
color:#444;
}
a, a:visited {
color:#00BF10;
}
.internalError {
width:800px;
margin:50px auto;
}
.header {
border-bottom:10px solid #333;
margin-bottom:1px;
background-image: url("data:image/gif;base64,R0lGODlhAwADAIAAAP///8zMzCH5BAAAAAAALAAAAAADAAMAAAIEBHIJBQA7");
padding:20px;
}
table.trace {
width:100%;
font-family:courier, monospace;
letter-spacing:-1px;
border-collapse: collapse;
border-spacing:0;
}
table.trace tr td{
padding:0;
height:26px;
font-size:13px;
vertical-align:middle;
}
table.trace tr.file{
border-top:2px solid #fff;
background-color:#F3F3F3;
}
table.trace tr.source {
background-color:#F8F8F8;
display:none;
}
table.trace .open tr.source {
display:table-row;
}
table.trace tr.file td.expand {
width:23px;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAXCAIAAABvSEP3AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdVJREFUeNqMVL+TwUAYxaRIOlEhlZHGDAUzzOQ61+AqXMV1lJSU7q/QRqm8KFUcJTNn5qJkaPyoKKVz7y4mF8na5Kt29tt9+/Z97/u81+vVQ4r9frdarS6Xi7ETDIZisRjxMGPfmk4niNPpZE+xLAugbPaZ53nzvtfMBe/3+/3dbuehBrAKhZdUKkVAWa9Xsiybv0CPZDJZLr/qa5/BwgwRjYqOKIvFYjQa/aNommZh0Ww2K5UqzwfoQOPxaLPZ3FAmk0+7lplMpt1u53J5OpBOR0eZEE9wHJfP5zud93g88QhluwWbjW+5VOmKBgKBer3eaDTDYeGBQF8+x7rqIYoiPgixWJazpA6HA+MSxRArkUgMh0M409g8Ho8+9wYxxCqVSq1W26EDHGM2m4HOHQrEc38f/Yn7cLmlIRhBENzcx8cVRZnPZ/YUep2BWkjTIfA+PKVpZAXR5QxsjiqCKvGEqqp443w+0dvy17swqD0HB3S73V5PpkNg1qBqt8kwGCjmPkinM0QJbIoEa7U6UG6ToVgs4V9G2g0ESoP5Aoi7KYX5oCgf8IKbkvn9/mr1LRQKESamzgJy0g0tSZIuB3nuGqRU9Vv9C4sKkUhEkp4soxvxI8AAhWrrtXa3X8EAAAAASUVORK5CYII=);
background-position:top left;
background-repeat:no-repeat;
}
table.trace .open tr.file td.expand {
width:19px;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAB1CAIAAAAqdO2mAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAXZJREFUeNrslK1ywkAUhcMOBomEOiSdqLxEBJX0NaijOsjyHGGmCGyQQYaiiiw4gktkcOmZbpsuuzQ/M5XnqJ2d3S/n3nM3rTzPLUP7/Tt0+pLcGQwG3W53OLyHzPMtjYL7q9UqSRLrD4E1Gj1orCvKYuFHUWTVkOM44/HjDcp8/lL4r6NerzeZPMm1KFw0QkDn83m5fP2lHA4fNQvRtNvtjsfDd0WzmSfb2e/fdTqdOvdh/HLJZLOn0+d2HJ+KRGzbdl23EpFlmed5cp2maRzHQq1lvQ5KMi6EUZBGfup6E1pTfd+vrGW7jbQ2C9hTt9BpqNyIWaAwAy6xg2eBz5iRC/NomiZhGN5sqmnkauo0BUGgVQoBjQ80oCACgNQdZHfTYBkF2mxCtWWAqunWpahxIDUt3QYUxIFQpJHyIWpXjinabKbbwItMHT+NyjchrP8QKaSQQgoppJBCCimkkEIKKaSQQgoppJBCCimkkEIKKaSo+hRgAEFD17X08O2NAAAAAElFTkSuQmCC);
background-position:top left;
background-repeat:no-repeat;
}
table.trace tr.source td.collapse {
width:19px;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAB1CAIAAAAqdO2mAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAVxJREFUeNrs0zFygkAUBmBlUkgJHdABlQwVkVJKKUxBYWbkALTxMJwhltyDFkss03IF8pudIcwaDaDl/6pd2P327b7d+eHwMXs4lNkzggoVKlSoUKFChQoVKlSoUKFChQoVKlSoUKFChQqVEYqm6ft9+qiSJEkYho7jTlcw2fd9NOI4nq4gEdFwXXe1Cqco63VkWVbXRTqLhTpOwQRpF7quR1E0TgGhqvLKUFCyoQqG/rks3O6kZKW/eRFpevOCoGTXVTcMQ5EyxyDEkML1c5RzuZOICIyXqn7JBVez6282MWrx731HOv2qB8Hri2lamNk0DfpVVdV1Peodappmmua8bdvzuc7zfNprzrLMth1FnGh/X8MjCAIQv/cFz/+65PcDh7rbvYv2ZUfdj+PxsyzLgVl0hKwgTqeqKApx2LeOc7t98zyv/1FWOgvx9RPii23bmL9cetJ8Ed8CDAC6aFW8bCzFhwAAAABJRU5ErkJggg==);
background-position:bottom left;
background-repeat:no-repeat;
background-color:#6F706F;
}
table.trace tr td.path {
padding-left:10px;
}
table.trace tr td.code {
padding-left:35px;
white-space: pre;
line-height:9px;
padding-bottom:10px;
}
table.trace tr td.code em {
font-weight:bold;
color:#00BF10;
}
table.trace tr td.code a {
width: 20px;
float: left;
}
table.trace tr td.code .more {
color:#666;
}
table.trace tr td.line {
width:30px;
text-align:right;
padding-right:4px;
}
.footer {
margin-top:5px;
font-size:11px;
color:#444;
text-align:right;
}
</style>
</head>
<body>
<div class="internalError">
<div class="header">
<h1><%= @exception_name %> <sup class="error_<%= @exception.class::STATUS %>"><%= @exception.class::STATUS %></sup></h1>
<% if show_details = ::Merb::Config[:exception_details] -%>
<h2><%= @exception.message %></h2>
<% else -%>
<h2>Sorry about that...</h2>
<% end -%>
<h3>Parameters</h3>
<ul>
<% params[:original_params].each do |param, value| %>
<li><strong><%= param %>:</strong> <%= value.inspect %></li>
<% end %>
<%= "<li>None</li>" if params[:original_params].empty? %>
</ul>
<h3>Session</h3>
<ul>
<% params[:original_session].each do |param, value| %>
<li><strong><%= param %>:</strong> <%= value.inspect %></li>
<% end %>
<%= "<li>None</li>" if params[:original_session].empty? %>
</ul>
<h3>Cookies</h3>
<ul>
<% params[:original_cookies].each do |param, value| %>
<li><strong><%= param %>:</strong> <%= value.inspect %></li>
<% end %>
<%= "<li>None</li>" if params[:original_cookies].empty? %>
</ul>
</div>
<% if show_details %>
<table class="trace">
<% @exception.backtrace.each_with_index do |line, index| %>
<tbody class="close">
<tr class="file">
<td class="expand">
</td>
<td class="path">
<%= (line.match(/^([^:]+)/)[1] rescue 'unknown').sub(/\/((opt|usr)\/local\/lib\/(ruby\/)?(gems\/)?(1.8\/)?(gems\/)?|.+\/app\/)/, '') %>
<% unless line.match(/\.erb:/) %>
in "<strong><%= line.match(/:in `(.+)'$/)[1] rescue '?' %></strong>"
<% else %>
(<strong>ERB Template</strong>)
<% end %>
</td>
<td class="line">
<a href="txmt://open?url=file://<%=file = (line.match(/^([^:]+)/)[1] rescue 'unknown')%>&amp;line=<%= lineno = line.match(/:([0-9]+):/)[1] rescue '?' %>"><%=lineno%></a>&nbsp;
</td>
</tr>
<tr class="source">
<td class="collapse">
</td>
<td class="code" colspan="2"><% (__caller_lines__(file, lineno, 5) rescue []).each do |llineno, lcode, lcurrent| %>
<a href="txmt://open?url=file://<%=file%>&amp;line=<%=llineno%>"><%= llineno %></a><%='<em>' if llineno==lineno.to_i %><%= lcode.size > 90 ? CGI.escapeHTML(lcode[0..90])+'<span class="more">......</span>' : CGI.escapeHTML(lcode) %><%='</em>' if llineno==lineno.to_i %>
<% end %>
</td>
</tr>
</tbody>
<% end %>
</table>
<script type="text/javascript" charset="utf-8">
// swop the open & closed classes
els = document.getElementsByTagName('td');
for(i=0; i<els.length; i++){
if(els[i].className=='expand' || els[i].className=='collapse'){
els[i].onclick = function(e){
tbody = this.parentNode.parentNode;
if(tbody.className=='open'){
tbody.className='closed';
}else{
tbody.className='open';
}
}
}
}
</script>
<% end %>
<div class="footer">
lots of love, from <a href="#">merb</a>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1 @@
<p><%= params[:exception] %></p>

View File

@ -0,0 +1 @@
<p>The requested resource <em><strong><%= h(request.uri) -%></em></strong> could not be found.</p>

View File

@ -0,0 +1,11 @@
Hello,
You have been given an invitation to join the TuxBliki.
Check it out at: http://penguincoder.org
Sign up for your account with this address:
<%= url(:new_author, :invitation_code => @invitation.code) %>
Thanks,
The PenguinCoding Initiative

View File

@ -0,0 +1,11 @@
<% form_for :invitation, :action => url(:invitation) do -%>
<fieldset>
<legend>Invite A Drinker</legend>
<p>
<%= text_control 'recipient', :label => 'Recipient: ' %>
</p>
</fieldset>
<p>
<%= submit_button 'Send' %>
</p>
<% end -%>

View File

@ -0,0 +1,88 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
<head>
<title>PenguinCoder's TuxBliki<% if @page_title -%> :: <%= @page_title -%><% end -%><% if @secondary_title -%> :: <%= @secondary_title -%><% end -%></title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="/stylesheets/application.css" type="text/css" media="screen" charset="utf-8" />
<script src="/javascripts/prototype.js" type="text/javascript"></script>
<script src="/javascripts/scriptaculous.js" type="text/javascript"></script>
<style type="text/css">
<%= catch_content :for_stylesheet %>
</style>
<script type="text/javascript">
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
oldonload();
func();
}
}
}
<%= catch_content :for_javascript %>
</script>
</head>
<body>
<div id="container">
<% flash.keys.each do |key| -%>
<div id="<%= key -%>">
<%= flash[key] %>
</div>
<% end -%>
<div id="header">
<span style="float: left; margin: 0px 20px 0px 0px"><img src="/images/penguincoder-logo.png" /></span>
<h1><%= @page_title or 'TuxBliki' -%></h1>
<% if @secondary_title -%><h2><%= @secondary_title -%></h2><% end -%>
<br style="clear: both" />
<%
links = []
links << [ 'Blog', '/', 'internet-group-chat.png' ]
links << [ 'Wiki', url(:pages), 'text-html.png' ]
links << [ 'Post', url(:new_page), 'accessories-text-editor.png' ] if allowed_to?(:create_pages)
links << [ 'Photo Albums', url(:albums), 'camera-photo.png' ]
links << [ 'Authors', url(:authors), 'system-users.png' ]
links << [ 'Tags', url(:tags), 'preferences-desktop-font.png' ]
if logged_in?
links << [ 'Logout', url(:delete_session, :id => session[:author_id]), 'system-log-out.png' ]
else
links << [ 'Login', url(:new_session), 'system-lock-screen.png' ]
end
links << [ 'Help', url(:page, :id => 'Help'), 'help-browser.png' ]
-%>
<div><%= links.collect { |l| "<a href='#{l[1]}'><img src='/images/#{l[2]}' alt='#{l[0]}' /> #{l[0]}</a>" }.join(' | ') -%></div>
</div>
<div id="page">
<div id="content">
<%= catch_content :for_layout %>
</div>
<div id="sidebar">
<%= catch_content :for_sidebar %>
</div>
<br style="clear: both" />
</div>
<div id="footer">
<hr />
<p>&copy; 2004 - 2008 penguincoder</p>
<ul>
<li><a href="http://merbivore.com">merb</a></li>
<li><a href="http://quotedprintable.com/pages/scribbish">scribbish</a></li>
</ul>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,54 @@
<% throw_content :for_sidebar do -%>
<div id="tag_cloud">
<p>Popular Tags</p>
<%= tag_cloud @tags %>
</div>
<div id="things_i_do">
<div class="title">Things I Do</div>
<p>
<a href="http://github.com/penguincoder"><img src="/images/utilities-terminal.png" /> Code on Github</a><br />
<a href="http://del.icio.us/penguincoder"><img src="/images/delicious.med.gif" /> Del.icio.us Feed</a><br />
</p>
</div>
<% end -%>
<% @secondary_title = "Demolishing innocence for #{time_lost_in_words(Time.now, @oldest_date)}" unless @oldest_date.nil? -%>
<% if @news.empty? -%>
<p><strong><em>There are no news posts, yet.</em></strong></p>
<% else -%>
<% @news.each do |page| -%>
<%= partial 'pages/page', :with => [ page ] %>
<% end -%>
<% if @page_count > 0 -%>
<div id="pagination_links">
<% if @page > 0 -%>
<a href="<%= url(:news, :page => 0) -%>"><img src="/images/go-first.png" alt="First Page" /></a> <a href="<%= url(:news, :page => 0) -%>"><img src="/images/go-previous.png" alt="Previous Page" /></a>
<% end -%>
<% if @page_count > 1 -%>
<% (@page - 4).upto(@page - 1) do |i| ; next if i < 0 -%>
<a href="<%= url(:news, :page => i) -%>"><%= i + 1 -%></a>
<% end %>
<%= @page + 1 %>
<% (@page + 1).upto(@page + 4) do |i| ; next if i >= @page_count -%>
<a href="<%= url(:news, :page => i) -%>"><%= i + 1 -%></a>
<% end %>
<% if @page < @page_count - 1 -%>
<a href="<%= url(:news, :page => @page + 1) -%>"><img src="/images/go-next.png" alt="Next Page" /></a> <a href="<%= url(:news, :page => @page_count - 1) -%>"><img src="/images/go-last.png" alt="Last Page" /></a>
<% end -%>
<% end -%>
</div>
<% end -%>
<% end -%>

View File

@ -0,0 +1,19 @@
<% if !@page.comments.empty? -%>
<h3>Comments</h3>
<ol id="comments" class="comments">
<% @page.comments.each_with_index do |comment, position| -%>
<li class="comment" id="comment-<%= comment.id %>">
<span style="float: right"><% if allowed_to?(:delete_comment, comment) -%><a href="<%= url(:delete_comment, comment) -%>" onclick="if(!confirm('Are you sure you want to delete this comment?')){return false;}" rel="nofollow"><img src="/images/edit-delete.png" /></a><% end -%></span>
<div class="author">
<cite><%= position + 1 -%>. <%= (comment.url.blank?) ? h(comment.name) : "<a href='#{comment.url}'>#{h(comment.name)}</a>" %></cite>
<abbr title="<%= comment.created_at %>">said <%= time_lost_in_words comment.page.created_at, comment.created_at %> later:</abbr>
</div>
<div class="content">
<%= h(comment.comment) %>
</div>
</li>
<% end -%>
</ol>
<br />
<% end -%>

View File

@ -0,0 +1,21 @@
<div class="hentry" id="page-<%= page.object_id %>">
<h2 class="entry-title">
<%= show_page_link(page) %>
<span class='comment_count'><%= "#{page.comments.size} comments" unless page.comments.empty? %></span>
</h2>
<div class="vcard">
Posted by <span class="fn"><%= page.author.name rescue 'AUTHOR' -%></span>
</div>
<abbr class="published" title="<%= page.created_at %>"><%= time_lost_in_words page.created_at %> ago<% unless page.department.to_s.empty? -%> in the <%= page.department -%> department<% end -%>.</abbr>
<br class="clear" />
<div class="entry-content">
<%= show_page_description(page) %>
</div>
<ul class="meta">
<% unless page.tags.empty? -%>
<li>Tags: <%= page.tags.collect { |t| "<a href='#{url(:tag, :id => t.name)}' title='#{t.name}'>#{t.name}</a>" }.join(' ') -%></li>
<% end -%>
<li>Created: <%= page.created_at -%></li>
</ul>
</div>

View File

@ -0,0 +1,54 @@
<%= error_messages_for :page %>
<% form_for :page, :action => url(:page, :id => @page.name.gsub(/ /, '_')) do -%>
<fieldset>
<legend>Update a page</legend>
<h3 style="margin-top: 10px;">Name</h3>
<p><img src="/images/emblem-readonly.png" alt="Read Only" /> <span style="vertical-align: top"><%= (@page.name) %></span></p>
<h3>Original Author</h3>
<p><img src="/images/emblem-readonly.png" alt="Read Only" /> <span style="vertical-align: top"><%= (@page.author.name) %></span></p>
<p><%= checkbox_control :published, :label => ' Published in blog?', :value => "1" %></p>
<h3>Department</h3>
<p><%= text_control :department, :size => 50 %></p>
<h3>Description</h3>
<p><%= text_area_control :description, :rows => 10, :cols => 70 %></p>
<h3>Tags</h3>
<p>
<p><a href="#" onclick="$('page[tag_names]').value = ''; return false;"><img src="/images/edit-clear.png" style="vertical-align: top;" /></a> <%= text_control 'tag_names', :size => 30 -%></p>
<div id="tag_auto_complete" class="auto_complete"></div>
</p>
</fieldset>
<br />
<p><%= submit_button 'Update' %></p>
<% end -%>
<script type="text/javascript">
//<![CDATA[
new Ajax.Autocompleter(
'page_tag_names',
'tag_auto_complete',
'/tags/auto_complete',
{
paramName: 'id',
updateElement: function(tag_name)
{
var new_tag = tag_name.innerHTML.gsub(/\<[^>]+\>/, '');
var existing_tags = $('page_tag_names').value.gsub(/( |^)[^ ]+$/, '');
var plus_space = (existing_tags.length == 0 ? '' : ' ');
$('page_tag_names').value = existing_tags + plus_space + new_tag;
$('page_tag_names').focus();
}
}
);
//]]>
</script>

View File

@ -0,0 +1,16 @@
<% throw_content :for_sidebar do -%>
<div id="tag_cloud">
<p>Popular Tags</p>
<%= tag_cloud @tags %>
</div>
<% end -%>
<% if @pages.empty? -%>
<p><strong><em>No pages were found!</em></strong></p>
<% else -%>
<ol>
<% @pages.each do |page| -%>
<li><%= edit_page_link page -%></li>
<% end -%>
</ol>
<% end -%>

View File

@ -0,0 +1,50 @@
<%= error_messages_for :page %>
<% form_for :page, :action => url(:page) do -%>
<fieldset>
<legend>Create a page</legend>
<h3 style="margin-top: 10px;">Name</h3>
<p><%= text_control :name, :size => 50 %></p>
<p><%= checkbox_control :published, :label => ' Published in blog?', :value => "1" %></p>
<h3>Department</h3>
<p><%= text_control :department, :size => 50 %></p>
<h3>Description</h3>
<p><%= text_area_control :description, :rows => 10, :cols => 70 %></p>
<h3>Tags</h3>
<p>
<p><a href="#" onclick="$('page[tag_names]').value = ''; return false;"><img src="/images/edit-clear.png" style="vertical-align: top;" /></a> <%= text_control 'tag_names', :size => 30 -%></p>
<div id="tag_auto_complete" class="auto_complete"></div>
</p>
</fieldset>
<br />
<p><%= submit_button 'Create' %></p>
<% end -%>
<script type="text/javascript">
//<![CDATA[
new Ajax.Autocompleter(
'page_tag_names',
'tag_auto_complete',
'/tags/auto_complete',
{
paramName: 'id',
updateElement: function(tag_name)
{
var new_tag = tag_name.innerHTML.gsub(/\<[^>]+\>/, '');
var existing_tags = $('page_tag_names').value.gsub(/( |^)[^ ]+$/, '');
var plus_space = (existing_tags.length == 0 ? '' : ' ');
$('page_tag_names').value = existing_tags + plus_space + new_tag;
$('page_tag_names').focus();
}
}
);
//]]>
</script>

View File

@ -0,0 +1,9 @@
<% throw_content :for_sidebar do -%>
<% if allowed_to?(:edit_page, @page) -%><a href="<%= url(:edit_page, :id => @page.name.gsub(/ /, '_')) -%>" rel="nofollow"><img src="/images/document-save.png" /> Edit page</a><br /><% end -%>
<% if allowed_to?(:delete_page, @page) -%><a href="<%= url(:delete_page, :id => @page.name.gsub(/ /, '_')) -%>" onclick="if(!confirm('Are you sure you want to delete this page?')){return false;}" rel="nofollow"><img src="/images/edit-delete.png" /> Destroy page</a><br /><% end -%>
<a href="<%= url(:controller => 'comments', :action => 'new', :page_id => @page.name.gsub(/ /, '_')) -%>" rel="nofollow"><img src="/images/mail-message-new.png" /> Post a comment</a><br />
<% end -%>
<%= partial :page, :with => [ @page ] %>
<%= partial :comments %>

View File

@ -0,0 +1,43 @@
<% throw_content :for_sidebar do -%>
<a href="<%= url(:author, :id => @author.name.gsub(/ /, '_')) -%>"><img src="/images/go-home.png" alt="Author's Home" /> <%= @author.name -%></a><br />
<% end -%>
<script type="text/javascript">
function check_all(form_name, field_name, checkbox_value)
{
if(!document.forms[form_name])
return;
var check_boxes = document.forms[form_name].elements[field_name];
if(!check_boxes)
return;
var count_check_boxes = check_boxes.length;
if(!count_check_boxes)
check_boxes.checked = check_value;
else
// set the check value for all check boxes
for(var i = 0; i < count_check_boxes; i++)
check_boxes[i].checked = checkbox_value;
}
</script>
<% form_for :permission, :action => url(:permission, @author), :id => 'permission_form' do -%>
<%= hidden_field :name => '_method', :value => 'put' %>
<fieldset>
<legend>Select Author's permissions</legend>
<p>Select: <a href="#" onclick="check_all('permission_form', 'permissions[]', true); return false">all</a> | <a href="#" onclick="check_all('permission_form', 'permissions[]', false); return false">none</a></p>
<ul style="list-style-type: none">
<% @permissions.each do |p| -%>
<%
attr = { :name => 'permissions[]', :boolean => false, :value => p.id }
if @author.permissions.include?(p)
attr[:checked] = true
end
-%>
<li><%= checkbox_field attr -%> <%= p.name -%></li>
<% end -%>
</ul>
</fieldset>
<p>
<%= submit_button 'Save' %>
</p>
<% end -%>

View File

@ -0,0 +1,14 @@
<% throw_content :for_sidebar do -%>
<a href="<%= url(:author, :id => @author.name.gsub(/ /, '_')) -%>"><img src="/images/go-home.png" alt="Author's Home" /> <%= @author.name -%></a><br />
<% if allowed_to?(:change_permissions) -%><a href="<%= url(:edit_permission, :id => @author.id) -%>"><img src="/images/preferences-system.png" /> Change Permissions</a><br /><% end %>
<% end -%>
<% if @permissions.empty? -%>
<p><em><strong>User has no permissions.</strong></em></p>
<% else -%>
<ol>
<% @permissions.each do |p| -%>
<li><%= p.name -%></li>
<% end -%>
</ol>
<% end -%>

View File

@ -0,0 +1,14 @@
<h3>Tagged:</h3>
<p>
<% if @photo.nil? or @photo.photo_tags.empty? -%>
None.
<% else -%>
<%= @photo.photo_tags.collect { |t|
str = "<span onmouseover=\"show_tag_at(#{t.x}, #{t.y})\" onmouseout=\"hide_tag_box()\" id=\"photo_tag_#{t.id}\">#{t.tag.name}"
if @editable
str += " (<a href='#' onclick='destroy_photo_tag(#{t.id}); return false;'><img src='/images/edit-delete.png' /> Remove</a>)"
end
str += "</span>" }.join(', ') %>
<% end -%>
</p>

View File

@ -0,0 +1,17 @@
<% throw_content :for_sidebar do -%>
<a href="<%= url(:album, :id => @photo.album.name.gsub(/ /, '_')) -%>"><img src="/images/camera-photo.png" /> Back to <%= @photo.album.name -%></a><br />
<a href="<%= url(:photo, :id => @photo.id) -%>"><img src="/images/image-x-generic.png" /> Back to photo</a><br />
<% end -%>
<%= error_messages_for :photo %>
<% form_for :photo, :action => url(:photo, :id => @photo.id) do %>
<fieldset>
<legend>Change Photo Details</legend>
<p>Photo: <img src="<%= thumbnail_photo_url(@photo) -%>" /></p>
<p>Album: <%= select_control 'album_id', :collection => Album.for_select, :selected => (@photo.album.name rescue nil) -%></p>
</fieldset>
<p>
<%= submit_button 'Update' %>
</p>
<% end -%>

View File

@ -0,0 +1,17 @@
<% throw_content :for_sidebar do -%>
<% if @photo.album -%><a href="<%= url(:album, :id => @photo.album.name.gsub(/ /, '_')) -%>"><img src="/images/camera-photo.png" /> Back to <%= @photo.album.name -%></a><br /><% end %>
<% end -%>
<%= error_messages_for :photo %>
<% form_for :photo, :action => url(:photo), :multipart => true, :onsubmit => "$('indicator').style.display = 'inline';" do %>
<fieldset>
<legend>Upload a photo</legend>
<p>Album: <%= select_control 'album_id', :collection => Album.for_select, :selected => (@photo.album.name rescue nil) -%></p>
<p>File: <%= file_control 'file' -%></p>
</fieldset>
<p>
<%= submit_button 'Create' %> <img src='/images/ajax-loader.gif' id='indicator' style='display:none;' />
</p>
<% end -%>

View File

@ -0,0 +1,231 @@
<% throw_content :for_stylesheet do -%>
#photo_block {
z-index: 0;
border: 1px solid black;
padding: 0px;
width: <%= @width -%>px;
height: <%= @height -%>px;
background-image: url('/photos/screen/<%= @photo.id -%>');
background-repeat: no-repeat;
}
#photo_block_container {
margin: 10px <%= (600 - @width) / 2 -%>px 20px <%= (600 - @width) / 2 -%>px;
}
#photo_tag_box {
position: relative;
z-index: 2;
width: 100px;
height: 100px;
border: 7px solid #6f9bdc;
left: 0;
top: 0;
display: none;
}
#inner_photo_tag_box {
border: 2px solid black;
width: 96px;
height: 96px;
}
#photo_tag_editor {
margin-bottom: 10px;
}
<% end -%>
<% throw_content :for_javascript do -%>
function show_tag_at(x, y)
{
$('photo_tag_box').style.top = (y - 50) + 'px';
$('photo_tag_box').style.left = (x - 50) + 'px';
$('photo_tag_box').style.display = 'block';
}
function hide_tag_box()
{
$('photo_tag_box').style.display = 'none';
}
function set_coordinates(x, y)
{
$('cartesian_x').innerHTML = x;
$('cartesian_y').innerHTML = y;
$('photo_tag[x]').value = x;
$('photo_tag[y]').value = y;
show_tag_at(x, y);
}
var block_box = true;
function set_coordinates_from_event(event)
{
if(block_box)
return;
var xcoord = (event.offsetX ? event.offsetX : (event.pageX - $('photo_block').offsetLeft));
var ycoord = (event.offsetY ? event.offsetY : (event.pageY - $('photo_block').offsetTop));
if(xcoord < 0)
xcoord = 0;
if(xcoord > <%= @width -%>)
xcoord = <%= @width -%>;
if(ycoord < 0)
ycoord = 0;
if(ycoord > <%= @height -%>)
ycoord = <%= @height -%>;
set_coordinates(xcoord, ycoord);
}
function update_tag_selection(tag_name)
{
var new_tag = tag_name.innerHTML.gsub(/\<[^>]+\>/, '');
var existing_tags = $('tags').value.gsub(/( |^)[^ ]+$/, '');
var plus_space = (existing_tags.length == 0 ? '' : ' ');
$('tags').value = existing_tags + plus_space + new_tag;
$('tags').focus();
}
function photo_tag_effect()
{
new Effect.Highlight('photo_tags', {duration: 2.0});
}
function save_new_tags()
{
$('save').disabled = true;
$('indicator').show();
new Ajax.Updater(
{ success: 'photo_tags', failure: 'photo_tag_errors' },
'<%= url(:photo_tag) -%>',
{
parameters: Form.serialize($('photo_tag_fields')),
asynchronous: false,
onSuccess: function() {
set_coordinates(0, 0);
hide_tag_box();
$('tags').value = '';
photo_tag_effect();
}
}
);
$('indicator').hide();
$('save').disabled = false;
}
function destroy_photo_tag(tag_id)
{
$('indicator').show();
new Ajax.Updater(
{ success: 'photo_tags', failure: 'photo_tag_errors' },
'/photo_tags/' + tag_id,
{
method: 'delete',
onSuccess: function() {
photo_tag_effect();
},
onComplete: function() {
$('indicator').hide();
}
}
);
}
function toggle_photo_tag_editor(direction)
{
if(direction)
{
// swap buttons
$('hide_photo_tag_editor').show();
$('show_photo_tag_editor').hide();
block_box = false;
// update tags to editable mode
new Ajax.Updater(
'photo_tags',
'/photo_tags/<%= @photo.id -%>?editable=true',
{
method: 'get',
onSuccess: function() {
photo_tag_effect();
}
}
);
// transition in editor
new Effect.BlindDown('photo_tag_editor', {duration: 1.5});
}
else
{
// toggle buttons
$('show_photo_tag_editor').show();
$('hide_photo_tag_editor').hide();
block_box = true;
// transition out editable blocks
new Effect.BlindUp('photo_tag_editor', {duration: 1.5});
// update tags to read only
new Ajax.Updater(
'photo_tags',
'/photo_tags/<%= @photo.id -%>',
{
method: 'get',
onSuccess: function() {
photo_tag_effect();
}
}
);
}
}
<% end -%>
<div id="photo_tag_editor" style="display: none;">
<div id="photo_tag_errors" class="errorExplanation"></div>
<form id="photo_tag_fields" onsubmit="save_new_tags(); return false;">
<fieldset>
<legend>Tag a photo...</legend>
<%= hidden_field :name => 'photo_tag[x]', :id => 'photo_tag[x]' %>
<%= hidden_field :name => 'photo_tag[y]', :id => 'photo_tag[y]' %>
<%= hidden_field :name => 'photo_tag[photo_id]', :value => @photo.id %>
<h3 style="margin-top: 5px;">Select Tags (<span id="cartesian_x">0</span>, <span id="cartesian_y">0</span>)</h3>
<p><a href="#" onclick="$('tags').value = ''; return false;"><img src="/images/edit-clear.png" style="vertical-align: top;" /></a> <%= text_field :name => 'tags', :size => 30, :id => 'tags' -%> <input type="submit" value="Save" id="save" /> <img src="/images/ajax-loader.gif" style="display: none; margin-right: 5px;" id="indicator" /></p>
<div id="photo_tag_auto_complete" class="auto_complete"></div>
</fieldset>
</form>
</div>
<div id="photo_block_container">
<div id="photo_block" onclick='set_coordinates_from_event(event);'>
<div id="photo_tag_box" style="display: none;"><div id="inner_photo_tag_box"></div></div>
</div>
</div>
<div id="photo_tags">
<%= partial 'photo_tags/photo_tags' %>
</div>
<script type="text/javascript">
//<![CDATA[
new Ajax.Autocompleter(
'tags',
'photo_tag_auto_complete',
'/tags/auto_complete',
{
paramName: 'id',
updateElement: update_tag_selection
}
);
//]]>
</script>
<% throw_content :for_sidebar do -%>
<a href="<%= url(:album, :id => @photo.album.name.gsub(/ /, '_')) -%>"><img src="/images/camera-photo.png" /> Back to <%= @photo.album.name -%></a><br />
<% if allowed_to?(:edit_photo, @photo) -%><a href="<%= url(:edit_photo, :id => @photo.id) -%>" rel="nofollow"><img src="/images/document-save.png" /> Edit photo</a><br /><% end %>
<% if allowed_to?(:delete_photo, @photo) -%><a href="<%= url(:delete_photo, :id => @photo.id) -%>" onclick="if(!confirm('Are you sure you want to delete this photo?')){return false;}" rel="nofollow"><img src="/images/edit-delete.png" /> Destroy photo</a><br /><% end -%>
<a href="<%= photo_url(@photo) -%>"><img src="/images/image-x-generic.png" /> Download original</a><br />
<% if allowed_to?(:upload_images) -%><a href="<%= url(:new_photo, :photo => { :album_id => @photo.album_id }) -%>"><img src="/images/emblem-photos.png" /> Upload Image</a><br /><% end %>
<% if allowed_to?(:tag_photo) -%><span id="show_photo_tag_editor"><a href="#" onclick="toggle_photo_tag_editor(true)"><img src="/images/face-monkey.png" /> Tag Image</a></span><span id="hide_photo_tag_editor" style="display: none;"><a href="#" onclick="toggle_photo_tag_editor(false); return false;"><img src="/images/face-monkey.png" /> Done Tagging</a></span><br /><% end %>
<% end -%>

View File

@ -0,0 +1,12 @@
<% form_tag :action => url(:sessions) do -%>
<fieldset>
<legend>Login</legend>
<p><%= text_field :name => :username, :label => 'Username: ', :id => 'username' -%></p>
<p><%= password_field :name => :password, :label => 'Password: ' -%></p>
</fieldset>
<p><%= submit_button 'Login' -%></p>
<% end -%>
<script type="text/javascript">
$('username').focus();
</script>

View File

@ -0,0 +1,5 @@
<ul>
<% @tags.each do |tag| -%>
<li><%= highlight(tag.name, @phrase) -%></li>
<% end -%>
</ul>

View File

@ -0,0 +1,11 @@
<% form_for :tag, :action => url(:tag, :id => @tag.name) do -%>
<fieldset>
<legend>Change a tag's name</legend>
<p>
<%= text_control :name, :label => 'Name: ' -%>
</p>
</fieldset>
<p>
<%= submit_button 'Save' %>
</p>
<% end -%>

View File

@ -0,0 +1,8 @@
<% if @tags.empty? -%>
<p><em><strong>No tags were found!</strong></em></p>
<% else -%>
<div id="tag_cloud">
<p>All Tags in TuxBliki</p>
<%= tag_cloud @tags -%>
</div>
<% end -%>

View File

@ -0,0 +1,18 @@
<% throw_content :for_sidebar do -%>
<% if allowed_to?(:edit_tags) -%><a href="<%= url(:edit_tag, :id => @tag.name) -%>"><img src="/images/document-save.png" /> Edit tag</a><br /><% end -%>
<% if allowed_to?(:destroy_tags) -%><a href="<%= url(:delete_tag, :id => @tag.name) -%>" onclick="if(!confirm('Are you sure you want to delete this tag?')){return false;}" rel="nofollow"><img src="/images/edit-delete.png" /> Destroy tag</a><br /><% end -%>
<% end -%>
<h2>Pages</h2>
<% if @pages.empty? -%>
<p><em><strong>None!</strong></em></p>
<% else -%>
<ol><%= @pages.collect { |p| "<li><a href='#{url(:page, :id => p.name.gsub(/ /, '_'))}'>#{p.name}</a></li>" }.join -%></ol>
<% end %>
<h2>Albums</h2>
<% if @albums.empty? -%>
<p><em><strong>None!</strong></em></p>
<% else -%>
<ol><%= @albums.collect { |a| "<li><a href='#{url(:album, :id => a.name.gsub(/ /, '_'))}'>#{a.name}</a></li>" }.join -%></ol>
<% end -%>

13
bin/create_first_user.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/bash
if [[ $# -ne 1 ]] ; then
echo Usage: $0 [username]
exit 1
fi
merb -i << EOF
a = Author.create :name => '$1', :password => 'password', :password_confirmation => 'password'
p = Permission.find_by_name('change_permissions')
p ||= Permission.create :name => 'change_permissions'
a.permissions << p
EOF

76
bin/import_drupal.rb Executable file
View File

@ -0,0 +1,76 @@
#!/bin/bash
# must be run from Merb.root
merb -i << EOF
a = Author.find :first
ActiveRecord::Base.establish_connection({
:adapter => 'mysql',
:username => 'andrew',
:socket => '/var/lib/mysql/mysql.sock',
:database => 'drupal'
})
nodes = ActiveRecord::Base.connection.execute("SELECT * FROM node")
comments = ActiveRecord::Base.connection.execute("SELECT * FROM comments")
#ActiveRecord::Base.connection.execute("DELETE FROM files WHERE filename = 'thumbnail' OR filename = 'preview'")
#files = ActiveRecord::Base.connection.execute("SELECT * FROM files")
ActiveRecord::Base.connection.disconnect!
ActiveRecord::Base.establish_connection(YAML::load_file('config/database.yml')[:development])
pages = []
nodes.each_hash do |node|
next unless node['type'] == 'blog'
c = Time.now
c -= (c.to_i - node['created'].to_i).seconds
[
[ /<\/?em>/, '_' ],
[ /<\/?strong>/, '*' ],
[ /<blockquote>/, 'bq.' ],
[ /<\/blockquote>/, '' ],
[ /<\/?strike>/, '-' ],
[ /<\/?sup>/, '^' ],
[ /<\/?sub>/, '~' ],
[ /<\/?pre>/, '' ],
[ /<\/?code>/, '@' ],
[ /<br ?\/?>/, "\n" ],
[ /<\/?[ou]l>/, '' ],
[ /<li>/, '* ' ],
[ /<\/li>/, '' ],
[ /\&amp\;/, '&' ]
].each do |regexp|
node['body'].gsub!(regexp.first, regexp.last)
end
node['body'].gsub!(/<a.+href=['"]([^"']+)["'].*>(.+)<\/a>/) do |match|
"\"#{\$2}\":#{\$1}"
end
p = Page.new :name => node['title'].gsub(/[^A-Za-z0-9 ]/, ''), :created_at => c, :description => node['body'], :published => true, :nid => node['nid']
p.author_id = a.id
pages << p
end
pages.each do |p|
p.save
if p.new_record?
\$stderr.puts "FAILED TO SAVE PAGE #{p.name} #{p.nid}"
p.errors.each_full { |msg| \$stderr.puts "* #{msg}" }
next
else
puts "Saved page #{p.id} for node #{p.nid}"
end
comments.data_seek(0)
comments.each_hash do |comment|
next unless comment['nid'].to_i == p.nid.to_i
c2 = Time.now
c2 -= (c2.to_i - comment['timestamp'].to_i).seconds
c = Comment.create(:comment => comment['comment'], :user => comment['name'], :url => comment['homepage'], :created_at => c2)
if c.new_record?
\$stderr.puts "FAILED TO SAVE COMMENT ON PAGE #{p.id} NODE #{p.nid}"
c.errors.each_full { |msg| \$stderr.puts "* #{msg}" }
else
puts "Saved comment id #{c.id} for page #{p.id} node #{p.nid}"
end
end
end.size
EOF

42
bin/import_zip.sh Executable file
View File

@ -0,0 +1,42 @@
#!/bin/bash
if [[ $# -ne 3 ]] ; then
echo Usage: $0 [zipfile] [author_name] [album_name]
exit 1
fi
merb -i <<EOF
require 'zip/zipfilesystem'
author = Author.find_by_name '$2'
if author.nil?
\$stderr.puts "Author is missing!"
return false
end
album = Album.find_by_name '$3'
if album.nil?
\$stderr.puts "Album is missing!"
return false
end
Zip::ZipFile.open('$1') do |zipfile|
zipfile.dir.entries('.').each do |ifile_name|
puts ifile_name
ifile = Tempfile.new(ifile_name)
ifile.write zipfile.file.read(ifile_name)
ifile.rewind
photo = Photo.new :album_id => album.id,
:file => {
:content_type => 'image/jpeg',
:size => ifile.size,
:tempfile => ifile,
:filename => ifile_name
}
photo.author_id = author.id
unless photo.save
\$stderr.puts "PHOTO (#{ifile_name}) SAVE FAILED:"
photo.errors.each_full { |msg| \$stderr.puts " * #{msg}" }
end
end
end
EOF

View File

@ -0,0 +1,16 @@
---
# This is a sample database file for the DataMapper ORM
:development: &defaults
:adapter: mysql
:username: andrew
:password:
:socket: /var/lib/mysql/mysql.sock
:database: tuxbliki_development
:test:
<<: *defaults
:database: tuxbliki_test
:production:
<<: *defaults
:database: tuxbliki_production

View File

@ -0,0 +1,6 @@
Merb.logger.info("Loaded DEVELOPMENT Environment...")
Merb::Config.use { |c|
c[:exception_details] = true
c[:reload_classes] = true
c[:reload_time] = 0.5
}

View File

@ -0,0 +1,5 @@
Merb.logger.info("Loaded PRODUCTION Environment...")
Merb::Config.use { |c|
c[:exception_details] = false
c[:reload_classes] = false
}

View File

@ -0,0 +1,6 @@
Merb.logger.info("Loaded TEST Environment...")
Merb::Config.use { |c|
c[:exception_details] = true
c[:reload_classes] = true
c[:reload_time] = 0.5
}

27
config/init.rb Normal file
View File

@ -0,0 +1,27 @@
Gem.clear_paths
Gem.path.unshift(Merb.root / "gems")
$LOAD_PATH.unshift(Merb.root / "lib")
Merb::Config.use do |c|
c[:session_secret_key] = '9e6d92dd24c39be48946fc947255476fa4d7f7e9'
c[:session_store] = :activerecord
end
use_orm :activerecord
use_test :rspec
dependencies 'merb_helpers', 'merb_has_flash', 'merb-mailer'
require 'redcloth'
require 'RMagick'
require 'memcache'
require 'memcache_util'
Merb::BootLoader.after_app_loads do
config_path = File.join(Merb.root, 'config', 'memcache.yml')
if File.file?(config_path) and File.readable?(config_path)
memcache_connection_str = YAML.load(File.read(config_path))
else
memcache_connection_str = 'localhost:11211'
end
CACHE = MemCache.new memcache_connection_str
end

View File

@ -0,0 +1 @@
localhost:11211

1
config/rack.rb Normal file
View File

@ -0,0 +1 @@
run Merb::Rack::Application.new

34
config/router.rb Normal file
View File

@ -0,0 +1,34 @@
Merb.logger.info("Compiling routes...")
Merb::Router.prepare do |r|
r.match('/node/:id').to(
:controller => 'node',
:action => 'show'
)
r.resources :pages
r.resources :comments
r.resources :tags
r.match('/tags/auto_complete').to(
:controller => 'tags',
:action => 'auto_complete'
)
r.resources :authors
r.resources :sessions
r.resources :permissions
r.resources :news
r.resources :invitations
r.resources :albums
r.resources :photos
r.match('/photos/thumbnail/:id').to(
:controller => 'photos',
:action => 'thumbnail'
)
r.match('/photos/screen/:id').to(
:controller => 'photos',
:action => 'screen'
)
r.resources :photo_tags
r.match('/').to(
:controller => 'news',
:action => 'index'
)
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 864 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 873 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 680 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 784 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

BIN
public/images/go-first.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 B

BIN
public/images/go-home.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

Some files were not shown because too many files have changed in this diff Show More