Commit c514316a authored by Jean-Philippe Lang's avatar Jean-Philippe Lang

wiki branch merged into trunk

git-svn-id: http://redmine.rubyforge.org/svn/trunk@323 e93f8b46-1217-0410-a6f0-8f06a7374b81
parent 8b98ceb9
......@@ -32,6 +32,10 @@ class ApplicationController < ActionController::Base
end
end
def logged_in_user_membership
@user_membership ||= Member.find(:first, :conditions => ["user_id=? and project_id=?", self.logged_in_user.id, @project.id])
end
# check if login is globally required to access the application
def check_if_login_required
require_login if Setting.login_required?
......@@ -89,6 +93,16 @@ class ApplicationController < ActionController::Base
render :nothing => true, :status => 403
false
end
# make sure that the user is a member of the project (or admin) if project is private
# used as a before_filter for actions that do not require any particular permission on the project
def check_project_privacy
return true if @project.is_public?
return false unless logged_in_user
return true if logged_in_user.admin? || logged_in_user_membership
render :nothing => true, :status => 403
false
end
# store current uri in session.
# return to this location by calling redirect_back_or_default
......
......@@ -68,6 +68,10 @@ class ProjectsController < ApplicationController
@project.repository = Repository.new
@project.repository.attributes = params[:repository]
end
if "1" == params[:wiki_enabled]
@project.wiki = Wiki.new
@project.wiki.attributes = params[:wiki]
end
if @project.save
flash[:notice] = l(:notice_successful_create)
redirect_to :controller => 'admin', :action => 'projects'
......@@ -113,6 +117,15 @@ class ProjectsController < ApplicationController
@project.repository.update_attributes params[:repository]
end
end
if params[:wiki_enabled]
case params[:wiki_enabled]
when "0"
@project.wiki.destroy
when "1"
@project.wiki ||= Wiki.new
@project.wiki.update_attributes params[:wiki]
end
end
@project.attributes = params[:project]
if @project.save
flash[:notice] = l(:notice_successful_update)
......
# redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class WikiController < ApplicationController
layout 'base'
before_filter :find_wiki, :check_project_privacy, :except => [:preview]
# display a page (in editing mode if it doesn't exist)
def index
page_title = params[:page]
@page = @wiki.find_or_new_page(page_title)
if @page.new_record?
edit
render :action => 'edit' and return
end
@content = (params[:version] ? @page.content.versions.find_by_version(params[:version]) : @page.content)
if params[:export] == 'html'
export = render_to_string :action => 'export', :layout => false
send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
return
elsif params[:export] == 'txt'
send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
return
end
render :action => 'show'
end
# edit an existing page or a new one
def edit
@page = @wiki.find_or_new_page(params[:page])
@page.content = WikiContent.new(:page => @page) if @page.new_record?
@content = @page.content
@content.text = "h1. #{@page.pretty_title}" if @content.text.empty?
# don't keep previous comment
@content.comment = nil
if request.post?
if @content.text == params[:content][:text]
# don't save if text wasn't changed
redirect_to :action => 'index', :id => @project, :page => @page.title
return
end
@content.text = params[:content][:text]
@content.comment = params[:content][:comment]
@content.author = logged_in_user
# if page is new @page.save will also save content, but not if page isn't a new record
if (@page.new_record? ? @page.save : @content.save)
redirect_to :action => 'index', :id => @project, :page => @page.title
end
end
end
# show page history
def history
@page = @wiki.find_page(params[:page])
# don't load text
@versions = @page.content.versions.find :all,
:select => "id, author_id, comment, updated_on, version",
:order => 'version DESC'
end
# display special pages
def special
page_title = params[:page].downcase
case page_title
# show pages index, sorted by title
when 'page_index'
# eager load information about last updates, without loading text
@pages = @wiki.pages.find :all, :select => "wiki_pages.*, wiki_contents.updated_on",
:joins => "LEFT JOIN wiki_contents ON wiki_contents.page_id = wiki_pages.id",
:order => 'title'
# export wiki to a single html file
when 'export'
@pages = @wiki.pages.find :all, :order => 'title'
export = render_to_string :action => 'export_multiple', :layout => false
send_data(export, :type => 'text/html', :filename => "wiki.html")
return
else
# requested special page doesn't exist, redirect to default page
redirect_to :action => 'index', :id => @project, :page => nil and return
end
render :action => "special_#{page_title}"
end
def preview
@text = params[:content][:text]
render :partial => 'preview'
end
private
def find_wiki
@project = Project.find(params[:id])
@wiki = @project.wiki
rescue ActiveRecord::RecordNotFound
render_404
end
end
......@@ -63,7 +63,7 @@ module ApplicationHelper
end
def format_time(time)
l_datetime(time) if time
l_datetime((time.is_a? String) ? time.to_time : time) if time
end
def day_name(day)
......@@ -92,10 +92,42 @@ module ApplicationHelper
html
end
def textilizable(text)
text = (Setting.text_formatting == 'textile') && (ActionView::Helpers::TextHelper.method_defined? "textilize") ? RedCloth.new(h(text)).to_html : simple_format(auto_link(h(text)))
# turn "#id" patterns into links to issues
text = text.gsub(/#(\d+)([^;\d])/, "<a href='/issues/show/\\1'>#\\1</a>\\2")
# textilize text according to system settings and RedCloth availability
def textilizable(text, options = {})
# different methods for formatting wiki links
case options[:wiki_links]
when :local
# used for local links to html files
format_wiki_link = Proc.new {|title| "#{title}.html" }
when :anchor
# used for single-file wiki export
format_wiki_link = Proc.new {|title| "##{title}" }
else
if @project
format_wiki_link = Proc.new {|title| url_for :controller => 'wiki', :action => 'index', :id => @project, :page => title }
else
format_wiki_link = Proc.new {|title| title }
end
end
# turn wiki links into textile links:
# example:
# [[link]] -> "link":link
# [[link|title]] -> "title":link
text = text.gsub(/\[\[([^\]\|]+)(\|([^\]\|]+))?\]\]/) {|m| "\"#{$3 || $1}\":" + format_wiki_link.call(Wiki.titleize($1)) }
# turn issue ids to textile links
# example:
# #52 -> "#52":/issues/show/52
text = text.gsub(/#(\d+)([\s\.\(\)\-,:;])/) {|m| "\"##{$1}\":" + url_for(:controller => 'issues', :action => 'show', :id => $1) + $2 }
# turn revision ids to textile links (@project needed)
# example:
# r52 -> "r52":/repositories/revision/6?rev=52 (@project.id is 6)
text = text.gsub(/r(\d+)([\s\.\(\)\-,:;])/) {|m| "\"r#{$1}\":" + url_for(:controller => 'repositories', :action => 'revision', :id => @project.id, :rev => $1) + $2 } if @project
# finally textilize text
text = (Setting.text_formatting == 'textile') && (ActionView::Helpers::TextHelper.method_defined? "textilize") ? auto_link(RedCloth.new(text, [:filter_html]).to_html) : simple_format(auto_link(h(text)))
end
def error_messages_for(object_name, options = {})
......
# redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module WikiHelper
end
......@@ -26,13 +26,14 @@ class Project < ActiveRecord::Base
has_many :news, :dependent => :delete_all, :include => :author
has_many :issue_categories, :dependent => :delete_all, :order => "issue_categories.name"
has_one :repository, :dependent => :destroy
has_one :wiki, :dependent => :destroy
has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => 'custom_fields_projects', :association_foreign_key => 'custom_field_id'
acts_as_tree :order => "name", :counter_cache => true
validates_presence_of :name, :description
validates_uniqueness_of :name
validates_associated :custom_values, :on => :update
validates_associated :repository
validates_associated :repository, :wiki
validates_format_of :name, :with => /^[\w\s\'\-]*$/i
# returns latest created projects
......
# redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Wiki < ActiveRecord::Base
belongs_to :project
has_many :pages, :class_name => 'WikiPage', :dependent => :destroy
validates_presence_of :project_id, :start_page
# find the page with the given title
# if page doesn't exist, return a new page
def find_or_new_page(title)
title = Wiki.titleize(title || start_page)
find_page(title) || WikiPage.new(:wiki => self, :title => title)
end
# find the page with the given title
def find_page(title)
pages.find_by_title(Wiki.titleize(title || start_page))
end
# turn a string into a valid page title
def self.titleize(title)
# replace spaces with _ and remove unwanted caracters
title = title.gsub(/\s+/, '_').delete(',;|') if title
# upcase the first letter
title = title[0..0].upcase + title[1..-1] if title
title
end
end
# redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'zlib'
class WikiContent < ActiveRecord::Base
belongs_to :page, :class_name => 'WikiPage', :foreign_key => 'page_id'
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
validates_presence_of :text
acts_as_versioned
class Version
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
attr_protected :data
def text=(plain)
case Setting.wiki_compression
when 'gzip'
begin
self.data = Zlib::Deflate.deflate(plain, Zlib::BEST_COMPRESSION)
self.compression = 'gzip'
rescue
self.data = plain
self.compression = ''
end
else
self.data = plain
self.compression = ''
end
plain
end
def text
@text ||= case compression
when 'gzip'
Zlib::Inflate.inflate(data)
else
# uncompressed data
data
end
end
end
end
# redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class WikiPage < ActiveRecord::Base
belongs_to :wiki
has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy
validates_presence_of :title
validates_format_of :title, :with => /^[^,\s]*$/
validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false
validates_associated :content
def before_save
self.title = Wiki.titleize(title)
end
def pretty_title
title.tr '_', ' '
end
end
......@@ -91,6 +91,7 @@
<%= link_to l(:label_change_log), {:controller => 'projects', :action => 'changelog', :id => @project }, :class => "menuItem" %>
<%= link_to l(:label_roadmap), {:controller => 'projects', :action => 'roadmap', :id => @project }, :class => "menuItem" %>
<%= link_to l(:label_document_plural), {:controller => 'projects', :action => 'list_documents', :id => @project }, :class => "menuItem" %>
<%= link_to l(:label_wiki), {:controller => 'wiki', :id => @project, :page => nil }, :class => "menuItem" if @project.wiki and !@project.wiki.new_record? %>
<%= link_to l(:label_member_plural), {:controller => 'projects', :action => 'list_members', :id => @project }, :class => "menuItem" %>
<%= link_to l(:label_attachment_plural), {:controller => 'projects', :action => 'list_files', :id => @project }, :class => "menuItem" %>
<%= link_to l(:label_search), {:controller => 'projects', :action => 'search', :id => @project }, :class => "menuItem" %>
......@@ -115,6 +116,7 @@
<li><%= link_to l(:label_change_log), :controller => 'projects', :action => 'changelog', :id => @project %></li>
<li><%= link_to l(:label_roadmap), :controller => 'projects', :action => 'roadmap', :id => @project %></li>
<li><%= link_to l(:label_document_plural), :controller => 'projects', :action => 'list_documents', :id => @project %></li>
<li><%= link_to l(:label_wiki), :controller => 'wiki', :id => @project, :page => nil if @project.wiki and !@project.wiki.new_record? %></li>
<li><%= link_to l(:label_member_plural), :controller => 'projects', :action => 'list_members', :id => @project %></li>
<li><%= link_to l(:label_attachment_plural), :controller => 'projects', :action => 'list_files', :id => @project %></li>
<li><%= link_to l(:label_search), :controller => 'projects', :action => 'search', :id => @project %></li>
......
......@@ -38,6 +38,20 @@
<%= javascript_tag "Element.hide('repository');" if @project.repository.nil? %>
</div>
<div class="box">
<h3><%= check_box_tag "wiki_enabled", 1, !@project.wiki.nil?, :onclick => "Element.toggle('wiki');" %> <%= l(:label_wiki) %></h3>
<%= hidden_field_tag "wiki_enabled", 0 %>
<div id="wiki">
<% fields_for :wiki, @project.wiki, { :builder => TabularFormBuilder, :lang => current_language} do |wiki| %>
<p><%= wiki.text_field :start_page, :size => 60, :required => true %></p>
<% # content_tag("div", "", :id => "wiki_start_page_auto_complete", :class => "auto_complete") +
# auto_complete_field("wiki_start_page", { :url => { :controller => 'wiki', :action => 'auto_complete_for_wiki_page', :id => @project } })
%>
<% end %>
</div>
<%= javascript_tag "Element.hide('wiki');" if @project.wiki.nil? %>
</div>
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
......
......@@ -38,6 +38,9 @@
<p><label><%= l(:setting_text_formatting) %></label>
<%= select_tag 'settings[text_formatting]', options_for_select( [[l(:label_none), 0], ["textile", "textile"]], Setting.text_formatting) %></p>
<p><label><%= l(:setting_wiki_compression) %></label>
<%= select_tag 'settings[wiki_compression]', options_for_select( [[l(:label_none), 0], ["gzip", "gzip"]], Setting.wiki_compression) %></p>
</div>
<%= submit_tag l(:button_save) %>
<% end %>
\ No newline at end of file
<fieldset class="preview"><legend><%= l(:label_preview) %></legend>
<%= textilizable @text %>
</fieldset>
<div class="contextual">
<%= link_to(l(:label_page_index), {:action => 'special', :page => 'Page_index'}, :class => 'icon icon-index') %>
</div>
<h2><%= @page.pretty_title %></h2>
<% form_for :content, @content, :url => {:action => 'edit', :page => @page.title}, :html => {:id => 'wiki_form'} do |f| %>
<%= error_messages_for 'content' %>
<p><%= f.text_area :text, :cols => 100, :rows => 25, :style => "width:99%;" %></p>
<p><label><%= l(:field_comment) %></label><br /><%= f.text_field :comment, :size => 120 %></p>
<p><%= submit_tag l(:button_save) %>
<%= link_to_remote l(:label_preview),
{ :url => { :controller => 'wiki', :action => 'preview' },
:method => 'get',
:update => 'preview',
:with => "Form.serialize('wiki_form')",
:loading => "Element.show('indicator')",
:loaded => "Element.hide('indicator')"
} %>
<span id="indicator" style="display:none"><%= image_tag "loading.gif", :align => "absmiddle" %></span>
</p>
<% end %>
<% if Setting.text_formatting == 'textile' %>
<%= javascript_include_tag 'jstoolbar' %>
<script type="text/javascript">
//<![CDATA[
if (document.getElementById) {
if (document.getElementById('content_text')) {
var commentTb = new jsToolBar(document.getElementById('content_text'));
commentTb.draw();
}
}
//]]>
</script>
<% end %>
<div id="preview" class="wiki"></div>
\ No newline at end of file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title><%=h @page.pretty_title %></title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<style>
body { font:80% Verdana,Tahoma,Arial,sans-serif; }
h1, h2, h3, h4 { font-family: Trebuchet MS,Georgia,"Times New Roman",serif; }
</style>
</head>
<body>
<%= textilizable @content.text, :wiki_links => :local %>
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title><%=h @wiki.project.name %></title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<style>
body { font:80% Verdana,Tahoma,Arial,sans-serif; }
h1, h2, h3, h4 { font-family: Trebuchet MS,Georgia,"Times New Roman",serif; }
</style>
</head>
<body>
<strong><%= l(:label_page_index) %></strong>
<ul>
<% @pages.each do |page| %>
<li><a href="#<%= page.title %>"><%= page.pretty_title %></a></li>
<% end %>
</ul>
<% @pages.each do |page| %>
<hr />
<%= textilizable page.content.text, :wiki_links => :anchor %>
<% end %>
</body>
</html>
<div class="contextual">
<%= link_to(l(:label_page_index), {:action => 'special', :page => 'Page_index'}, :class => 'icon icon-index') %>
</div>
<h2><%= @page.pretty_title %></h2>
<h3><%= l(:label_history) %></h3>
<table class="list">
<thead><tr>
<th>#</th>
<th><%= l(:field_updated_on) %></th>
<th><%= l(:field_author) %></th>
<th><%= l(:field_comment) %></th>
</tr></thead>
<tbody>
<% @versions.each do |ver| %>
<tr class="<%= cycle("odd", "even") %>">
<th align="center"><%= link_to ver.version, :action => 'index', :page => @page.title, :version => ver.version %></th>
<td align="center"><%= format_time(ver.updated_on) %></td>
<td><em><%= ver.author ? ver.author.name : "anonyme" %></em></td>
<td><%=h ver.comment %></td>
</tr>
<% end %>
</tbody>
</table>
<p><%= link_to l(:button_back), :action => 'index', :page => @page.title %></p>
\ No newline at end of file
<div class="contextual">
<%= link_to(l(:button_edit), {:action => 'edit', :page => @page.title}, :class => 'icon icon-edit') if @content.version == @page.content.version %>
<%= link_to(l(:label_history), {:action => 'history', :page => @page.title}, :class => 'icon icon-history') %>
<%= link_to(l(:label_page_index), {:action => 'special', :page => 'Page_index'}, :class => 'icon icon-index') %>
</div>
<% if @content.version != @page.content.version %>
<p>
<%= link_to(('&#171; ' + l(:label_previous)), :action => 'index', :page => @page.title, :version => (@content.version - 1)) + " - " if @content.version > 1 %>
<%= "#{l(:label_version)} #{@content.version}/#{@page.content.version}" %> -
<%= link_to((l(:label_next) + ' &#187;'), :action => 'index', :page => @page.title, :version => (@content.version + 1)) + " - " if @content.version < @page.content.version %>
<%= link_to(l(:label_current_version), :action => 'index', :page => @page.title) %>
<br />
<em><%= @content.author ? @content.author.name : "anonyme" %>, <%= format_time(@content.updated_on) %> </em><br />
<%=h @content.comment %>
</p>
<hr />
<% end %>
<div class="wiki">
<% cache "wiki/show/#{@page.id}/#{@content.version}" do %>
<%= textilizable @content.text %>
<% end %>
</div>
<div class="contextual">
<%= l(:label_export_to) %>
<%= link_to 'HTML', {:export => 'html', :version => @content.version}, :class => 'icon icon-html' %>,
<%= link_to 'TXT', {:export => 'txt', :version => @content.version}, :class => 'icon icon-txt' %>
</div>
\ No newline at end of file
<div class="contextual">
<% unless @pages.empty? %>
<%= l(:label_export_to) %> <%= link_to 'HTML', {:action => 'special', :page => 'export'}, :class => 'icon icon-html' %>
<% end %>
</div>
<h2><%= l(:label_page_index) %></h2>
<% if @pages.empty? %><p><i><%= l(:label_no_data) %></i></p><% end %>
<ul><% @pages.each do |page| %>
<li><%= link_to page.pretty_title, :action => 'index', :page => page.title %> -
<%= l(:label_last_updates) %>: <%= format_time(page.updated_on) %></li>
<% end %></ul>
\ No newline at end of file
......@@ -9,7 +9,8 @@ ActionController::Routing::Routes.draw do |map|
# You can have the root of your site routed by hooking up ''
# -- just remember to delete public/index.html.
map.connect '', :controller => "welcome"
map.connect 'wiki/:id/:page/:action', :controller => 'wiki', :page => nil
map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow'
map.connect 'help/:ctrl/:page', :controller => 'help'
#map.connect ':controller/:action/:id/:sort_key/:sort_order'
......
......@@ -41,6 +41,8 @@ mail_from:
default: redmine@somenet.foo
text_formatting:
default: textile
wiki_compression:
default: ""
default_language:
default: en
host_name:
......
class CreateWikis < ActiveRecord::Migration
def self.up
create_table :wikis do |t|
t.column :project_id, :integer, :null => false
t.column :start_page, :string, :limit => 255, :null => false
t.column :status, :integer, :default => 1, :null => false
end
add_index :wikis, :project_id, :name => :wikis_project_id
end
def self.down
drop_table :wikis
end
end
class CreateWikiPages < ActiveRecord::Migration
def self.up
create_table :wiki_pages do |t|
t.column :wiki_id, :integer, :null => false
t.column :title, :string, :limit => 255, :null => false
t.column :created_on, :datetime, :null => false
end
add_index :wiki_pages, [:wiki_id, :title], :name => :wiki_pages_wiki_id_title
end
def self.down
drop_table :wiki_pages
end
end
class CreateWikiContents < ActiveRecord::Migration
def self.up
create_table :wiki_contents do |t|
t.column :page_id, :integer, :null => false
t.column :author_id, :integer
t.column :text, :text, :default => "", :null => false
t.column :comment, :string, :limit => 255, :default => ""
t.column :updated_on, :datetime, :null => false
t.column :version, :integer, :null => false
end
add_index :wiki_contents, :page_id, :name => :wiki_contents_page_id
create_table :wiki_content_versions do |t|
t.column :wiki_content_id, :integer, :null => false
t.column :page_id, :integer, :null => false
t.column :author_id, :integer
t.column :data, :binary
t.column :compression, :string, :limit => 6, :default => ""
t.column :comment, :string, :limit => 255, :default => ""
t.column :updated_on, :datetime, :null => false
t.column :version, :integer, :null => false
end
add_index :wiki_content_versions, :wiki_content_id, :name => :wiki_content_versions_wcid
end
def self.down
drop_table :wiki_contents
drop_table :wiki_content_versions
end
end
......@@ -142,6 +142,7 @@ field_auth_source: Authentisierung Modus
field_hide_mail: Mein email address verstecken
field_comment: Anmerkung
field_url: URL
field_start_page: Hauptseite
setting_app_title: Applikation Titel
setting_app_subtitle: Applikation Untertitel
......@@ -154,6 +155,7 @@ setting_issues_export_limit: Issues export limit
setting_mail_from: Emission address
setting_host_name: Host Name
setting_text_formatting: Textformatierung
setting_wiki_compression: Wiki Geschichte Kompression
label_user: Benutzer
label_user_plural: Benutzer
......@@ -322,6 +324,10 @@ label_search: Suche
label_result: %d Resultat
label_result_plural: %d Resultate
label_all_words: Alle Wörter
label_wiki: Wiki
label_page_index: Index
label_current_version: Gegenwärtige Version
label_preview: Vorbetrachtung
button_login: Einloggen
button_submit: Einreichen
......
......@@ -142,6 +142,7 @@ field_auth_source: Authentication mode
field_hide_mail: Hide my email address
field_comment: Comment
field_url: URL
field_start_page: Start page
setting_app_title: Application title
setting_app_subtitle: Application subtitle
......@@ -154,6 +155,7 @@ setting_issues_export_limit: Issues export limit
setting_mail_from: Emission mail address
setting_host_name: Host name
setting_text_formatting: Text formatting
setting_wiki_compression: Wiki history compression
label_user: User
label_user_plural: Users
......@@ -322,6 +324,10 @@ label_search: Search
label_result: %d result
label_result_plural: %d results
label_all_words: All words
label_wiki: Wiki
label_page_index: Index
label_current_version: Current version
label_preview: Preview
button_login: Login
button_submit: Submit
......
......@@ -142,6 +142,7 @@ field_auth_source: Modo de la autentificación
field_hide_mail: Ocultar mi email address
field_comment: Comentario
field_url: URL
field_start_page: Página principal
setting_app_title: Título del aplicación
setting_app_subtitle: Subtítulo del aplicación
......@@ -154,6 +155,7 @@ setting_issues_export_limit: Issues export limit
setting_mail_from: Email de la emisión
setting_host_name: Nombre de anfitrión
setting_text_formatting: Formato de texto
setting_wiki_compression: Compresión de la historia de Wiki
label_user: Usuario
label_user_plural: Usuarios
......@@ -322,6 +324,10 @@ label_search: Búsqueda
label_result: %d resultado
label_result_plural: %d resultados
label_all_words: Todas las palabras
label_wiki: Wiki
label_page_index: Índice
label_current_version: Versión actual
label_preview: Previo
button_login: Conexión
button_submit: Someter
......
......@@ -142,6 +142,7 @@ field_auth_source: Mode d'authentification
field_hide_mail: Cacher mon adresse mail
field_comment: Commentaire
field_url: URL
field_start_page: Page de démarrage
setting_app_title: Titre de l'application
setting_app_subtitle: Sous-titre de l'application
......@@ -154,6 +155,7 @@ setting_issues_export_limit: Limite export demandes
setting_mail_from: Adresse d'émission
setting_host_name: Nom d'hôte
setting_text_formatting: Formatage du texte
setting_wiki_compression: Compression historique wiki
label_user: Utilisateur
label_user_plural: Utilisateurs
......@@ -322,6 +324,10 @@ label_search: Recherche
label_result: %d résultat
label_result_plural: %d résultats
label_all_words: Tous les mots
label_wiki: Wiki
label_page_index: Index
label_current_version: Version actuelle
label_preview: Prévisualisation
button_login: Connexion
button_submit: Soumettre
......
......@@ -143,6 +143,7 @@ field_auth_source: 認証モード
field_hide_mail: Emailアドレスを隠す
field_comment: コメント
field_url: URL
field_start_page: メインページ
setting_app_title: アプリケーションのタイトル
setting_app_subtitle: アプリケーションのサブタイトル
......@@ -155,6 +156,7 @@ setting_issues_export_limit: 出力する問題数の上限
setting_mail_from: Emission メールアドレス
setting_host_name: ホスト名
setting_text_formatting: テキストの書式
setting_wiki_compression: Wiki history compression
label_user: ユーザ
label_user_plural: ユーザ
......@@ -323,6 +325,10 @@ label_search: 検索
label_result: %d 件の結果
label_result_plural: %d 件の結果
label_all_words: すべての単語
label_wiki: Wiki
label_page_index: 索引
label_current_version: 最近版
label_preview: 下検分
button_login: ログイン
button_submit: 変更
......
......@@ -139,6 +139,8 @@ vertical-align: middle;
.icon-cancel { background-image: url(../images/cancel.png); }
.icon-pdf { background-image: url(../images/pdf.png); }
.icon-csv { background-image: url(../images/csv.png); }
.icon-html { background-image: url(../images/html.png); }
.icon-txt { background-image: url(../images/txt.png); }
.icon-file { background-image: url(../images/file.png); }
.icon-folder { background-image: url(../images/folder.png); }
.icon-package { background-image: url(../images/package.png); }
......@@ -150,6 +152,8 @@ vertical-align: middle;
.icon-logout { background-image: url(../images/logout.png); }
.icon-help { background-image: url(../images/help.png); }
.icon-attachment { background-image: url(../images/attachment.png); }
.icon-index { background-image: url(../images/index.png); }
.icon-history { background-image: url(../images/history.png); }
.icon22-projects { background-image: url(../images/22x22/projects.png); }
.icon22-users { background-image: url(../images/22x22/users.png); }
......@@ -181,7 +185,7 @@ border-left: 1px dashed #c0c0c0;
}
#content h2{
#content h2, #content div.wiki h1 {
display:block;
margin:0 0 16px 0;
font-size:1.7em;
......@@ -576,4 +580,23 @@ to account for 3 pixel bug: http://www.positioniseverything.net/explorer/threepx
* html .threepxfix{
margin-left: 3px;
}
\ No newline at end of file
}
/***** Wiki sections ****/
#content div.wiki { font-size: 110%}
#content div.wiki h2, div.wiki h3 { font-family: Trebuchet MS,Georgia,"Times New Roman",serif; color:#606060; }
#content div.wiki h2 { font-size: 1.4em;}
#content div.wiki h3 { font-size: 1.2em;}
div.wiki table {
border: 1px solid #505050;
border-collapse: collapse;
}
div.wiki table, div.wiki td {
border: 1px solid #bbb;
padding: 4px;
}
#preview .preview { background: #fafbfc url(../images/draft.png); }
......@@ -449,6 +449,15 @@ permissions_005:
mail_option: false
sort: 151
is_public: false
permissions_061:
action: search
id: 62
description: label_search
controller: projects
mail_enabled: false
mail_option: false
sort: 130
is_public: true
permissions_050:
action: history
id: 50
......
This diff is collapsed.
---
wiki_content_versions_001:
updated_on: 2007-03-07 00:08:07 +01:00
page_id: 1
id: 1
version: 1
author_id: 1
comment: Page creation
wiki_content_id: 1
compression: ""
data: |-
h1. CookBook documentation
Some [[documentation]] here...
wiki_content_versions_002:
updated_on: 2007-03-07 00:08:34 +01:00
page_id: 1
id: 2
version: 2
author_id: 1
comment: Small update
wiki_content_id: 1
compression: ""
data: |-
h1. CookBook documentation
Some updated [[documentation]] here...
wiki_content_versions_003:
updated_on: 2007-03-07 00:10:51 +01:00
page_id: 1
id: 3
version: 3
author_id: 1
comment: ""
wiki_content_id: 1
compression: ""
data: |-
h1. CookBook documentation
Some updated [[documentation]] here...
---
wiki_contents_001:
text: |-
h1. CookBook documentation
Some updated [[documentation]] here with gzipped history
updated_on: 2007-03-07 00:10:51 +01:00
page_id: 1
id: 1
version: 3
author_id: 1
comment: Gzip compression activated
---
wiki_pages_001:
created_on: 2007-03-07 00:08:07 +01:00
title: CookBook_documentation
id: 1
wiki_id: 1
---
wikis_001:
status: 1
start_page: CookBook documentation
project_id: 1
id: 1
......@@ -24,7 +24,7 @@ class MailerTest < Test::Unit::TestCase
def test_issue_add
issue = Issue.find(1)
GLoc.valid_languages.each do |lang|
Setting.default_language = lang
Setting.default_language = lang.to_s
assert Mailer.deliver_issue_add(issue)
end
end
......@@ -32,7 +32,7 @@ class MailerTest < Test::Unit::TestCase
def test_issue_edit
journal = Journal.find(1)
GLoc.valid_languages.each do |lang|
Setting.default_language = lang
Setting.default_language = lang.to_s
assert Mailer.deliver_issue_edit(journal)
end
end
......@@ -40,7 +40,7 @@ class MailerTest < Test::Unit::TestCase
def test_document_add
document = Document.find(1)
GLoc.valid_languages.each do |lang|
Setting.default_language = lang
Setting.default_language = lang.to_s
assert Mailer.deliver_document_add(document)
end
end
......@@ -48,7 +48,7 @@ class MailerTest < Test::Unit::TestCase
def test_lost_password
token = Token.find(2)
GLoc.valid_languages.each do |lang|
token.user.update_attribute :language, lang
token.user.update_attribute :language, lang.to_s
assert Mailer.deliver_lost_password(token)
end
end
......@@ -56,7 +56,7 @@ class MailerTest < Test::Unit::TestCase
def test_register
token = Token.find(1)
GLoc.valid_languages.each do |lang|
token.user.update_attribute :language, lang
token.user.update_attribute :language, lang.to_s
assert Mailer.deliver_register(token)
end
end
......
# redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.dirname(__FILE__) + '/../test_helper'
class WikiContentTest < Test::Unit::TestCase
fixtures :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, :users
def setup
@wiki = Wiki.find(1)
@page = @wiki.pages.first
end
def test_create
page = WikiPage.new(:wiki => @wiki, :title => "Page")
page.content = WikiContent.new(:text => "Content text", :author => User.find(1), :comment => "My comment")
assert page.save
page.reload
content = page.content
assert_kind_of WikiContent, content
assert_equal 1, content.version
assert_equal 1, content.versions.length
assert_equal "Content text", content.text
assert_equal "My comment", content.comment
assert_equal User.find(1), content.author
assert_equal content.text, content.versions.last.text
end
def test_update
content = @page.content
version_count = content.version
content.text = "My new content"
assert content.save
content.reload
assert_equal version_count+1, content.version
assert_equal version_count+1, content.versions.length
end
def test_fetch_history
assert !@page.content.versions.empty?
@page.content.versions.each do |version|
assert_kind_of String, version.text
end
end
end
# redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.dirname(__FILE__) + '/../test_helper'
class WikiPageTest < Test::Unit::TestCase
fixtures :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions
def setup
@wiki = Wiki.find(1)
@page = @wiki.pages.first
end
def test_create
page = WikiPage.new(:wiki => @wiki)
assert !page.save
assert_equal 1, page.errors.count
page.title = "Page"
assert page.save
page.reload
@wiki.reload
assert @wiki.pages.include?(page)
end
def test_find_or_new_page
page = @wiki.find_or_new_page("CookBook documentation")
assert_kind_of WikiPage, page
assert !page.new_record?
page = @wiki.find_or_new_page("Non existing page")
assert_kind_of WikiPage, page
assert page.new_record?
end
end
# redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.dirname(__FILE__) + '/../test_helper'
class WikiTest < Test::Unit::TestCase
fixtures :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions
def test_create
wiki = Wiki.new(:project => Project.find(2))
assert !wiki.save
assert_equal 1, wiki.errors.count
wiki.start_page = "Start page"
assert wiki.save
end
def test_update
@wiki = Wiki.find(1)
@wiki.start_page = "Another start page"
assert @wiki.save
@wiki.reload
assert_equal "Another start page", @wiki.start_page
end
end
*SVN* (version numbers are overrated)
* (5 Oct 2006) Allow customization of #versions association options [Dan Peterson]
*0.5.1*
* (8 Aug 2006) Versioned models now belong to the unversioned model. @article_version.article.class => Article [Aslak Hellesoy]
*0.5* # do versions even matter for plugins?
* (21 Apr 2006) Added without_locking and without_revision methods.
Foo.without_revision do
@foo.update_attributes ...
end
*0.4*
* (28 March 2006) Rename non_versioned_fields to non_versioned_columns (old one is kept for compatibility).
* (28 March 2006) Made explicit documentation note that string column names are required for non_versioned_columns.
*0.3.1*
* (7 Jan 2006) explicitly set :foreign_key option for the versioned model's belongs_to assocation for STI [Caged]
* (7 Jan 2006) added tests to prove has_many :through joins work
*0.3*
* (2 Jan 2006) added ability to share a mixin with versioned class
* (2 Jan 2006) changed the dynamic version model to MyModel::Version
*0.2.4*
* (27 Nov 2005) added note about possible destructive behavior of if_changed? [Michael Schuerig]
*0.2.3*
* (12 Nov 2005) fixed bug with old behavior of #blank? [Michael Schuerig]
* (12 Nov 2005) updated tests to use ActiveRecord Schema
*0.2.2*
* (3 Nov 2005) added documentation note to #acts_as_versioned [Martin Jul]
*0.2.1*
* (6 Oct 2005) renamed dirty? to changed? to keep it uniform. it was aliased to keep it backwards compatible.
*0.2*
* (6 Oct 2005) added find_versions and find_version class methods.
* (6 Oct 2005) removed transaction from create_versioned_table().
this way you can specify your own transaction around a group of operations.
* (30 Sep 2005) fixed bug where find_versions() would order by 'version' twice. (found by Joe Clark)
* (26 Sep 2005) added :sequence_name option to acts_as_versioned to set the sequence name on the versioned model
*0.1.3* (18 Sep 2005)
* First RubyForge release
*0.1.2*
* check if module is already included when acts_as_versioned is called
*0.1.1*
* Adding tests and rdocs
*0.1*
* Initial transfer from Rails ticket: http://dev.rubyonrails.com/ticket/1974
\ No newline at end of file
Copyright (c) 2005 Rick Olson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
= acts_as_versioned
This library adds simple versioning to an ActiveRecord module. ActiveRecord is required.
== Resources
Install
* gem install acts_as_versioned
Rubyforge project
* http://rubyforge.org/projects/ar-versioned
RDocs
* http://ar-versioned.rubyforge.org
Subversion
* http://techno-weenie.net/svn/projects/acts_as_versioned
Collaboa
* http://collaboa.techno-weenie.net/repository/browse/acts_as_versioned
Special thanks to Dreamer on ##rubyonrails for help in early testing. His ServerSideWiki (http://serversidewiki.com)
was the first project to use acts_as_versioned <em>in the wild</em>.
\ No newline at end of file
== Creating the test database
The default name for the test databases is "activerecord_versioned". If you
want to use another database name then be sure to update the connection
adapter setups you want to test with in test/connections/<your database>/connection.rb.
When you have the database online, you can import the fixture tables with
the test/fixtures/db_definitions/*.sql files.
Make sure that you create database objects with the same user that you specified in i
connection.rb otherwise (on Postgres, at least) tests for default values will fail.
== Running with Rake
The easiest way to run the unit tests is through Rake. The default task runs
the entire test suite for all the adapters. You can also run the suite on just
one adapter by using the tasks test_mysql_ruby, test_ruby_mysql, test_sqlite,
or test_postresql. For more information, checkout the full array of rake tasks with "rake -T"
Rake can be found at http://rake.rubyforge.org
== Running by hand
Unit tests are located in test directory. If you only want to run a single test suite,
or don't want to bother with Rake, you can do so with something like:
cd test; ruby -I "connections/native_mysql" base_test.rb
That'll run the base suite using the MySQL-Ruby adapter. Change the adapter
and test suite name as needed.
== Faster tests
If you are using a database that supports transactions, you can set the
"AR_TX_FIXTURES" environment variable to "yes" to use transactional fixtures.
This gives a very large speed boost. With rake:
rake AR_TX_FIXTURES=yes
Or, by hand:
AR_TX_FIXTURES=yes ruby -I connections/native_sqlite3 base_test.rb
require 'rubygems'
Gem::manage_gems
require 'rake/rdoctask'
require 'rake/packagetask'
require 'rake/gempackagetask'
require 'rake/testtask'
require 'rake/contrib/rubyforgepublisher'
PKG_NAME = 'acts_as_versioned'
PKG_VERSION = '0.3.1'
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
PROD_HOST = "technoweenie@bidwell.textdrive.com"
RUBY_FORGE_PROJECT = 'ar-versioned'
RUBY_FORGE_USER = 'technoweenie'
desc 'Default: run unit tests.'
task :default => :test
desc 'Test the calculations plugin.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end
desc 'Generate documentation for the calculations plugin.'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = "#{PKG_NAME} -- Simple versioning with active record models"
rdoc.options << '--line-numbers --inline-source'
rdoc.rdoc_files.include('README', 'CHANGELOG', 'RUNNING_UNIT_TESTS')
rdoc.rdoc_files.include('lib/**/*.rb')
end
spec = Gem::Specification.new do |s|
s.name = PKG_NAME
s.version = PKG_VERSION
s.platform = Gem::Platform::RUBY
s.summary = "Simple versioning with active record models"
s.files = FileList["{lib,test}/**/*"].to_a + %w(README MIT-LICENSE CHANGELOG RUNNING_UNIT_TESTS)
s.files.delete "acts_as_versioned_plugin.sqlite.db"
s.files.delete "acts_as_versioned_plugin.sqlite3.db"
s.files.delete "test/debug.log"
s.require_path = 'lib'
s.autorequire = 'acts_as_versioned'
s.has_rdoc = true
s.test_files = Dir['test/**/*_test.rb']
s.add_dependency 'activerecord', '>= 1.10.1'
s.add_dependency 'activesupport', '>= 1.1.1'
s.author = "Rick Olson"
s.email = "technoweenie@gmail.com"
s.homepage = "http://techno-weenie.net"
end
Rake::GemPackageTask.new(spec) do |pkg|
pkg.need_tar = true
end
desc "Publish the API documentation"
task :pdoc => [:rdoc] do
Rake::RubyForgePublisher.new(RUBY_FORGE_PROJECT, RUBY_FORGE_USER).upload
end
desc 'Publish the gem and API docs'
task :publish => [:pdoc, :rubyforge_upload]
desc "Publish the release files to RubyForge."
task :rubyforge_upload => :package do
files = %w(gem tgz).map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" }
if RUBY_FORGE_PROJECT then
require 'net/http'
require 'open-uri'
project_uri = "http://rubyforge.org/projects/#{RUBY_FORGE_PROJECT}/"
project_data = open(project_uri) { |data| data.read }
group_id = project_data[/[?&]group_id=(\d+)/, 1]
raise "Couldn't get group id" unless group_id
# This echos password to shell which is a bit sucky
if ENV["RUBY_FORGE_PASSWORD"]
password = ENV["RUBY_FORGE_PASSWORD"]
else
print "#{RUBY_FORGE_USER}@rubyforge.org's password: "
password = STDIN.gets.chomp
end
login_response = Net::HTTP.start("rubyforge.org", 80) do |http|
data = [
"login=1",
"form_loginname=#{RUBY_FORGE_USER}",
"form_pw=#{password}"
].join("&")
http.post("/account/login.php", data)
end
cookie = login_response["set-cookie"]
raise "Login failed" unless cookie
headers = { "Cookie" => cookie }
release_uri = "http://rubyforge.org/frs/admin/?group_id=#{group_id}"
release_data = open(release_uri, headers) { |data| data.read }
package_id = release_data[/[?&]package_id=(\d+)/, 1]
raise "Couldn't get package id" unless package_id
first_file = true
release_id = ""
files.each do |filename|
basename = File.basename(filename)
file_ext = File.extname(filename)
file_data = File.open(filename, "rb") { |file| file.read }
puts "Releasing #{basename}..."
release_response = Net::HTTP.start("rubyforge.org", 80) do |http|
release_date = Time.now.strftime("%Y-%m-%d %H:%M")
type_map = {
".zip" => "3000",
".tgz" => "3110",
".gz" => "3110",
".gem" => "1400"
}; type_map.default = "9999"
type = type_map[file_ext]
boundary = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor"
query_hash = if first_file then
{
"group_id" => group_id,
"package_id" => package_id,
"release_name" => PKG_FILE_NAME,
"release_date" => release_date,
"type_id" => type,
"processor_id" => "8000", # Any
"release_notes" => "",
"release_changes" => "",
"preformatted" => "1",
"submit" => "1"
}
else
{
"group_id" => group_id,
"release_id" => release_id,
"package_id" => package_id,
"step2" => "1",
"type_id" => type,
"processor_id" => "8000", # Any
"submit" => "Add This File"
}
end
query = "?" + query_hash.map do |(name, value)|
[name, URI.encode(value)].join("=")
end.join("&")
data = [
"--" + boundary,
"Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"",
"Content-Type: application/octet-stream",
"Content-Transfer-Encoding: binary",
"", file_data, ""
].join("\x0D\x0A")
release_headers = headers.merge(
"Content-Type" => "multipart/form-data; boundary=#{boundary}"
)
target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php"
http.post(target + query, data, release_headers)
end
if first_file then
release_id = release_response.body[/release_id=(\d+)/, 1]
raise("Couldn't get release id") unless release_id
end
first_file = false
end
end
end
\ No newline at end of file
require 'acts_as_versioned'
\ No newline at end of file
This diff is collapsed.
$:.unshift(File.dirname(__FILE__) + '/../lib')
require 'test/unit'
require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb'))
require 'active_record/fixtures'
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'sqlite'])
load(File.dirname(__FILE__) + "/schema.rb")
# set up custom sequence on widget_versions for DBs that support sequences
if ENV['DB'] == 'postgresql'
ActiveRecord::Base.connection.execute "DROP SEQUENCE widgets_seq;" rescue nil
ActiveRecord::Base.connection.remove_column :widget_versions, :id
ActiveRecord::Base.connection.execute "CREATE SEQUENCE widgets_seq START 101;"
ActiveRecord::Base.connection.execute "ALTER TABLE widget_versions ADD COLUMN id INTEGER PRIMARY KEY DEFAULT nextval('widgets_seq');"
end
Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
$LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path)
class Test::Unit::TestCase #:nodoc:
def create_fixtures(*table_names)
if block_given?
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
else
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
end
end
# Turn off transactional fixtures if you're working with MyISAM tables in MySQL
self.use_transactional_fixtures = true
# Instantiated fixtures are slow, but give you @david where you otherwise would need people(:david)
self.use_instantiated_fixtures = false
# Add more helper methods to be used by all tests here...
end
\ No newline at end of file
sqlite:
:adapter: sqlite
:dbfile: acts_as_versioned_plugin.sqlite.db
sqlite3:
:adapter: sqlite3
:dbfile: acts_as_versioned_plugin.sqlite3.db
postgresql:
:adapter: postgresql
:username: postgres
:password: postgres
:database: acts_as_versioned_plugin_test
:min_messages: ERROR
mysql:
:adapter: mysql
:host: localhost
:username: rails
:password:
:database: acts_as_versioned_plugin_test
\ No newline at end of file
caged:
id: 1
name: caged
mly:
id: 2
name: mly
\ No newline at end of file
class Landmark < ActiveRecord::Base
acts_as_versioned :if_changed => [ :name, :longitude, :latitude ]
end
washington:
id: 1
landmark_id: 1
version: 1
name: Washington, D.C.
latitude: 38.895
longitude: -77.036667
washington:
id: 1
name: Washington, D.C.
latitude: 38.895
longitude: -77.036667
version: 1
welcome:
id: 1
title: Welcome to the weblog
lock_version: 24
type: LockedPage
thinking:
id: 2
title: So I was thinking
lock_version: 24
type: SpecialLockedPage
welcome_1:
id: 1
page_id: 1
title: Welcome to the weblg
version: 23
version_type: LockedPage
welcome_2:
id: 2
page_id: 1
title: Welcome to the weblog
version: 24
version_type: LockedPage
thinking_1:
id: 3
page_id: 2
title: So I was thinking!!!
version: 23
version_type: SpecialLockedPage
thinking_2:
id: 4
page_id: 2
title: So I was thinking
version: 24
version_type: SpecialLockedPage
class AddVersionedTables < ActiveRecord::Migration
def self.up
create_table("things") do |t|
t.column :title, :text
end
Thing.create_versioned_table
end
def self.down
Thing.drop_versioned_table
drop_table "things" rescue nil
end
end
\ No newline at end of file
class Page < ActiveRecord::Base
belongs_to :author
has_many :authors, :through => :versions, :order => 'name'
belongs_to :revisor, :class_name => 'Author'
has_many :revisors, :class_name => 'Author', :through => :versions, :order => 'name'
acts_as_versioned :if => :feeling_good? do
def self.included(base)
base.cattr_accessor :feeling_good
base.feeling_good = true
base.belongs_to :author
base.belongs_to :revisor, :class_name => 'Author'
end
def feeling_good?
@@feeling_good == true
end
end
end
module LockedPageExtension
def hello_world
'hello_world'
end
end
class LockedPage < ActiveRecord::Base
acts_as_versioned \
:inheritance_column => :version_type,
:foreign_key => :page_id,
:table_name => :locked_pages_revisions,
:class_name => 'LockedPageRevision',
:version_column => :lock_version,
:limit => 2,
:if_changed => :title,
:extend => LockedPageExtension
end
class SpecialLockedPage < LockedPage
end
class Author < ActiveRecord::Base
has_many :pages
end
\ No newline at end of file
welcome_2:
id: 1
page_id: 1
title: Welcome to the weblog
body: Such a lovely day
version: 24
author_id: 1
revisor_id: 1
welcome_1:
id: 2
page_id: 1
title: Welcome to the weblg
body: Such a lovely day
version: 23
author_id: 2
revisor_id: 2
welcome:
id: 1
title: Welcome to the weblog
body: Such a lovely day
version: 24
author_id: 1
revisor_id: 1
\ No newline at end of file
class Widget < ActiveRecord::Base
acts_as_versioned :sequence_name => 'widgets_seq', :association_options => {
:dependent => nil, :order => 'version desc'
}
non_versioned_columns << 'foo'
end
\ No newline at end of file
require File.join(File.dirname(__FILE__), 'abstract_unit')
if ActiveRecord::Base.connection.supports_migrations?
class Thing < ActiveRecord::Base
attr_accessor :version
acts_as_versioned
end
class MigrationTest < Test::Unit::TestCase
self.use_transactional_fixtures = false
def teardown
ActiveRecord::Base.connection.initialize_schema_information
ActiveRecord::Base.connection.update "UPDATE schema_info SET version = 0"
Thing.connection.drop_table "things" rescue nil
Thing.connection.drop_table "thing_versions" rescue nil
Thing.reset_column_information
end
def test_versioned_migration
assert_raises(ActiveRecord::StatementInvalid) { Thing.create :title => 'blah blah' }
# take 'er up
ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/')
t = Thing.create :title => 'blah blah'
assert_equal 1, t.versions.size
# now lets take 'er back down
ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/')
assert_raises(ActiveRecord::StatementInvalid) { Thing.create :title => 'blah blah' }
end
end
end
ActiveRecord::Schema.define(:version => 0) do
create_table :pages, :force => true do |t|
t.column :version, :integer
t.column :title, :string, :limit => 255
t.column :body, :text
t.column :updated_on, :datetime
t.column :author_id, :integer
t.column :revisor_id, :integer
end
create_table :page_versions, :force => true do |t|
t.column :page_id, :integer
t.column :version, :integer
t.column :title, :string, :limit => 255
t.column :body, :text
t.column :updated_on, :datetime
t.column :author_id, :integer
t.column :revisor_id, :integer
end
create_table :authors, :force => true do |t|
t.column :page_id, :integer
t.column :name, :string
end
create_table :locked_pages, :force => true do |t|
t.column :lock_version, :integer
t.column :title, :string, :limit => 255
t.column :type, :string, :limit => 255
end
create_table :locked_pages_revisions, :force => true do |t|
t.column :page_id, :integer
t.column :version, :integer
t.column :title, :string, :limit => 255
t.column :version_type, :string, :limit => 255
t.column :updated_at, :datetime
end
create_table :widgets, :force => true do |t|
t.column :name, :string, :limit => 50
t.column :foo, :string
t.column :version, :integer
t.column :updated_at, :datetime
end
create_table :widget_versions, :force => true do |t|
t.column :widget_id, :integer
t.column :name, :string, :limit => 50
t.column :version, :integer
t.column :updated_at, :datetime
end
create_table :landmarks, :force => true do |t|
t.column :name, :string
t.column :latitude, :float
t.column :longitude, :float
t.column :version, :integer
end
create_table :landmark_versions, :force => true do |t|
t.column :landmark_id, :integer
t.column :name, :string
t.column :latitude, :float
t.column :longitude, :float
t.column :version, :integer
end
end
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment