Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
O
OHR Support
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
97
Issues
97
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
OHR Support
Commits
b1845fcf
Commit
b1845fcf
authored
May 13, 2011
by
Eric Davis
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[
#123
] Added latest edavis10:acts_as_journalized
parent
62c9fd21
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
48 changed files
with
3812 additions
and
0 deletions
+3812
-0
.gitignore
vendor/plugins/acts_as_journalized/.gitignore
+22
-0
GPL.txt
vendor/plugins/acts_as_journalized/GPL.txt
+339
-0
LICENSE
vendor/plugins/acts_as_journalized/LICENSE
+87
-0
README.rdoc
vendor/plugins/acts_as_journalized/README.rdoc
+3
-0
REVISION
vendor/plugins/acts_as_journalized/REVISION
+1
-0
journals_controller.rb
...cts_as_journalized/app/controllers/journals_controller.rb
+45
-0
journals_helper.rb
...lugins/acts_as_journalized/app/helpers/journals_helper.rb
+128
-0
journal.rb
vendor/plugins/acts_as_journalized/app/models/journal.rb
+111
-0
journal_observer.rb
...lugins/acts_as_journalized/app/models/journal_observer.rb
+33
-0
_notes_form.rhtml
.../acts_as_journalized/app/views/journals/_notes_form.rhtml
+8
-0
edit.rjs
...r/plugins/acts_as_journalized/app/views/journals/edit.rjs
+3
-0
update.rjs
...plugins/acts_as_journalized/app/views/journals/update.rjs
+11
-0
20100714111651_generalize_journals.rb
...rnalized/db/migrate/20100714111651_generalize_journals.rb
+119
-0
20100804112053_merge_wiki_versions_with_journals.rb
...grate/20100804112053_merge_wiki_versions_with_journals.rb
+49
-0
init.rb
vendor/plugins/acts_as_journalized/init.rb
+17
-0
acts_as_journalized.rb
...or/plugins/acts_as_journalized/lib/acts_as_journalized.rb
+181
-0
journal_deprecated.rb
vendor/plugins/acts_as_journalized/lib/journal_deprecated.rb
+49
-0
journal_formatter.rb
vendor/plugins/acts_as_journalized/lib/journal_formatter.rb
+190
-0
changes.rb
...ts_as_journalized/lib/redmine/acts/journalized/changes.rb
+162
-0
configuration.rb
...journalized/lib/redmine/acts/journalized/configuration.rb
+77
-0
creation.rb
...s_as_journalized/lib/redmine/acts/journalized/creation.rb
+127
-0
deprecated.rb
...as_journalized/lib/redmine/acts/journalized/deprecated.rb
+68
-0
format_hooks.rb
..._journalized/lib/redmine/acts/journalized/format_hooks.rb
+42
-0
options.rb
...ts_as_journalized/lib/redmine/acts/journalized/options.rb
+81
-0
permissions.rb
...s_journalized/lib/redmine/acts/journalized/permissions.rb
+36
-0
reload.rb
...cts_as_journalized/lib/redmine/acts/journalized/reload.rb
+60
-0
reset.rb
...acts_as_journalized/lib/redmine/acts/journalized/reset.rb
+65
-0
reversion.rb
..._as_journalized/lib/redmine/acts/journalized/reversion.rb
+110
-0
save_hooks.rb
...as_journalized/lib/redmine/acts/journalized/save_hooks.rb
+115
-0
users.rb
...acts_as_journalized/lib/redmine/acts/journalized/users.rb
+86
-0
versioned.rb
..._as_journalized/lib/redmine/acts/journalized/versioned.rb
+67
-0
versions.rb
...s_as_journalized/lib/redmine/acts/journalized/versions.rb
+111
-0
changes_test.rb
vendor/plugins/acts_as_journalized/test/changes_test.rb
+169
-0
conditions_test.rb
vendor/plugins/acts_as_journalized/test/conditions_test.rb
+137
-0
configuration_test.rb
...or/plugins/acts_as_journalized/test/configuration_test.rb
+39
-0
control_test.rb
vendor/plugins/acts_as_journalized/test/control_test.rb
+152
-0
creation_test.rb
vendor/plugins/acts_as_journalized/test/creation_test.rb
+110
-0
options_test.rb
vendor/plugins/acts_as_journalized/test/options_test.rb
+52
-0
reload_test.rb
vendor/plugins/acts_as_journalized/test/reload_test.rb
+19
-0
reset_test.rb
vendor/plugins/acts_as_journalized/test/reset_test.rb
+112
-0
reversion_test.rb
vendor/plugins/acts_as_journalized/test/reversion_test.rb
+68
-0
schema.rb
vendor/plugins/acts_as_journalized/test/schema.rb
+43
-0
tagging_test.rb
vendor/plugins/acts_as_journalized/test/tagging_test.rb
+39
-0
test_helper.rb
vendor/plugins/acts_as_journalized/test/test_helper.rb
+11
-0
users_test.rb
vendor/plugins/acts_as_journalized/test/users_test.rb
+25
-0
version_test.rb
vendor/plugins/acts_as_journalized/test/version_test.rb
+43
-0
versioned_test.rb
vendor/plugins/acts_as_journalized/test/versioned_test.rb
+18
-0
versions_test.rb
vendor/plugins/acts_as_journalized/test/versions_test.rb
+172
-0
No files found.
vendor/plugins/acts_as_journalized/.gitignore
0 → 100644
View file @
b1845fcf
## MAC OS
.DS_Store
## TEXTMATE
*.tmproj
tmtags
## EMACS
*~
\#*
.\#*
## VIM
*.swp
## PROJECT::GENERAL
coverage
rdoc
pkg
## PROJECT::SPECIFIC
*.db
vendor/plugins/acts_as_journalized/GPL.txt
0 → 100644
View file @
b1845fcf
This diff is collapsed.
Click to expand it.
vendor/plugins/acts_as_journalized/LICENSE
0 → 100644
View file @
b1845fcf
"Acts_as_journalized" is a Redmine core plugin derived from the vestal_versions
Ruby on Rails plugin. The parts are under different copyright and license conditions
noted below.
The overall license terms applying to "Acts_as_journalized" as in
this distribution are 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.
For the individual files, the following copyrights and licenses apply:
app/controllers/**
app/views/**
app/helpers/**
app/models/journal_observer.rb
Copyright (C) 2006-2008 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.
lib/acts_as_journalized.rb
lib/journal_formatter.rb
lib/redmine/acts/journalized/permissions.rb
lib/redmine/acts/journalized/save_hooks.rb
lib/redmine/acts/journalized/format_hooks.rb
lib/redmine/acts/journalized/deprecated.rb
Copyright (c) 2010 Finn GmbH
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.
All remaining files are:
Copyright (c) 2009 Steve Richert
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
vendor/plugins/acts_as_journalized/README.rdoc
0 → 100644
View file @
b1845fcf
acts as journalized
A redmine core plugin for unification of journals, events and activities in redmine
vendor/plugins/acts_as_journalized/REVISION
0 → 100644
View file @
b1845fcf
67a8c4bee0a06420f1ba64eb9906a15d63bf5ac5 https://github.com/edavis10/acts_as_journalized
vendor/plugins/acts_as_journalized/app/controllers/journals_controller.rb
0 → 100644
View file @
b1845fcf
# This file is part of the acts_as_journalized plugin for the redMine
# project management software
#
# Copyright (C) 2006-2008 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 journal 2
# of the License, or (at your option) any later journal.
#
# 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
JournalsController
<
ApplicationController
unloadable
before_filter
:find_journal
def
edit
if
request
.
post?
@journal
.
update_attribute
(
:notes
,
params
[
:notes
])
if
params
[
:notes
]
@journal
.
destroy
if
@journal
.
details
.
empty?
&&
@journal
.
notes
.
blank?
call_hook
(
:controller_journals_edit_post
,
{
:journal
=>
@journal
,
:params
=>
params
})
respond_to
do
|
format
|
format
.
html
{
redirect_to
:controller
=>
@journal
.
journaled
.
class
.
name
.
pluralize
.
downcase
,
:action
=>
'show'
,
:id
=>
@journal
.
journaled_id
}
format
.
js
{
render
:action
=>
'update'
}
end
end
end
private
def
find_journal
@journal
=
Journal
.
find
(
params
[
:id
])
(
render_403
;
return
false
)
unless
@journal
.
editable_by?
(
User
.
current
)
@project
=
@journal
.
project
rescue
ActiveRecord
::
RecordNotFound
render_404
end
end
vendor/plugins/acts_as_journalized/app/helpers/journals_helper.rb
0 → 100644
View file @
b1845fcf
# This file is part of the acts_as_journalized plugin for the redMine
# project management software
#
# Copyright (C) 2006-2008 Jean-Philippe Lang
# Copyright (C) 2010 Finn GmbH, http://finn.de
#
# 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 journal 2
# of the License, or (at your option) any later journal.
#
# 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
JournalsHelper
unloadable
include
ApplicationHelper
include
ActionView
::
Helpers
::
TagHelper
def
self
.
included
(
base
)
base
.
class_eval
do
if
respond_to?
:before_filter
before_filter
:find_optional_journal
,
:only
=>
[
:edit
]
end
end
end
def
render_journal
(
model
,
journal
,
options
=
{})
return
""
if
journal
.
initial?
journal_content
=
render_journal_details
(
journal
,
:label_updated_time_by
)
journal_content
+=
render_notes
(
model
,
journal
,
options
)
unless
journal
.
notes
.
blank?
content_tag
"div"
,
journal_content
,
{
:id
=>
"change-
#{
journal
.
id
}
"
,
:class
=>
journal
.
css_classes
}
end
# This renders a journal entry wiht a header and details
def
render_journal_details
(
journal
,
header_label
=
:label_updated_time_by
)
header
=
<<-
HTML
<h4>
<div style="float:right;">
#{
link_to
"#
#{
journal
.
anchor
}
"
,
:anchor
=>
"note-
#{
journal
.
anchor
}
"
}
</div>
#{
avatar
(
journal
.
user
,
:size
=>
"24"
)
}
#{
content_tag
(
'a'
,
''
,
:name
=>
"note-
#{
journal
.
anchor
}
"
)
}
#{
authoring
journal
.
created_at
,
journal
.
user
,
:label
=>
header_label
}
</h4>
HTML
if
journal
.
details
.
any?
details
=
content_tag
"ul"
,
:class
=>
"details"
do
journal
.
details
.
collect
do
|
detail
|
if
d
=
journal
.
render_detail
(
detail
)
content_tag
(
"li"
,
d
)
end
end
.
compact
end
end
content_tag
(
"div"
,
"
#{
header
}#{
details
}
"
,
:id
=>
"change-
#{
journal
.
id
}
"
,
:class
=>
"journal"
)
end
def
render_notes
(
model
,
journal
,
options
=
{})
controller
=
model
.
class
.
name
.
downcase
.
pluralize
action
=
'edit'
reply_links
=
authorize_for
(
controller
,
action
)
if
User
.
current
.
logged?
editable
=
User
.
current
.
allowed_to?
(
options
[
:edit_permission
],
journal
.
project
)
if
options
[
:edit_permission
]
if
journal
.
user
==
User
.
current
&&
options
[
:edit_own_permission
]
editable
||=
User
.
current
.
allowed_to?
(
options
[
:edit_own_permission
],
journal
.
project
)
end
end
unless
journal
.
notes
.
blank?
links
=
returning
[]
do
|
l
|
if
reply_links
l
<<
link_to_remote
(
image_tag
(
'comment.png'
),
:title
=>
l
(
:button_quote
),
:url
=>
{
:controller
=>
controller
,
:action
=>
action
,
:id
=>
model
,
:journal_id
=>
journal
})
end
if
editable
l
<<
link_to_in_place_notes_editor
(
image_tag
(
'edit.png'
),
"journal-
#{
journal
.
id
}
-notes"
,
{
:controller
=>
'journals'
,
:action
=>
'edit'
,
:id
=>
journal
},
:title
=>
l
(
:button_edit
))
end
end
end
content
=
''
content
<<
content_tag
(
'div'
,
links
.
join
(
' '
),
:class
=>
'contextual'
)
unless
links
.
empty?
content
<<
textilizable
(
journal
,
:notes
)
css_classes
=
"wiki"
css_classes
<<
" editable"
if
editable
content_tag
(
'div'
,
content
,
:id
=>
"journal-
#{
journal
.
id
}
-notes"
,
:class
=>
css_classes
)
end
def
link_to_in_place_notes_editor
(
text
,
field_id
,
url
,
options
=
{})
onclick
=
"new Ajax.Request('
#{
url_for
(
url
)
}
', {asynchronous:true, evalScripts:true, method:'get'}); return false;"
link_to
text
,
'#'
,
options
.
merge
(
:onclick
=>
onclick
)
end
# This may conveniently be used by controllers to find journals referred to in the current request
def
find_optional_journal
@journal
=
Journal
.
find_by_id
(
params
[
:journal_id
])
end
def
render_reply
(
journal
)
user
=
journal
.
user
text
=
journal
.
notes
# Replaces pre blocks with [...]
text
=
text
.
to_s
.
strip
.
gsub
(
%r{<pre>((.|
\s
)*?)</pre>}m
,
'[...]'
)
content
=
"
#{
ll
(
Setting
.
default_language
,
:text_user_wrote
,
user
)
}
\n
> "
content
<<
text
.
gsub
(
/(\r?\n|\r\n?)/
,
"
\n
> "
)
+
"
\n\n
"
render
(
:update
)
do
|
page
|
page
<<
"$('notes').value =
\"
#{
escape_javascript
content
}
\"
;"
page
.
show
'update'
page
<<
"Form.Element.focus('notes');"
page
<<
"Element.scrollTo('update');"
page
<<
"$('notes').scrollTop = $('notes').scrollHeight - $('notes').clientHeight;"
end
end
end
\ No newline at end of file
vendor/plugins/acts_as_journalized/app/models/journal.rb
0 → 100644
View file @
b1845fcf
# This file is part of the acts_as_journalized plugin for the redMine
# project management software
#
# Copyright (c) 2009 Steve Richert
# Copyright (c) 2010 Finn GmbH, http://finn.de
#
# 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 journal 2
# of the License, or (at your option) any later journal.
#
# 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_dependency
'journal_formatter'
# The ActiveRecord model representing journals.
class
Journal
<
ActiveRecord
::
Base
unloadable
include
Comparable
include
JournalFormatter
include
JournalDeprecated
# Make sure each journaled model instance only has unique version ids
validates_uniqueness_of
:version
,
:scope
=>
[
:journaled_id
,
:type
]
belongs_to
:journaled
belongs_to
:user
# ActiveRecord::Base#changes is an existing method, so before serializing the +changes+ column,
# the existing +changes+ method is undefined. The overridden +changes+ method pertained to
# dirty attributes, but will not affect the partial updates functionality as that's based on
# an underlying +changed_attributes+ method, not +changes+ itself.
# undef_method :changes
serialize
:changes
,
Hash
# In conjunction with the included Comparable module, allows comparison of journal records
# based on their corresponding version numbers, creation timestamps and IDs.
def
<
=>
(
other
)
[
version
,
created_at
,
id
].
map
(
&
:to_i
)
<=>
[
other
.
version
,
other
.
created_at
,
other
.
id
].
map
(
&
:to_i
)
end
# Returns whether the version has a version number of 1. Useful when deciding whether to ignore
# the version during reversion, as initial versions have no serialized changes attached. Helps
# maintain backwards compatibility.
def
initial?
version
<
2
end
# The anchor number for html output
def
anchor
version
-
1
end
# Possible shortcut to the associated project
def
project
if
journaled
.
respond_to?
(
:project
)
journaled
.
project
elsif
journaled
.
is_a?
Project
journaled
else
nil
end
end
def
editable_by?
(
user
)
journaled
.
journal_editable_by?
(
user
)
end
def
details
attributes
[
"changes"
]
||
{}
end
alias_method
:changes
,
:details
def
new_value_for
(
prop
)
details
[
prop
.
to_s
].
last
if
details
.
keys
.
include?
prop
.
to_s
end
def
old_value_for
(
prop
)
details
[
prop
.
to_s
].
first
if
details
.
keys
.
include?
prop
.
to_s
end
# Returns a string of css classes
def
css_classes
s
=
'journal'
s
<<
' has-notes'
unless
notes
.
blank?
s
<<
' has-details'
unless
details
.
empty?
s
end
# This is here to allow people to disregard the difference between working with a
# Journal and the object it is attached to.
# The lookup is as follows:
## => Call super if the method corresponds to one of our attributes (will end up in AR::Base)
## => Try the journaled object with the same method and arguments
## => On error, call super
def
method_missing
(
method
,
*
args
,
&
block
)
return
super
if
attributes
[
method
.
to_s
]
journaled
.
send
(
method
,
*
args
,
&
block
)
rescue
NoMethodError
=>
e
e
.
name
==
method
?
super
:
raise
(
e
)
end
end
vendor/plugins/acts_as_journalized/app/models/journal_observer.rb
0 → 100644
View file @
b1845fcf
# 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
JournalObserver
<
ActiveRecord
::
Observer
def
after_create
(
journal
)
if
journal
.
type
==
"IssueJournal"
and
journal
.
version
>
1
after_create_issue_journal
(
journal
)
end
end
def
after_create_issue_journal
(
journal
)
if
Setting
.
notified_events
.
include?
(
'issue_updated'
)
||
(
Setting
.
notified_events
.
include?
(
'issue_note_added'
)
&&
journal
.
notes
.
present?
)
||
(
Setting
.
notified_events
.
include?
(
'issue_status_updated'
)
&&
journal
.
new_status
.
present?
)
||
(
Setting
.
notified_events
.
include?
(
'issue_priority_updated'
)
&&
journal
.
new_value_for
(
'priority_id'
).
present?
)
Mailer
.
deliver_issue_edit
(
journal
)
end
end
end
vendor/plugins/acts_as_journalized/app/views/journals/_notes_form.rhtml
0 → 100644
View file @
b1845fcf
<%
form_remote_tag
(
:url
=>
{},
:html
=>
{
:id
=>
"journal-
#{
@journal
.
id
}
-form"
})
do
%>
<%=
text_area_tag
:notes
,
@journal
.
notes
,
:class
=>
'wiki-edit'
,
:rows
=>
(
@journal
.
notes
.
blank?
?
10
:
[[
10
,
@journal
.
notes
.
length
/
50
].
max
,
100
].
min
)
%>
<%=
call_hook
(
:view_journals_notes_form_after_notes
,
{
:journal
=>
@journal
})
%>
<p>
<%=
submit_tag
l
(
:button_save
)
%>
<%=
link_to
l
(
:button_cancel
),
'#'
,
:onclick
=>
"Element.remove('journal-
#{
@journal
.
id
}
-form'); "
+
"Element.show('journal-
#{
@journal
.
id
}
-notes'); return false;"
%>
</p>
<%
end
%>
vendor/plugins/acts_as_journalized/app/views/journals/edit.rjs
0 → 100644
View file @
b1845fcf
page.hide "journal-#{@journal.id}-notes"
page.insert_html :after, "journal-#{@journal.id}-notes",
:partial => 'notes_form'
vendor/plugins/acts_as_journalized/app/views/journals/update.rjs
0 → 100644
View file @
b1845fcf
if @journal.frozen?
# journal was destroyed
page.remove "change-#{@journal.id}"
else
page.replace "journal-#{@journal.id}-notes", render_notes(@journal.journaled, @journal,
:edit_permission => :edit_issue_notes, :edit_own_permission => :edit_own_issue_notes)
page.show "journal-#{@journal.id}-notes"
page.remove "journal-#{@journal.id}-form"
end
call_hook(:view_journals_update_rjs_bottom, { :page => page, :journal => @journal })
vendor/plugins/acts_as_journalized/db/migrate/20100714111651_generalize_journals.rb
0 → 100644
View file @
b1845fcf
class
GeneralizeJournals
<
ActiveRecord
::
Migration
def
self
.
up
# This is provided here for migrating up after the JournalDetails has been removed
unless
Object
.
const_defined?
(
"JournalDetails"
)
Object
.
const_set
(
"JournalDetails"
,
Class
.
new
(
ActiveRecord
::
Base
))
end
change_table
:journals
do
|
t
|
t
.
rename
:journalized_id
,
:journaled_id
t
.
rename
:created_on
,
:created_at
t
.
integer
:version
,
:default
=>
0
,
:null
=>
false
t
.
string
:activity_type
t
.
text
:changes
t
.
string
:type
t
.
index
:journaled_id
t
.
index
:activity_type
t
.
index
:created_at
t
.
index
:type
end
Journal
.
all
.
group_by
(
&
:journaled_id
).
each_pair
do
|
id
,
journals
|
journals
.
sort_by
(
&
:created_at
).
each_with_index
do
|
j
,
idx
|
j
.
update_attribute
(
:type
,
"
#{
j
.
journalized_type
}
Journal"
)
j
.
update_attribute
(
:version
,
idx
+
1
)
# FIXME: Find some way to choose the right activity here
j
.
update_attribute
(
:activity_type
,
j
.
journalized_type
.
constantize
.
activity_provider_options
.
keys
.
first
)
end
end
change_table
:journals
do
|
t
|
t
.
remove
:journalized_type
end
JournalDetails
.
all
.
each
do
|
detail
|
journal
=
Journal
.
find
(
detail
.
journal_id
)
changes
=
journal
.
changes
||
{}
if
detail
.
property
==
'attr'
# Standard attributes
changes
[
detail
.
prop_key
.
to_s
]
=
[
detail
.
old_value
,
detail
.
value
]
elsif
detail
.
property
==
'cf'
# Custom fields
changes
[
"custom_values_"
+
detail
.
prop_key
.
to_s
]
=
[
detail
.
old_value
,
detail
.
value
]
elsif
detail
.
property
==
'attachment'
# Attachment
changes
[
"attachments_"
+
detail
.
prop_key
.
to_s
]
=
[
detail
.
old_value
,
detail
.
value
]
end
journal
.
update_attribute
(
:changes
,
changes
.
to_yaml
)
end
# Create creation journals for all activity providers
providers
=
Redmine
::
Activity
.
providers
.
collect
{
|
k
,
v
|
v
.
collect
(
&
:constantize
)
}.
flatten
.
compact
.
uniq
providers
.
each
do
|
p
|
next
unless
p
.
table_exists?
# Objects not in the DB yet need creation journal entries
p
.
find
(
:all
).
each
do
|
o
|
unless
o
.
last_journal
o
.
send
(
:update_journal
)
created_at
=
nil
[
:created_at
,
:created_on
,
:updated_at
,
:updated_on
].
each
do
|
m
|
if
o
.
respond_to?
m
created_at
=
o
.
send
(
m
)
break
end
end
p
"Updating
#{
o
}
"
o
.
last_journal
.
update_attribute
(
:created_at
,
created_at
)
if
created_at
and
o
.
last_journal
end
end
end
# drop_table :journal_details
end
def
self
.
down
# create_table "journal_details", :force => true do |t|
# t.integer "journal_id", :default => 0, :null => false
# t.string "property", :limit => 30, :default => "", :null => false
# t.string "prop_key", :limit => 30, :default => "", :null => false
# t.string "old_value"
# t.string "value"
# end
change_table
"journals"
do
|
t
|
t
.
rename
:journaled_id
,
:journalized_id
t
.
rename
:created_at
,
:created_on
t
.
string
:journalized_type
,
:limit
=>
30
,
:default
=>
""
,
:null
=>
false
end
custom_field_names
=
CustomField
.
all
.
group_by
(
&
:type
)[
IssueCustomField
].
collect
(
&
:name
)
Journal
.
all
.
each
do
|
j
|
j
.
update_attribute
(
:journalized_type
,
j
.
journalized
.
class
.
name
)
# j.changes.each_pair do |prop_key, values|
# if Issue.columns.collect(&:name).include? prop_key.to_s
# property = :attr
# elsif CustomField.find_by_id(prop_key.to_s)
# property = :cf
# else
# property = :attachment
# end
# JournalDetail.create(:journal_id => j.id, :property => property,
# :prop_key => prop_key, :old_value => values.first, :value => values.last)
# end
end
change_table
"journals"
do
|
t
|
t
.
remove_index
:journaled_id
t
.
remove_index
:activity_type
t
.
remove_index
:created_at
t
.
remove_index
:type
t
.
remove
:type
t
.
remove
:version
t
.
remove
:activity_type
t
.
remove
:changes
end
# add_index "journal_details", ["journal_id"], :name => "journal_details_journal_id"
# add_index "journals", ["journalized_id", "journalized_type"], :name => "journals_journalized_id"
end
end
vendor/plugins/acts_as_journalized/db/migrate/20100804112053_merge_wiki_versions_with_journals.rb
0 → 100644
View file @
b1845fcf
class
MergeWikiVersionsWithJournals
<
ActiveRecord
::
Migration
def
self
.
up
# This is provided here for migrating up after the WikiContent::Version class has been removed
unless
WikiContent
.
const_defined?
(
"Version"
)
WikiContent
.
const_set
(
"Version"
,
Class
.
new
(
ActiveRecord
::
Base
))
end
WikiContent
::
Version
.
find_by_sql
(
"SELECT * FROM wiki_content_versions"
).
each
do
|
wv
|
journal
=
WikiContentJournal
.
create!
(
:journaled_id
=>
wv
.
wiki_content_id
,
:user_id
=>
wv
.
author_id
,
:notes
=>
wv
.
comments
,
:activity_type
=>
"wiki_edits"
)
changes
=
{}
changes
[
"compression"
]
=
wv
.
compression
changes
[
"data"
]
=
wv
.
data
journal
.
update_attribute
(
:changes
,
changes
.
to_yaml
)
journal
.
update_attribute
(
:version
,
wv
.
version
)
end
# drop_table :wiki_content_versions
change_table
:wiki_contents
do
|
t
|
t
.
rename
:version
,
:lock_version
end
end
def
self
.
down
change_table
:wiki_contents
do
|
t
|
t
.
rename
:lock_version
,
:version
end
# 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 :comments, :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
#
# WikiContentJournal.all.each do |j|
# WikiContent::Version.create(:wiki_content_id => j.journaled_id, :page_id => j.journaled.page_id,
# :author_id => j.user_id, :data => j.changes["data"], :compression => j.changes["compression"],
# :comments => j.notes, :updated_on => j.created_at, :version => j.version)
# end
WikiContentJournal
.
destroy_all
end
end
vendor/plugins/acts_as_journalized/init.rb
0 → 100644
View file @
b1845fcf
$LOAD_PATH
.
unshift
File
.
expand_path
(
"../lib/"
,
__FILE__
)
require
"acts_as_journalized"
ActiveRecord
::
Base
.
send
(
:include
,
Redmine
::
Acts
::
Journalized
)
require
'dispatcher'
Dispatcher
.
to_prepare
do
# Model
require_dependency
"journal"
# this is for compatibility with current trunk
# once the plugin is part of the core, this will not be needed
# patches should then be ported onto the core
# require_dependency File.dirname(__FILE__) + '/lib/acts_as_journalized/journal_patch'
# require_dependency File.dirname(__FILE__) + '/lib/acts_as_journalized/journal_observer_patch'
# require_dependency File.dirname(__FILE__) + '/lib/acts_as_journalized/activity_fetcher_patch'
end
vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb
0 → 100644
View file @
b1845fcf
# This file is part of the acts_as_journalized plugin for the redMine
# project management software
#
# Copyright (C) 2010 Finn GmbH, http://finn.de
#
# 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 journal 2
# of the License, or (at your option) any later journal.
#
# 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.
Dir
[
File
.
expand_path
(
"../redmine/acts/journalized/*.rb"
,
__FILE__
)].
each
{
|
f
|
require
f
}
require_dependency
'lib/ar_condition'
module
Redmine
module
Acts
module
Journalized
def
self
.
included
(
base
)
base
.
extend
ClassMethods
base
.
extend
Versioned
end
module
ClassMethods
def
plural_name
self
.
name
.
underscore
.
pluralize
end
# A model might provide as many activity_types as it wishes.
# Activities are just different search options for the event a model provides
def
acts_as_activity
(
options
=
{})
activity_hash
=
journalized_activity_hash
(
options
)
type
=
activity_hash
[
:type
]
acts_as_activity_provider
activity_hash
unless
Redmine
::
Activity
.
providers
[
type
].
include?
self
.
name
Redmine
::
Activity
.
register
type
.
to_sym
,
:class_name
=>
self
.
name
end
end
# This call will add an activity and, if neccessary, start the journaling and
# add an event callback on the model.
# Versioning and acting as an Event may only be applied once.
# To apply more than on activity, use acts_as_activity
def
acts_as_journalized
(
options
=
{},
&
block
)
activity_hash
,
event_hash
,
journal_hash
=
split_option_hashes
(
options
)
acts_as_activity
(
activity_hash
)
return
if
journaled?
include
Options
include
Changes
include
Creation
include
Users
include
Reversion
include
Reset
include
Reload
include
Permissions
include
SaveHooks
include
FormatHooks
# FIXME: When the transition to the new API is complete, remove me
include
Deprecated
journal_class
.
acts_as_event
journalized_event_hash
(
event_hash
)
(
journal_hash
[
:except
]
||=
[])
<<
self
.
primary_key
<<
inheritance_column
<<
:updated_on
<<
:updated_at
<<
:lock_version
<<
:lft
<<
:rgt
prepare_journaled_options
(
journal_hash
)
has_many
:journals
,
journal_hash
.
merge
({
:class_name
=>
journal_class
.
name
,
:foreign_key
=>
"journaled_id"
}),
&
block
end
def
journal_class
journal_class_name
=
"
#{
name
.
gsub
(
"::"
,
"_"
)
}
Journal"
if
Object
.
const_defined?
(
journal_class_name
)
Object
.
const_get
(
journal_class_name
)
else
Object
.
const_set
(
journal_class_name
,
Class
.
new
(
Journal
)).
tap
do
|
c
|
# Run after the inherited hook to associate with the parent record.
# This eager loads the associated project (for permissions) if possible
if
project_assoc
=
reflect_on_association
(
:project
).
try
(
:name
)
include_option
=
", :include => :
#{
project_assoc
.
to_s
}
"
end
c
.
class_eval
(
"belongs_to :journaled, :class_name => '
#{
name
}
'
#{
include_option
}
"
)
c
.
class_eval
(
"belongs_to :
#{
name
.
gsub
(
"::"
,
"_"
).
underscore
}
,
:foreign_key => 'journaled_id'
#{
include_option
}
"
)
end
end
end
private
# Splits an option has into three hashes:
## => [{ options prefixed with "activity_" }, { options prefixed with "event_" }, { other options }]
def
split_option_hashes
(
options
)
activity_hash
=
{}
event_hash
=
{}
journal_hash
=
{}
options
.
each_pair
do
|
k
,
v
|
case
when
k
.
to_s
=~
/^activity_(.+)$/
activity_hash
[
$1
.
to_sym
]
=
v
when
k
.
to_s
=~
/^event_(.+)$/
event_hash
[
$1
.
to_sym
]
=
v
else
journal_hash
[
k
.
to_sym
]
=
v
end
end
[
activity_hash
,
event_hash
,
journal_hash
]
end
# Merges the passed activity_hash with the options we require for
# acts_as_journalized to work, as follows:
# # type is the supplied or the pluralized class name
# # timestamp is supplied or the journal's created_at
# # author_key will always be the journal's author
# #
# # find_options are merged as follows:
# # # select statement is enriched with the journal fields
# # # journal association is added to the includes
# # # if a project is associated with the model, this is added to the includes
# # # the find conditions are extended to only choose journals which have the proper activity_type
# => a valid activity hash
def
journalized_activity_hash
(
options
)
options
.
tap
do
|
h
|
h
[
:type
]
||=
plural_name
h
[
:timestamp
]
=
"
#{
journal_class
.
table_name
}
.created_at"
h
[
:author_key
]
=
"
#{
journal_class
.
table_name
}
.user_id"
h
[
:find_options
]
||=
{}
# in case it is nil
h
[
:find_options
]
=
{}.
tap
do
|
opts
|
cond
=
ARCondition
.
new
cond
.
add
([
"
#{
journal_class
.
table_name
}
.activity_type = ?"
,
h
[
:type
]])
cond
.
add
(
h
[
:find_options
][
:conditions
])
if
h
[
:find_options
][
:conditions
]
opts
[
:conditions
]
=
cond
.
conditions
include_opts
=
[]
include_opts
<<
:project
if
reflect_on_association
(
:project
)
if
h
[
:find_options
][
:include
]
include_opts
+=
case
h
[
:find_options
][
:include
]
when
Array
then
h
[
:find_options
][
:include
]
else
[
h
[
:find_options
][
:include
]]
end
end
include_opts
.
uniq!
opts
[
:include
]
=
[
:journaled
=>
include_opts
]
#opts[:joins] = h[:find_options][:joins] if h[:find_options][:joins]
end
end
end
# Merges the event hashes defaults with the options provided by the user
# The defaults take their details from the journal
def
journalized_event_hash
(
options
)
unless
options
.
has_key?
:url
options
[
:url
]
=
Proc
.
new
do
|
journal
|
{
:controller
=>
plural_name
,
:action
=>
'show'
,
:id
=>
journal
.
journaled_id
,
:anchor
=>
(
"note-
#{
journal
.
anchor
}
"
unless
journal
.
initial?
)
}
end
end
{
:description
=>
:notes
,
:author
=>
:user
}.
reverse_merge
options
end
end
end
end
end
\ No newline at end of file
vendor/plugins/acts_as_journalized/lib/journal_deprecated.rb
0 → 100644
View file @
b1845fcf
# This file is part of the acts_as_journalized plugin for the redMine
# project management software
#
# Copyright (C) 2010 Finn GmbH, http://finn.de
#
# 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 journal 2
# of the License, or (at your option) any later journal.
#
# 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.
# This module holds the formatting methods that each journal has.
# It provides the hooks to apply different formatting to the details
# of a specific journal.
module
JournalDeprecated
unloadable
# Old timestamps. created_at is what t.timestamps creates in recent Rails journals
def
created_on
created_at
end
# Old naming
def
journalized
journaled
end
# Old naming
def
journalized
=
obj
journaled
=
obj
end
# Shortcut from more issue-specific journals
def
attachments
journalized
.
respond_to?
(
:attachments
)
?
journalized
.
attachments
:
nil
end
# deprecate :created_on => "use #created_at"
# deprecate :journalized => "use journaled"
# deprecate :attachments => "implement it yourself"
end
vendor/plugins/acts_as_journalized/lib/journal_formatter.rb
0 → 100644
View file @
b1845fcf
# This file is part of the acts_as_journalized plugin for the redMine
# project management software
#
# Copyright (C) 2010 Finn GmbH, http://finn.de
#
# 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 journal 2
# of the License, or (at your option) any later journal.
#
# 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.
# This module holds the formatting methods that each journal has.
# It provides the hooks to apply different formatting to the details
# of a specific journal.
module
JournalFormatter
unloadable
mattr_accessor
:formatters
,
:registered_fields
include
ApplicationHelper
include
CustomFieldsHelper
include
ActionView
::
Helpers
::
TagHelper
include
ActionView
::
Helpers
::
UrlHelper
extend
Redmine
::
I18n
def
self
.
register
(
hash
)
if
hash
[
:class
]
klazz
=
hash
.
delete
(
:class
)
registered_fields
[
klazz
]
||=
{}
registered_fields
[
klazz
].
merge!
(
hash
)
else
formatters
.
merge
(
hash
)
end
end
# TODO: Document Formatters (can take up to three params, value, journaled, field ...)
def
self
.
default_formatters
{
:plaintext
=>
(
Proc
.
new
{
|
v
,
*|
v
.
try
(
:to_s
)
}),
:datetime
=>
(
Proc
.
new
{
|
v
,
*|
format_date
(
v
.
to_date
)
}),
:named_association
=>
(
Proc
.
new
do
|
value
,
journaled
,
field
|
association
=
journaled
.
class
.
reflect_on_association
(
field
.
to_sym
)
if
association
record
=
association
.
class_name
.
constantize
.
find_by_id
(
value
.
to_i
)
record
.
name
if
record
end
end
),
:fraction
=>
(
Proc
.
new
{
|
v
,
*|
"%0.02f"
%
v
.
to_f
}),
:decimal
=>
(
Proc
.
new
{
|
v
,
*|
v
.
to_i
.
to_s
}),
:id
=>
(
Proc
.
new
{
|
v
,
*|
"#
#{
v
}
"
})
}
end
self
.
formatters
=
default_formatters
self
.
registered_fields
=
{}
def
format_attribute_detail
(
key
,
values
,
no_html
=
false
)
field
=
key
.
to_s
.
gsub
(
/\_id$/
,
""
)
label
=
l
((
"field_"
+
field
).
to_sym
)
if
format
=
JournalFormatter
.
registered_fields
[
self
.
class
.
name
.
to_sym
][
key
]
formatter
=
JournalFormatter
.
formatters
[
format
]
old_value
=
formatter
.
call
(
values
.
first
,
journaled
,
field
)
if
values
.
first
value
=
formatter
.
call
(
values
.
last
,
journaled
,
field
)
if
values
.
last
[
label
,
old_value
,
value
]
else
return
nil
end
end
def
format_custom_value_detail
(
custom_field
,
values
,
no_html
)
label
=
custom_field
.
name
old_value
=
format_value
(
values
.
first
,
custom_field
.
field_format
)
if
values
.
first
value
=
format_value
(
values
.
last
,
custom_field
.
field_format
)
if
values
.
last
[
label
,
old_value
,
value
]
end
def
format_attachment_detail
(
key
,
values
,
no_html
)
label
=
l
(
:label_attachment
)
old_value
=
values
.
first
value
=
values
.
last
[
label
,
old_value
,
value
]
end
def
format_html_attachment_detail
(
key
,
value
)
if
!
value
.
blank?
&&
a
=
Attachment
.
find_by_id
(
key
.
to_i
)
# Link to the attachment if it has not been removed
# FIXME: this is broken => link_to_attachment(a)
a
.
filename
else
content_tag
(
"i"
,
h
(
value
))
if
value
.
present?
end
end
def
format_html_detail
(
label
,
old_value
,
value
)
label
=
content_tag
(
'strong'
,
label
)
old_value
=
content_tag
(
"i"
,
h
(
old_value
))
if
old_value
&&
!
old_value
.
blank?
old_value
=
content_tag
(
"strike"
,
old_value
)
if
old_value
and
value
.
blank?
value
=
content_tag
(
"i"
,
h
(
value
))
if
value
.
present?
value
||=
""
[
label
,
old_value
,
value
]
end
def
property
(
detail
)
key
=
prop_key
(
detail
)
if
key
.
start_with?
"custom_values"
:custom_field
elsif
key
.
start_with?
"attachments"
:attachment
elsif
journaled
.
class
.
columns
.
collect
(
&
:name
).
include?
key
:attribute
end
end
def
prop_key
(
detail
)
if
detail
.
respond_to?
:to_ary
detail
.
first
else
detail
end
end
def
values
(
detail
)
key
=
prop_key
(
detail
)
if
detail
!=
key
detail
.
last
else
details
[
key
.
to_s
]
end
end
def
old_value
(
detail
)
values
(
detail
).
first
end
def
value
(
detail
)
values
(
detail
).
last
end
def
render_detail
(
detail
,
no_html
=
false
)
if
detail
.
respond_to?
:to_ary
key
=
detail
.
first
values
=
detail
.
last
else
key
=
detail
values
=
details
[
key
.
to_s
]
end
case
property
(
detail
)
when
:attribute
attr_detail
=
format_attribute_detail
(
key
,
values
,
no_html
)
when
:custom_field
custom_field
=
CustomField
.
find_by_id
(
key
.
sub
(
"custom_values"
,
""
).
to_i
)
cv_detail
=
format_custom_value_detail
(
custom_field
,
values
,
no_html
)
when
:attachment
attachment_detail
=
format_attachment_detail
(
key
.
sub
(
"attachments"
,
""
),
values
,
no_html
)
end
label
,
old_value
,
value
=
attr_detail
||
cv_detail
||
attachment_detail
Redmine
::
Hook
.
call_hook
:helper_issues_show_detail_after_setting
,
{
:detail
=>
detail
,
:label
=>
label
,
:value
=>
value
,
:old_value
=>
old_value
}
return
nil
unless
label
||
old_value
||
value
# print nothing if there are no values
label
,
old_value
,
value
=
[
label
,
old_value
,
value
].
collect
(
&
:to_s
)
unless
no_html
label
,
old_value
,
value
=
*
format_html_detail
(
label
,
old_value
,
value
)
value
=
format_html_attachment_detail
(
key
.
sub
(
"attachments"
,
""
),
value
)
if
attachment_detail
end
unless
value
.
blank?
if
attr_detail
||
cv_detail
unless
old_value
.
blank?
l
(
:text_journal_changed
,
:label
=>
label
,
:old
=>
old_value
,
:new
=>
value
)
else
l
(
:text_journal_set_to
,
:label
=>
label
,
:value
=>
value
)
end
elsif
attachment_detail
l
(
:text_journal_added
,
:label
=>
label
,
:value
=>
value
)
end
else
l
(
:text_journal_deleted
,
:label
=>
label
,
:old
=>
old_value
)
end
end
end
vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/changes.rb
0 → 100644
View file @
b1845fcf
# This file included as part of the acts_as_journalized plugin for
# the redMine project management 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 journal 2
# of the License, or (at your option) any later journal.
#
# 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.
#
# The original copyright and license conditions are:
# Copyright (c) 2009 Steve Richert
#
# 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.
module
Redmine::Acts::Journalized
# Provides the ability to manipulate hashes in the specific format that ActiveRecord gives to
# dirty attribute changes: string keys and unique, two-element array values.
module
Changes
def
self
.
included
(
base
)
# :nodoc:
Hash
.
send
(
:include
,
HashMethods
)
base
.
class_eval
do
include
InstanceMethods
after_update
:merge_journal_changes
end
end
# Methods available to journaled ActiveRecord::Base instances in order to manage changes used
# for journal creation.
module
InstanceMethods
# Collects an array of changes from a record's journals between the given range and compiles
# them into one summary hash of changes. The +from+ and +to+ arguments can each be either a
# version number, a symbol representing an association proxy method, a string representing a
# journal tag or a journal object itself.
def
changes_between
(
from
,
to
)
from_number
,
to_number
=
journals
.
journal_at
(
from
),
journals
.
journal_at
(
to
)
return
{}
if
from_number
==
to_number
chain
=
journals
.
between
(
from_number
,
to_number
).
reject
(
&
:initial?
)
return
{}
if
chain
.
empty?
backward
=
from_number
>
to_number
backward
?
chain
.
pop
:
chain
.
shift
unless
from_number
==
1
||
to_number
==
1
chain
.
inject
({})
do
|
changes
,
journal
|
changes
.
append_changes!
(
backward
?
journal
.
changes
.
reverse_changes
:
journal
.
changes
)
end
end
private
# Before a new journal is created, the newly-changed attributes are appended onto a hash
# of previously-changed attributes. Typically the previous changes will be empty, except in
# the case that a control block is used where journals are to be merged. See
# VestalVersions::Control for more information.
def
merge_journal_changes
journal_changes
.
append_changes!
(
incremental_journal_changes
)
end
# Stores the cumulative changes that are eventually used for journal creation.
def
journal_changes
@journal_changes
||=
{}
end
# Stores the incremental changes that are appended to the cumulative changes before journal
# creation. Incremental changes are reset when the record is saved because they represent
# a subset of the dirty attribute changes, which are reset upon save.
def
incremental_journal_changes
changes
.
slice
(
*
journaled_columns
)
end
# Simply resets the cumulative changes after journal creation.
def
reset_journal_changes
@journal_changes
=
nil
end
end
# Instance methods included into Hash for dealing with manipulation of hashes in the specific
# format of ActiveRecord::Base#changes.
module
HashMethods
# When called on a hash of changes and given a second hash of changes as an argument,
# +append_changes+ will run the second hash on top of the first, updating the last element
# of each array value with its own, or creating its own key/value pair for missing keys.
# Resulting non-unique array values are removed.
#
# == Example
#
# first = {
# "first_name" => ["Steve", "Stephen"],
# "age" => [25, 26]
# }
# second = {
# "first_name" => ["Stephen", "Steve"],
# "last_name" => ["Richert", "Jobs"],
# "age" => [26, 54]
# }
# first.append_changes(second)
# # => {
# "last_name" => ["Richert", "Jobs"],
# "age" => [25, 54]
# }
def
append_changes
(
changes
)
changes
.
inject
(
self
)
do
|
new_changes
,
(
attribute
,
change
)
|
new_change
=
[
new_changes
.
fetch
(
attribute
,
change
).
first
,
change
.
last
]
new_changes
.
merge
(
attribute
=>
new_change
)
end
.
reject
do
|
attribute
,
change
|
change
.
first
==
change
.
last
end
end
# Destructively appends a given hash of changes onto an existing hash of changes.
def
append_changes!
(
changes
)
replace
(
append_changes
(
changes
))
end
# Appends the existing hash of changes onto a given hash of changes. Relates to the
# +append_changes+ method in the same way that Hash#reverse_merge relates to
# Hash#merge.
def
prepend_changes
(
changes
)
changes
.
append_changes
(
self
)
end
# Destructively prepends a given hash of changes onto an existing hash of changes.
def
prepend_changes!
(
changes
)
replace
(
prepend_changes
(
changes
))
end
# Reverses the array values of a hash of changes. Useful for rejournal both backward and
# forward through a record's history of changes.
def
reverse_changes
inject
({}){
|
nc
,(
a
,
c
)
|
nc
.
merge!
(
a
=>
c
.
reverse
)
}
end
# Destructively reverses the array values of a hash of changes.
def
reverse_changes!
replace
(
reverse_changes
)
end
end
end
end
vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/configuration.rb
0 → 100644
View file @
b1845fcf
# This file included as part of the acts_as_journalized plugin for
# the redMine project management 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.
#
# The original copyright and license conditions are:
# Copyright (c) 2009 Steve Richert
#
# 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.
module
Redmine::Acts::Journalized
# Allows for easy application-wide configuration of options passed into the +journaled+ method.
module
Configuration
# The VestalVersions module is extended by VestalVersions::Configuration, allowing the
# +configure method+ to be used as follows in a Rails initializer:
#
# VestalVersions.configure do |config|
# config.class_name = "MyCustomVersion"
# config.dependent = :destroy
# end
#
# Each variable assignment in the +configure+ block corresponds directly with the options
# available to the +journaled+ method. Assigning common options in an initializer can keep your
# models tidy.
#
# If an option is given in both an initializer and in the options passed to +journaled+, the
# value given in the model itself will take precedence.
def
configure
yield
Configuration
end
class
<<
self
# Simply stores a hash of options given to the +configure+ block.
def
options
@options
||=
{}
end
# If given a setter method name, will assign the first argument to the +options+ hash with
# the method name (sans "=") as the key. If given a getter method name, will attempt to
# a value from the +options+ hash for that key. If the key doesn't exist, defers to +super+.
def
method_missing
(
symbol
,
*
args
)
if
(
method
=
symbol
.
to_s
).
sub!
(
/\=$/
,
''
)
options
[
method
.
to_sym
]
=
args
.
first
else
options
.
fetch
(
method
.
to_sym
,
super
)
end
end
end
end
end
vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/creation.rb
0 → 100644
View file @
b1845fcf
# This file included as part of the acts_as_journalized plugin for
# the redMine project management 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.
#
# The original copyright and license conditions are:
# Copyright (c) 2009 Steve Richert
#
# 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.
module
Redmine::Acts::Journalized
# Adds the functionality necessary to control journal creation on a journaled instance of
# ActiveRecord::Base.
module
Creation
def
self
.
included
(
base
)
# :nodoc:
base
.
class_eval
do
extend
ClassMethods
include
InstanceMethods
after_save
:create_journal
,
:if
=>
:create_journal?
class
<<
self
alias_method_chain
:prepare_journaled_options
,
:creation
end
end
end
# Class methods added to ActiveRecord::Base to facilitate the creation of new journals.
module
ClassMethods
# Overrides the basal +prepare_journaled_options+ method defined in VestalVersions::Options
# to extract the <tt>:only</tt> and <tt>:except</tt> options into +vestal_journals_options+.
def
prepare_journaled_options_with_creation
(
options
)
result
=
prepare_journaled_options_without_creation
(
options
)
self
.
vestal_journals_options
[
:only
]
=
Array
(
options
.
delete
(
:only
)).
map
(
&
:to_s
).
uniq
if
options
[
:only
]
self
.
vestal_journals_options
[
:except
]
=
Array
(
options
.
delete
(
:except
)).
map
(
&
:to_s
).
uniq
if
options
[
:except
]
result
end
end
# Instance methods that determine whether to save a journal and actually perform the save.
module
InstanceMethods
private
# Returns whether a new journal should be created upon updating the parent record.
# A new journal will be created if
# a) attributes have changed
# b) no previous journal exists
# c) journal notes were added
# d) the parent record is already saved
def
create_journal?
update_journal
(
journal_changes
.
present?
or
journal_notes
.
present?
or
journals
.
empty?
)
and
!
new_record?
end
# Creates a new journal upon updating the parent record.
# "update_journal" has been called in "update_journal?" at this point (to get a hold on association changes)
# It must not be called again here.
def
create_journal
journals
<<
self
.
class
.
journal_class
.
create
(
journal_attributes
)
reset_journal_changes
reset_journal
true
rescue
Exception
=>
e
# FIXME: What to do? This likely means that the parent record is invalid!
p
e
p
e
.
message
p
e
.
backtrace
false
end
# Returns an array of column names that should be included in the changes of created
# journals. If <tt>vestal_journals_options[:only]</tt> is specified, only those columns
# will be journaled. Otherwise, if <tt>vestal_journals_options[:except]</tt> is specified,
# all columns will be journaled other than those specified. Without either option, the
# default is to journal all columns. At any rate, the four "automagic" timestamp columns
# maintained by Rails are never journaled.
def
journaled_columns
case
when
vestal_journals_options
[
:only
]
then
self
.
class
.
column_names
&
vestal_journals_options
[
:only
]
when
vestal_journals_options
[
:except
]
then
self
.
class
.
column_names
-
vestal_journals_options
[
:except
]
else
self
.
class
.
column_names
end
-
%w(created_at updated_at)
end
# Returns the activity type. Should be overridden in the journalized class to offer
# multiple types
def
activity_type
self
.
class
.
name
.
underscore
.
pluralize
end
# Specifies the attributes used during journal creation. This is separated into its own
# method so that it can be overridden by the VestalVersions::Users feature.
def
journal_attributes
attributes
=
{
:journaled_id
=>
self
.
id
,
:activity_type
=>
activity_type
,
:changes
=>
journal_changes
,
:version
=>
last_version
+
1
,
:notes
=>
journal_notes
,
:user_id
=>
(
journal_user
.
try
(
:id
)
||
User
.
current
)
}
end
end
end
end
\ No newline at end of file
vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/deprecated.rb
0 → 100644
View file @
b1845fcf
# This file is part of the acts_as_journalized plugin for the redMine
# project management software
#
# Copyright (C) 2010 Finn GmbH, http://finn.de
#
# 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.
# These hooks make sure journals are properly created and updated with Redmine user detail,
# notes and associated custom fields
module
Redmine::Acts::Journalized
module
Deprecated
# Old mailer API
def
recipients
notified
=
project
.
notified_users
notified
.
reject!
{
|
user
|
!
visible?
(
user
)}
notified
.
collect
(
&
:mail
)
end
def
current_journal
last_journal
end
# FIXME: When the new API is settled, remove me
Redmine
::
Acts
::
Event
::
InstanceMethods
.
instance_methods
(
false
).
each
do
|
m
|
if
m
.
start_with?
"event_"
class_eval
(
<<-
RUBY
,
__FILE__
,
__LINE__
)
def
#{
m
}
if last_journal.nil?
begin
journals << self.class.journal_class.create(journal_attributes)
reset_journal_changes
reset_journal
true
rescue Exception => e # FIXME: What to do? This likely means that the parent record is invalid!
p e
p e.message
p e.backtrace
false
end
journals.reload
end
return last_journal.
#{
m
}
end
RUBY
end
end
def
event_url
(
options
=
{})
last_journal
.
event_url
(
options
)
end
# deprecate :recipients => "use #last_journal.recipients"
# deprecate :current_journal => "use #last_journal"
end
end
vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/format_hooks.rb
0 → 100644
View file @
b1845fcf
# This file is part of the acts_as_journalized plugin for the redMine
# project management software
#
# Copyright (C) 2010 Finn GmbH, http://finn.de
#
# 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
Redmine::Acts::Journalized
module
FormatHooks
def
self
.
included
(
base
)
base
.
extend
ClassMethods
end
module
ClassMethods
# Shortcut to register a formatter for a number of fields
def
register_on_journal_formatter
(
formatter
,
*
field_names
)
formatter
=
formatter
.
to_sym
field_names
.
collect
(
&
:to_s
).
each
do
|
field
|
JournalFormatter
.
register
:class
=>
self
.
journal_class
.
name
.
to_sym
,
field
=>
formatter
end
end
# Shortcut to register a new proc as a named formatter. Overwrites
# existing formatters with the same name
def
register_journal_formatter
(
formatter
)
JournalFormatter
.
register
formatter
.
to_sym
=>
Proc
.
new
end
end
end
end
vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/options.rb
0 → 100644
View file @
b1845fcf
# This file included as part of the acts_as_journalized plugin for
# the redMine project management 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.
#
# The original copyright and license conditions are:
# Copyright (c) 2009 Steve Richert
#
# 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.
module
Redmine::Acts::Journalized
# Provides +journaled+ options conjournal and cleanup.
module
Options
def
self
.
included
(
base
)
# :nodoc:
base
.
class_eval
do
extend
ClassMethods
end
end
# Class methods that provide preparation of options passed to the +journaled+ method.
module
ClassMethods
# The +prepare_journaled_options+ method has three purposes:
# 1. Populate the provided options with default values where needed
# 2. Prepare options for use with the +has_many+ association
# 3. Save user-configurable options in a class-level variable
#
# Options are given priority in the following order:
# 1. Those passed directly to the +journaled+ method
# 2. Those specified in an initializer +configure+ block
# 3. Default values specified in +prepare_journaled_options+
#
# The method is overridden in feature modules that require specific options outside the
# standard +has_many+ associations.
def
prepare_journaled_options
(
options
)
options
.
symbolize_keys!
options
.
reverse_merge!
(
Configuration
.
options
)
options
.
reverse_merge!
(
:class_name
=>
'Journal'
,
:dependent
=>
:delete_all
)
options
.
reverse_merge!
(
:order
=>
"
#{
options
[
:class_name
].
constantize
.
table_name
}
.version ASC"
)
class_inheritable_accessor
:vestal_journals_options
self
.
vestal_journals_options
=
options
.
dup
options
.
merge!
(
:extend
=>
Array
(
options
[
:extend
]).
unshift
(
Versions
)
)
end
end
end
end
vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/permissions.rb
0 → 100644
View file @
b1845fcf
# This file is part of the acts_as_journalized plugin for the redMine
# project management software
#
# Copyright (C) 2010 Finn GmbH, http://finn.de
#
# 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
Redmine::Acts::Journalized
module
Permissions
# Default implementation of journal editing permission
# Is overridden if defined in the journalized model directly
def
journal_editable_by?
(
user
)
return
true
if
user
.
admin?
if
respond_to?
:editable_by?
editable_by?
user
else
permission
=
:"edit_
#{
self
.
class
.
to_s
.
pluralize
.
downcase
}
"
p
=
@project
||
(
project
if
respond_to?
:project
)
options
=
{
:global
=>
p
.
present?
}
user
.
allowed_to?
permission
,
p
,
options
end
end
end
end
vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/reload.rb
0 → 100644
View file @
b1845fcf
# This file included as part of the acts_as_journalized plugin for
# the redMine project management 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.
#
# The original copyright and license conditions are:
# Copyright (c) 2009 Steve Richert
#
# 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.
module
Redmine::Acts::Journalized
# Ties into the existing ActiveRecord::Base#reload method to ensure that journal information
# is properly reset.
module
Reload
def
self
.
included
(
base
)
# :nodoc:
base
.
class_eval
do
include
InstanceMethods
alias_method_chain
:reload
,
:journals
end
end
# Adds instance methods into ActiveRecord::Base to tap into the +reload+ method.
module
InstanceMethods
# Overrides ActiveRecord::Base#reload, resetting the instance-variable-cached journal number
# before performing the original +reload+ method.
def
reload_with_journals
(
*
args
)
reset_journal
reload_without_journals
(
*
args
)
end
end
end
end
vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/reset.rb
0 → 100644
View file @
b1845fcf
# This file included as part of the acts_as_journalized plugin for
# the redMine project management 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.
#
# The original copyright and license conditions are:
# Copyright (c) 2009 Steve Richert
#
# 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.
module
Redmine::Acts::Journalized
# Adds the ability to "reset" (or hard revert) a journaled ActiveRecord::Base instance.
module
Reset
def
self
.
included
(
base
)
# :nodoc:
base
.
class_eval
do
include
InstanceMethods
end
end
# Adds the instance methods required to reset an object to a previous journal.
module
InstanceMethods
# Similar to +revert_to!+, the +reset_to!+ method reverts an object to a previous journal,
# only instead of creating a new record in the journal history, +reset_to!+ deletes all of
# the journal history that occurs after the journal reverted to.
#
# The action taken on each journal record after the point of rejournal is determined by the
# <tt>:dependent</tt> option given to the +journaled+ method. See the +journaled+ method
# documentation for more details.
def
reset_to!
(
value
)
if
saved
=
skip_journal
{
revert_to!
(
value
)
}
journals
.
send
(
:delete_records
,
journals
.
after
(
value
))
reset_journal
end
saved
end
end
end
end
vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/reversion.rb
0 → 100644
View file @
b1845fcf
# This file included as part of the acts_as_journalized plugin for
# the redMine project management 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.
#
# The original copyright and license conditions are:
# Copyright (c) 2009 Steve Richert
#
# 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.
module
Redmine::Acts::Journalized
# Enables versioned ActiveRecord::Base instances to revert to a previously saved version.
module
Reversion
def
self
.
included
(
base
)
# :nodoc:
base
.
class_eval
do
include
InstanceMethods
end
end
# Provides the base instance methods required to revert a journaled instance.
module
InstanceMethods
# Returns the current version number for the versioned object.
def
version
@version
||=
last_version
end
def
last_journal
journals
.
last
end
# Accepts a value corresponding to a specific journal record, builds a history of changes
# between that journal and the current journal, and then iterates over that history updating
# the object's attributes until the it's reverted to its prior state.
#
# The single argument should adhere to one of the formats as documented in the +at+ method of
# VestalVersions::Versions.
#
# After the object is reverted to the target journal, it is not saved. In order to save the
# object after the rejournal, use the +revert_to!+ method.
#
# The journal number of the object will reflect whatever journal has been reverted to, and
# the return value of the +revert_to+ method is also the target journal number.
def
revert_to
(
value
)
to_number
=
journals
.
journal_at
(
value
)
changes_between
(
journal
,
to_number
).
each
do
|
attribute
,
change
|
write_attribute
(
attribute
,
change
.
last
)
end
reset_journal
(
to_number
)
end
# Behaves similarly to the +revert_to+ method except that it automatically saves the record
# after the rejournal. The return value is the success of the save.
def
revert_to!
(
value
)
revert_to
(
value
)
reset_journal
if
saved
=
save
saved
end
# Returns a boolean specifying whether the object has been reverted to a previous journal or
# if the object represents the latest journal in the journal history.
def
reverted?
version
!=
last_version
end
private
# Returns the number of the last created journal in the object's journal history.
#
# If no associated journals exist, the object is considered at version 0.
def
last_version
@last_version
||=
journals
.
maximum
(
:version
)
||
0
end
# Clears the cached version number instance variables so that they can be recalculated.
# Useful after a new version is created.
def
reset_journal
(
version
=
nil
)
@last_version
=
nil
if
version
.
nil?
@version
=
version
end
end
end
end
\ No newline at end of file
vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/save_hooks.rb
0 → 100644
View file @
b1845fcf
# This file is part of the acts_as_journalized plugin for the redMine
# project management software
#
# Copyright (C) 2010 Finn GmbH, http://finn.de
#
# 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.
# These hooks make sure journals are properly created and updated with Redmine user detail,
# notes and associated custom fields
module
Redmine::Acts::Journalized
module
SaveHooks
def
self
.
included
(
base
)
base
.
extend
ClassMethods
base
.
class_eval
do
before_save
:init_journal
after_save
:reset_instance_variables
attr_reader
:journal_notes
,
:journal_user
end
end
# Saves the current custom values, notes and journal to include them in the next journal
# Called before save
def
init_journal
(
user
=
User
.
current
,
notes
=
""
)
@journal_notes
||=
notes
@journal_user
||=
user
@associations_before_save
||=
{}
@associations
=
{}
save_possible_association
:custom_values
,
:key
=>
:custom_field_id
,
:value
=>
:value
save_possible_association
:attachments
,
:key
=>
:id
,
:value
=>
:filename
@current_journal
||=
last_journal
end
# Saves the notes and custom value changes in the last Journal
# Called before create_journal
def
update_journal
unless
(
@associations
||
{}).
empty?
changed_associations
=
{}
changed_associations
.
merge!
(
possibly_updated_association
:custom_values
)
changed_associations
.
merge!
(
possibly_updated_association
:attachments
)
end
unless
changed_associations
.
blank?
update_extended_journal_contents
(
changed_associations
)
end
end
def
reset_instance_variables
if
last_journal
!=
@current_journal
if
last_journal
.
user
!=
@journal_user
last_journal
.
update_attribute
(
:user_id
,
@journal_user
.
id
)
end
end
@associations_before_save
=
@current_journal
=
@journal_notes
=
@journal_user
=
nil
end
def
save_possible_association
(
method
,
options
)
@associations
[
method
]
=
options
if
self
.
respond_to?
method
@associations_before_save
[
method
]
||=
send
(
method
).
inject
({})
do
|
hash
,
cv
|
hash
[
cv
.
send
(
options
[
:key
])]
=
cv
.
send
(
options
[
:value
])
hash
end
end
end
def
possibly_updated_association
(
method
)
if
@associations_before_save
[
method
]
# Has custom values from init_journal_notes
return
changed_associations
(
method
,
@associations_before_save
[
method
])
end
{}
end
# Saves the notes and changed custom values to the journal
# Creates a new journal, if no immediate attributes were changed
def
update_extended_journal_contents
(
changed_associations
)
journal_changes
.
merge!
(
changed_associations
)
end
def
changed_associations
(
method
,
previous
)
send
(
method
).
reload
# Make sure the associations are reloaded
send
(
method
).
inject
({})
do
|
hash
,
c
|
key
=
c
.
send
(
@associations
[
method
][
:key
])
new_value
=
c
.
send
(
@associations
[
method
][
:value
])
if
previous
[
key
].
blank?
&&
new_value
.
blank?
# The key was empty before, don't add a blank value
elsif
previous
[
key
]
!=
new_value
# The key's value changed
hash
[
"
#{
method
}#{
key
}
"
]
=
[
previous
[
key
],
new_value
]
end
hash
end
end
module
ClassMethods
end
end
end
vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/users.rb
0 → 100644
View file @
b1845fcf
# This file included as part of the acts_as_journalized plugin for
# the redMine project management 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.
#
# The original copyright and license conditions are:
# Copyright (c) 2009 Steve Richert
#
# 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.
module
Redmine::Acts::Journalized
# Provides a way for information to be associated with specific journals as to who was
# responsible for the associated update to the parent.
module
Users
def
self
.
included
(
base
)
# :nodoc:
Journal
.
send
(
:include
,
JournalMethods
)
base
.
class_eval
do
include
InstanceMethods
attr_accessor
:updated_by
alias_method_chain
:journal_attributes
,
:user
end
end
# Methods added to journaled ActiveRecord::Base instances to enable journaling with additional
# user information.
module
InstanceMethods
private
# Overrides the +journal_attributes+ method to include user information passed into the
# parent object, by way of a +updated_by+ attr_accessor.
def
journal_attributes_with_user
journal_attributes_without_user
.
merge
(
:user
=>
updated_by
||
User
.
current
)
end
end
# Instance methods added to Redmine::Acts::Journalized::Journal to accomodate incoming
# user information.
module
JournalMethods
def
self
.
included
(
base
)
# :nodoc:
base
.
class_eval
do
belongs_to
:user
alias_method_chain
:user
=
,
:name
end
end
# Overrides the +user=+ method created by the polymorphic +belongs_to+ user association.
# Based on the class of the object given, either the +user+ association columns or the
# +user_name+ string column is populated.
def
user_with_name
=
(
value
)
case
value
when
ActiveRecord
::
Base
then
self
.
user_without_name
=
value
else
self
.
user
=
User
.
find_by_login
(
value
)
end
end
end
end
end
vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/versioned.rb
0 → 100644
View file @
b1845fcf
# This file included as part of the acts_as_journalized plugin for
# the redMine project management 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.
#
# The original copyright and license conditions are:
# Copyright (c) 2009 Steve Richert
#
# 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.
module
Redmine::Acts::Journalized
# Simply adds a flag to determine whether a model class if journaled.
module
Versioned
def
self
.
extended
(
base
)
# :nodoc:
base
.
class_eval
do
class
<<
self
alias_method_chain
:acts_as_journalized
,
:flag
end
end
end
# Overrides the +journaled+ method to first define the +journaled?+ class method before
# deferring to the original +journaled+.
def
acts_as_journalized_with_flag
(
*
args
)
acts_as_journalized_without_flag
(
*
args
)
class
<<
self
def
journaled?
true
end
end
end
# For all ActiveRecord::Base models that do not call the +journaled+ method, the +journaled?+
# method will return false.
def
journaled?
false
end
end
end
vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/versions.rb
0 → 100644
View file @
b1845fcf
# This file included as part of the acts_as_journalized plugin for
# the redMine project management 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.
#
# The original copyright and license conditions are:
# Copyright (c) 2009 Steve Richert
#
# 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.
module
Redmine::Acts::Journalized
# An extension module for the +has_many+ association with journals.
module
Versions
# Returns all journals between (and including) the two given arguments. See documentation for
# the +at+ extension method for what arguments are valid. If either of the given arguments is
# invalid, an empty array is returned.
#
# The +between+ method preserves returns an array of journal records, preserving the order
# given by the arguments. If the +from+ value represents a journal before that of the +to+
# value, the array will be ordered from earliest to latest. The reverse is also true.
def
between
(
from
,
to
)
from_number
,
to_number
=
journal_at
(
from
),
journal_at
(
to
)
return
[]
if
from_number
.
nil?
||
to_number
.
nil?
condition
=
(
from_number
==
to_number
)
?
to_number
:
Range
.
new
(
*
[
from_number
,
to_number
].
sort
)
all
(
:conditions
=>
{
:version
=>
condition
},
:order
=>
"
#{
aliased_table_name
}
.version
#{
(
from_number
>
to_number
)
?
'DESC'
:
'ASC'
}
"
)
end
# Returns all journal records created before the journal associated with the given value.
def
before
(
value
)
return
[]
if
(
version
=
journal_at
(
value
)).
nil?
all
(
:conditions
=>
"
#{
aliased_table_name
}
.version <
#{
version
}
"
)
end
# Returns all journal records created after the journal associated with the given value.
#
# This is useful for dissociating records during use of the +reset_to!+ method.
def
after
(
value
)
return
[]
if
(
version
=
journal_at
(
value
)).
nil?
all
(
:conditions
=>
"
#{
aliased_table_name
}
.version >
#{
version
}
"
)
end
# Returns a single journal associated with the given value. The following formats are valid:
# * A Date or Time object: When given, +to_time+ is called on the value and the last journal
# record in the history created before (or at) that time is returned.
# * A Numeric object: Typically a positive integer, these values correspond to journal numbers
# and the associated journal record is found by a journal number equal to the given value
# rounded down to the nearest integer.
# * A String: A string value represents a journal tag and the associated journal is searched
# for by a matching tag value. *Note:* Be careful with string representations of numbers.
# * A Symbol: Symbols represent association class methods on the +has_many+ journals
# association. While all of the built-in association methods require arguments, additional
# extension modules can be defined using the <tt>:extend</tt> option on the +journaled+
# method. See the +journaled+ documentation for more information.
# * A Version object: If a journal object is passed to the +at+ method, it is simply returned
# untouched.
def
at
(
value
)
case
value
when
Date
,
Time
then
last
(
:conditions
=>
[
"
#{
aliased_table_name
}
.created_at <= ?"
,
value
.
to_time
])
when
Numeric
then
find_by_version
(
value
.
floor
)
when
Symbol
then
respond_to?
(
value
)
?
send
(
value
)
:
nil
when
Journal
then
value
end
end
# Returns the journal number associated with the given value. In many cases, this involves
# simply passing the value to the +at+ method and then returning the subsequent journal number.
# Hoever, for Numeric values, the journal number can be returned directly and for Date/Time
# values, a default value of 1 is given to ensure that times prior to the first journal
# still return a valid journal number (useful for rejournal).
def
journal_at
(
value
)
case
value
when
Date
,
Time
then
(
v
=
at
(
value
))
?
v
.
version
:
1
when
Numeric
then
value
.
floor
when
Symbol
then
(
v
=
at
(
value
))
?
v
.
version
:
nil
when
String
then
nil
when
Journal
then
value
.
version
end
end
end
end
\ No newline at end of file
vendor/plugins/acts_as_journalized/test/changes_test.rb
0 → 100644
View file @
b1845fcf
require
File
.
join
(
File
.
dirname
(
__FILE__
),
'test_helper'
)
class
ChangesTest
<
Test
::
Unit
::
TestCase
context
"A journal's changes"
do
setup
do
@user
=
User
.
create
(
:name
=>
'Steve Richert'
)
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
@changes
=
@user
.
journals
.
last
.
changes
end
should
'be a hash'
do
assert_kind_of
Hash
,
@changes
end
should
'not be empty'
do
assert
!
@changes
.
empty?
end
should
'have string keys'
do
@changes
.
keys
.
each
do
|
key
|
assert_kind_of
String
,
key
end
end
should
'have array values'
do
@changes
.
values
.
each
do
|
value
|
assert_kind_of
Array
,
value
end
end
should
'have two-element values'
do
@changes
.
values
.
each
do
|
value
|
assert_equal
2
,
value
.
size
end
end
should
'have unique-element values'
do
@changes
.
values
.
each
do
|
value
|
assert_equal
value
.
uniq
,
value
end
end
should
"equal the model's changes"
do
@user
.
first_name
=
'Stephen'
model_changes
=
@user
.
changes
@user
.
save
changes
=
@user
.
journals
.
last
.
changes
assert_equal
model_changes
,
changes
end
end
context
'A hash of changes'
do
setup
do
@changes
=
{
'first_name'
=>
[
'Steve'
,
'Stephen'
]}
@other
=
{
'first_name'
=>
[
'Catie'
,
'Catherine'
]}
end
should
'properly append other changes'
do
expected
=
{
'first_name'
=>
[
'Steve'
,
'Catherine'
]}
changes
=
@changes
.
append_changes
(
@other
)
assert_equal
expected
,
changes
@changes
.
append_changes!
(
@other
)
assert_equal
expected
,
@changes
end
should
'properly prepend other changes'
do
expected
=
{
'first_name'
=>
[
'Catie'
,
'Stephen'
]}
changes
=
@changes
.
prepend_changes
(
@other
)
assert_equal
expected
,
changes
@changes
.
prepend_changes!
(
@other
)
assert_equal
expected
,
@changes
end
should
'be reversible'
do
expected
=
{
'first_name'
=>
[
'Stephen'
,
'Steve'
]}
changes
=
@changes
.
reverse_changes
assert_equal
expected
,
changes
@changes
.
reverse_changes!
assert_equal
expected
,
@changes
end
end
context
'The changes between two journals'
do
setup
do
name
=
'Steve Richert'
@user
=
User
.
create
(
:name
=>
name
)
# 1
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
# 2
@user
.
update_attribute
(
:first_name
,
'Stephen'
)
# 3
@user
.
update_attribute
(
:last_name
,
'Richert'
)
# 4
@user
.
update_attribute
(
:name
,
name
)
# 5
@version
=
@user
.
version
end
should
'be a hash'
do
1
.
upto
(
@version
)
do
|
i
|
1
.
upto
(
@version
)
do
|
j
|
changes
=
@user
.
changes_between
(
i
,
j
)
assert_kind_of
Hash
,
changes
end
end
end
should
'have string keys'
do
1
.
upto
(
@version
)
do
|
i
|
1
.
upto
(
@version
)
do
|
j
|
changes
=
@user
.
changes_between
(
i
,
j
)
changes
.
keys
.
each
do
|
key
|
assert_kind_of
String
,
key
end
end
end
end
should
'have array values'
do
1
.
upto
(
@version
)
do
|
i
|
1
.
upto
(
@version
)
do
|
j
|
changes
=
@user
.
changes_between
(
i
,
j
)
changes
.
values
.
each
do
|
value
|
assert_kind_of
Array
,
value
end
end
end
end
should
'have two-element values'
do
1
.
upto
(
@version
)
do
|
i
|
1
.
upto
(
@version
)
do
|
j
|
changes
=
@user
.
changes_between
(
i
,
j
)
changes
.
values
.
each
do
|
value
|
assert_equal
2
,
value
.
size
end
end
end
end
should
'have unique-element values'
do
1
.
upto
(
@version
)
do
|
i
|
1
.
upto
(
@version
)
do
|
j
|
changes
=
@user
.
changes_between
(
i
,
j
)
changes
.
values
.
each
do
|
value
|
assert_equal
value
.
uniq
,
value
end
end
end
end
should
'be empty between identical versions'
do
assert
@user
.
changes_between
(
1
,
@version
).
empty?
assert
@user
.
changes_between
(
@version
,
1
).
empty?
end
should
'be should reverse with direction'
do
1
.
upto
(
@version
)
do
|
i
|
i
.
upto
(
@version
)
do
|
j
|
up
=
@user
.
changes_between
(
i
,
j
)
down
=
@user
.
changes_between
(
j
,
i
)
assert_equal
up
,
down
.
reverse_changes
end
end
end
should
'be empty with invalid arguments'
do
1
.
upto
(
@version
)
do
|
i
|
assert
@user
.
changes_between
(
i
,
nil
)
assert
@user
.
changes_between
(
nil
,
i
)
end
end
end
end
vendor/plugins/acts_as_journalized/test/conditions_test.rb
0 → 100644
View file @
b1845fcf
require
File
.
join
(
File
.
dirname
(
__FILE__
),
'test_helper'
)
class
ConditionsTest
<
Test
::
Unit
::
TestCase
context
'Converted :if conditions'
do
setup
do
User
.
class_eval
do
def
true
;
true
;
end
end
end
should
'be an array'
do
assert_kind_of
Array
,
User
.
vestal_journals_options
[
:if
]
User
.
prepare_journaled_options
(
:if
=>
:true
)
assert_kind_of
Array
,
User
.
vestal_journals_options
[
:if
]
end
should
'have proc values'
do
User
.
prepare_journaled_options
(
:if
=>
:true
)
assert
User
.
vestal_journals_options
[
:if
].
all?
{
|
i
|
i
.
is_a?
(
Proc
)
}
end
teardown
do
User
.
prepare_journaled_options
(
:if
=>
[])
end
end
context
'Converted :unless conditions'
do
setup
do
User
.
class_eval
do
def
true
;
true
;
end
end
end
should
'be an array'
do
assert_kind_of
Array
,
User
.
vestal_journals_options
[
:unless
]
User
.
prepare_journaled_options
(
:unless
=>
:true
)
assert_kind_of
Array
,
User
.
vestal_journals_options
[
:unless
]
end
should
'have proc values'
do
User
.
prepare_journaled_options
(
:unless
=>
:true
)
assert
User
.
vestal_journals_options
[
:unless
].
all?
{
|
i
|
i
.
is_a?
(
Proc
)
}
end
teardown
do
User
.
prepare_journaled_options
(
:unless
=>
[])
end
end
context
'A new journal'
do
setup
do
User
.
class_eval
do
def
true
;
true
;
end
def
false
;
false
;
end
end
@user
=
User
.
create
(
:name
=>
'Steve Richert'
)
@count
=
@user
.
journals
.
count
end
context
'with :if conditions'
do
context
'that pass'
do
setup
do
User
.
prepare_journaled_options
(
:if
=>
[
:true
])
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
end
should
'be created'
do
assert_equal
@count
+
1
,
@user
.
journals
.
count
end
end
context
'that fail'
do
setup
do
User
.
prepare_journaled_options
(
:if
=>
[
:false
])
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
end
should
'not be created'
do
assert_equal
@count
,
@user
.
journals
.
count
end
end
end
context
'with :unless conditions'
do
context
'that pass'
do
setup
do
User
.
prepare_journaled_options
(
:unless
=>
[
:true
])
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
end
should
'not be created'
do
assert_equal
@count
,
@user
.
journals
.
count
end
end
context
'that fail'
do
setup
do
User
.
prepare_journaled_options
(
:unless
=>
[
:false
])
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
end
should
'not be created'
do
assert_equal
@count
+
1
,
@user
.
journals
.
count
end
end
end
context
'with :if and :unless conditions'
do
context
'that pass'
do
setup
do
User
.
prepare_journaled_options
(
:if
=>
[
:true
],
:unless
=>
[
:true
])
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
end
should
'not be created'
do
assert_equal
@count
,
@user
.
journals
.
count
end
end
context
'that fail'
do
setup
do
User
.
prepare_journaled_options
(
:if
=>
[
:false
],
:unless
=>
[
:false
])
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
end
should
'not be created'
do
assert_equal
@count
,
@user
.
journals
.
count
end
end
end
teardown
do
User
.
prepare_journaled_options
(
:if
=>
[],
:unless
=>
[])
end
end
end
vendor/plugins/acts_as_journalized/test/configuration_test.rb
0 → 100644
View file @
b1845fcf
require
File
.
join
(
File
.
dirname
(
__FILE__
),
'test_helper'
)
class
ConfigurationTest
<
Test
::
Unit
::
TestCase
context
'Global configuration options'
do
setup
do
module
Extension
;
end
@options
=
{
'class_name'
=>
'CustomVersion'
,
:extend
=>
Extension
,
:as
=>
:parent
}
VestalVersions
.
configure
do
|
config
|
@options
.
each
do
|
key
,
value
|
config
.
send
(
"
#{
key
}
="
,
value
)
end
end
@configuration
=
VestalVersions
::
Configuration
.
options
end
should
'should be a hash'
do
assert_kind_of
Hash
,
@configuration
end
should
'have symbol keys'
do
assert
@configuration
.
keys
.
all?
{
|
k
|
k
.
is_a?
(
Symbol
)
}
end
should
'store values identical to those given'
do
assert_equal
@options
.
symbolize_keys
,
@configuration
end
teardown
do
VestalVersions
::
Configuration
.
options
.
clear
end
end
end
vendor/plugins/acts_as_journalized/test/control_test.rb
0 → 100644
View file @
b1845fcf
require
File
.
join
(
File
.
dirname
(
__FILE__
),
'test_helper'
)
class
ControlTest
<
Test
::
Unit
::
TestCase
context
'Within a skip_journal block,'
do
setup
do
@user
=
User
.
create
(
:name
=>
'Steve Richert'
)
@count
=
@user
.
journals
.
count
end
context
'a model update'
do
setup
do
@user
.
skip_journal
do
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
end
end
should
'not create a journal'
do
assert_equal
@count
,
@user
.
journals
.
count
end
end
context
'multiple model updates'
do
setup
do
@user
.
skip_journal
do
@user
.
update_attribute
(
:first_name
,
'Stephen'
)
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
@user
.
update_attribute
(
:first_name
,
'Steve'
)
end
end
should
'not create a journal'
do
assert_equal
@count
,
@user
.
journals
.
count
end
end
end
context
'Within a merge_journal block,'
do
setup
do
@user
=
User
.
create
(
:name
=>
'Steve Richert'
)
@count
=
@user
.
journals
.
count
end
context
'a model update'
do
setup
do
@user
.
merge_journal
do
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
end
end
should
'create a journal'
do
assert_equal
@count
+
1
,
@user
.
journals
.
count
end
end
context
'multiple model updates'
do
setup
do
@user
.
merge_journal
do
@user
.
update_attribute
(
:first_name
,
'Stephen'
)
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
@user
.
update_attribute
(
:first_name
,
'Steve'
)
end
end
should
'create a journal'
do
assert_equal
@count
+
1
,
@user
.
journals
.
count
end
end
end
context
'Within a append_journal block'
do
context
'(when no journals exist),'
do
setup
do
@user
=
User
.
create
(
:name
=>
'Steve Richert'
)
@count
=
@user
.
journals
.
count
end
context
'a model update'
do
setup
do
@user
.
append_journal
do
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
end
end
should
'create a journal'
do
assert_equal
@count
+
1
,
@user
.
journals
.
count
end
end
context
'multiple model updates'
do
setup
do
@user
.
append_journal
do
@user
.
update_attribute
(
:first_name
,
'Stephen'
)
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
@user
.
update_attribute
(
:first_name
,
'Steve'
)
end
end
should
'create a journal'
do
assert_equal
@count
+
1
,
@user
.
journals
.
count
end
end
end
context
'(when journals exist),'
do
setup
do
@user
=
User
.
create
(
:name
=>
'Steve Richert'
)
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
@user
.
update_attribute
(
:last_name
,
'Richert'
)
@last_journal
=
@user
.
journals
.
last
@count
=
@user
.
journals
.
count
end
context
'a model update'
do
setup
do
@user
.
append_journal
do
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
end
end
should
'not create a journal'
do
assert_equal
@count
,
@user
.
journals
.
count
end
should
'update the last journal'
do
last_journal
=
@user
.
journals
(
true
).
last
assert_equal
@last_journal
.
id
,
last_journal
.
id
assert_not_equal
@last_journal
.
attributes
,
last_journal
.
attributes
end
end
context
'multiple model updates'
do
setup
do
@user
.
append_journal
do
@user
.
update_attribute
(
:first_name
,
'Stephen'
)
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
@user
.
update_attribute
(
:first_name
,
'Steve'
)
end
end
should
'not create a journal'
do
assert_equal
@count
,
@user
.
journals
.
count
end
should
'update the last journal'
do
last_journal
=
@user
.
journals
(
true
).
last
assert_equal
@last_journal
.
id
,
last_journal
.
id
assert_not_equal
@last_journal
.
attributes
,
last_journal
.
attributes
end
end
end
end
end
vendor/plugins/acts_as_journalized/test/creation_test.rb
0 → 100644
View file @
b1845fcf
require
File
.
join
(
File
.
dirname
(
__FILE__
),
'test_helper'
)
class
CreationTest
<
Test
::
Unit
::
TestCase
context
'The number of journals'
do
setup
do
@name
=
'Steve Richert'
@user
=
User
.
create
(
:name
=>
@name
)
@count
=
@user
.
journals
.
count
end
should
'initially equal zero'
do
assert_equal
0
,
@count
end
should
'not increase when no changes are made in an update'
do
@user
.
update_attribute
(
:name
,
@name
)
assert_equal
@count
,
@user
.
journals
.
count
end
should
'not increase when no changes are made before a save'
do
@user
.
save
assert_equal
@count
,
@user
.
journals
.
count
end
context
'after an update'
do
setup
do
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
end
should
'increase by one'
do
assert_equal
@count
+
1
,
@user
.
journals
.
count
end
end
context
'after multiple updates'
do
setup
do
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
@user
.
update_attribute
(
:last_name
,
'Richert'
)
end
should
'increase multiple times'
do
assert_operator
@count
+
1
,
:<
,
@user
.
journals
.
count
end
end
end
context
"A created journal's changes"
do
setup
do
@user
=
User
.
create
(
:name
=>
'Steve Richert'
)
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
end
should
'not contain Rails timestamps'
do
%w(created_at created_on updated_at updated_on)
.
each
do
|
timestamp
|
assert_does_not_contain
@user
.
journals
.
last
.
changes
.
keys
,
timestamp
end
end
context
'(with :only options)'
do
setup
do
@only
=
%w(first_name)
User
.
prepare_journaled_options
(
:only
=>
@only
)
@user
.
update_attribute
(
:name
,
'Steven Tyler'
)
end
should
'only contain the specified columns'
do
assert_equal
@only
,
@user
.
journals
.
last
.
changes
.
keys
end
teardown
do
User
.
prepare_journaled_options
(
:only
=>
nil
)
end
end
context
'(with :except options)'
do
setup
do
@except
=
%w(first_name)
User
.
prepare_journaled_options
(
:except
=>
@except
)
@user
.
update_attribute
(
:name
,
'Steven Tyler'
)
end
should
'not contain the specified columns'
do
@except
.
each
do
|
column
|
assert_does_not_contain
@user
.
journals
.
last
.
changes
.
keys
,
column
end
end
teardown
do
User
.
prepare_journaled_options
(
:except
=>
nil
)
end
end
context
'(with both :only and :except options)'
do
setup
do
@only
=
%w(first_name)
@except
=
@only
User
.
prepare_journaled_options
(
:only
=>
@only
,
:except
=>
@except
)
@user
.
update_attribute
(
:name
,
'Steven Tyler'
)
end
should
'respect only the :only options'
do
assert_equal
@only
,
@user
.
journals
.
last
.
changes
.
keys
end
teardown
do
User
.
prepare_journaled_options
(
:only
=>
nil
,
:except
=>
nil
)
end
end
end
end
vendor/plugins/acts_as_journalized/test/options_test.rb
0 → 100644
View file @
b1845fcf
require
File
.
join
(
File
.
dirname
(
__FILE__
),
'test_helper'
)
class
OptionsTest
<
Test
::
Unit
::
TestCase
context
'Configuration options'
do
setup
do
@options
=
{
:dependent
=>
:destroy
}
@configuration
=
{
:class_name
=>
'MyCustomVersion'
}
VestalVersions
::
Configuration
.
options
.
clear
@configuration
.
each
{
|
k
,
v
|
VestalVersions
::
Configuration
.
send
(
"
#{
k
}
="
,
v
)
}
@prepared_options
=
User
.
prepare_journaled_options
(
@options
.
dup
)
end
should
'have symbolized keys'
do
assert
User
.
vestal_journals_options
.
keys
.
all?
{
|
k
|
k
.
is_a?
(
Symbol
)
}
end
should
'combine class-level and global configuration options'
do
combined_keys
=
(
@options
.
keys
+
@configuration
.
keys
).
map
(
&
:to_sym
).
uniq
combined_options
=
@configuration
.
symbolize_keys
.
merge
(
@options
.
symbolize_keys
)
assert_equal
@prepared_options
.
slice
(
*
combined_keys
),
combined_options
end
teardown
do
VestalVersions
::
Configuration
.
options
.
clear
User
.
prepare_journaled_options
({})
end
end
context
'Given no options, configuration options'
do
setup
do
@prepared_options
=
User
.
prepare_journaled_options
({})
end
should
'default to "VestalVersions::Version" for :class_name'
do
assert_equal
'VestalVersions::Version'
,
@prepared_options
[
:class_name
]
end
should
'default to :delete_all for :dependent'
do
assert_equal
:delete_all
,
@prepared_options
[
:dependent
]
end
should
'force the :as option value to :journaled'
do
assert_equal
:journaled
,
@prepared_options
[
:as
]
end
should
'default to [VestalVersions::Versions] for :extend'
do
assert_equal
[
VestalVersions
::
Versions
],
@prepared_options
[
:extend
]
end
end
end
vendor/plugins/acts_as_journalized/test/reload_test.rb
0 → 100644
View file @
b1845fcf
require
File
.
join
(
File
.
dirname
(
__FILE__
),
'test_helper'
)
class
ReloadTest
<
Test
::
Unit
::
TestCase
context
'Reloading a reverted model'
do
setup
do
@user
=
User
.
create
(
:name
=>
'Steve Richert'
)
first_version
=
@user
.
version
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
@last_version
=
@user
.
version
@user
.
revert_to
(
first_version
)
end
should
'reset the journal number to the most recent journal'
do
assert_not_equal
@last_journal
,
@user
.
journal
@user
.
reload
assert_equal
@last_journal
,
@user
.
journal
end
end
end
vendor/plugins/acts_as_journalized/test/reset_test.rb
0 → 100644
View file @
b1845fcf
require
File
.
join
(
File
.
dirname
(
__FILE__
),
'test_helper'
)
class
ResetTest
<
Test
::
Unit
::
TestCase
context
'Resetting a model'
do
setup
do
@original_dependent
=
User
.
reflect_on_association
(
:journals
).
options
[
:dependent
]
@user
,
@journals
=
User
.
new
,
[]
@names
=
[
'Steve Richert'
,
'Stephen Richert'
,
'Stephen Jobs'
,
'Steve Jobs'
]
@names
.
each
do
|
name
|
@user
.
update_attribute
(
:name
,
name
)
@journals
<<
@user
.
journal
end
end
should
"properly revert the model's attributes"
do
@journals
.
reverse
.
each_with_index
do
|
journal
,
i
|
@user
.
reset_to!
(
journal
)
assert_equal
@names
.
reverse
[
i
],
@user
.
name
end
end
should
'dissociate all journals after the target'
do
@journals
.
reverse
.
each
do
|
journal
|
@user
.
reset_to!
(
journal
)
assert_equal
0
,
@user
.
journals
(
true
).
after
(
journal
).
count
end
end
context
'with the :dependent option as :delete_all'
do
setup
do
User
.
reflect_on_association
(
:journals
).
options
[
:dependent
]
=
:delete_all
end
should
'delete all journals after the target journal'
do
@journals
.
reverse
.
each
do
|
journal
|
later_journals
=
@user
.
journals
.
after
(
journal
)
@user
.
reset_to!
(
journal
)
later_journals
.
each
do
|
later_journal
|
assert_raise
ActiveRecord
::
RecordNotFound
do
later_journal
.
reload
end
end
end
end
should
'not destroy all journals after the target journal'
do
VestalVersions
::
Version
.
any_instance
.
stubs
(
:destroy
).
raises
(
RuntimeError
)
@journals
.
reverse
.
each
do
|
journal
|
assert_nothing_raised
do
@user
.
reset_to!
(
journal
)
end
end
end
end
context
'with the :dependent option as :destroy'
do
setup
do
User
.
reflect_on_association
(
:journals
).
options
[
:dependent
]
=
:destroy
end
should
'delete all journals after the target journal'
do
@journals
.
reverse
.
each
do
|
journal
|
later_journals
=
@user
.
journals
.
after
(
journal
)
@user
.
reset_to!
(
journal
)
later_journals
.
each
do
|
later_journal
|
assert_raise
ActiveRecord
::
RecordNotFound
do
later_journal
.
reload
end
end
end
end
should
'destroy all journals after the target journal'
do
VestalVersions
::
Version
.
any_instance
.
stubs
(
:destroy
).
raises
(
RuntimeError
)
@journals
.
reverse
.
each
do
|
journal
|
later_journals
=
@user
.
journals
.
after
(
journal
)
if
later_journals
.
empty?
assert_nothing_raised
do
@user
.
reset_to!
(
journal
)
end
else
assert_raise
RuntimeError
do
@user
.
reset_to!
(
journal
)
end
end
end
end
end
context
'with the :dependent option as :nullify'
do
setup
do
User
.
reflect_on_association
(
:journals
).
options
[
:dependent
]
=
:nullify
end
should
'leave all journals after the target journal'
do
@journals
.
reverse
.
each
do
|
journal
|
later_journals
=
@user
.
journals
.
after
(
journal
)
@user
.
reset_to!
(
journal
)
later_journals
.
each
do
|
later_journal
|
assert_nothing_raised
do
later_journal
.
reload
end
end
end
end
end
teardown
do
User
.
reflect_on_association
(
:journals
).
options
[
:dependent
]
=
@original_dependent
end
end
end
vendor/plugins/acts_as_journalized/test/reversion_test.rb
0 → 100644
View file @
b1845fcf
require
File
.
join
(
File
.
dirname
(
__FILE__
),
'test_helper'
)
class
RejournalTest
<
Test
::
Unit
::
TestCase
context
'A model rejournal'
do
setup
do
@user
,
@attributes
,
@times
=
User
.
new
,
{},
{}
names
=
[
'Steve Richert'
,
'Stephen Richert'
,
'Stephen Jobs'
,
'Steve Jobs'
]
time
=
names
.
size
.
hours
.
ago
names
.
each
do
|
name
|
@user
.
update_attribute
(
:name
,
name
)
@attributes
[
@user
.
journal
]
=
@user
.
attributes
time
+=
1
.
hour
if
last_journal
=
@user
.
journals
.
last
last_journal
.
update_attribute
(
:created_at
,
time
)
end
@times
[
@user
.
journal
]
=
time
end
@user
.
reload
.
journals
.
reload
@first_journal
,
@last_journal
=
@attributes
.
keys
.
min
,
@attributes
.
keys
.
max
end
should
'return the new journal number'
do
new_journal
=
@user
.
revert_to
(
@first_journal
)
assert_equal
@first_journal
,
new_journal
end
should
'change the journal number when saved'
do
current_journal
=
@user
.
journal
@user
.
revert_to!
(
@first_journal
)
assert_not_equal
current_journal
,
@user
.
journal
end
should
'do nothing for a invalid argument'
do
current_journal
=
@user
.
journal
[
nil
,
:bogus
,
'bogus'
,
(
1
..
2
)].
each
do
|
invalid
|
@user
.
revert_to
(
invalid
)
assert_equal
current_journal
,
@user
.
journal
end
end
should
'be able to target a journal number'
do
@user
.
revert_to
(
1
)
assert
1
,
@user
.
journal
end
should
'be able to target a date and time'
do
@times
.
each
do
|
journal
,
time
|
@user
.
revert_to
(
time
+
1
.
second
)
assert_equal
journal
,
@user
.
journal
end
end
should
'be able to target a journal object'
do
@user
.
journals
.
each
do
|
journal
|
@user
.
revert_to
(
journal
)
assert_equal
journal
.
number
,
@user
.
journal
end
end
should
"correctly roll back the model's attributes"
do
timestamps
=
%w(created_at created_on updated_at updated_on)
@attributes
.
each
do
|
journal
,
attributes
|
@user
.
revert_to!
(
journal
)
assert_equal
attributes
.
except
(
*
timestamps
),
@user
.
attributes
.
except
(
*
timestamps
)
end
end
end
end
vendor/plugins/acts_as_journalized/test/schema.rb
0 → 100644
View file @
b1845fcf
ActiveRecord
::
Base
.
establish_connection
(
:adapter
=>
defined?
(
RUBY_ENGINE
)
&&
RUBY_ENGINE
==
'jruby'
?
'jdbcsqlite3'
:
'sqlite3'
,
:database
=>
File
.
join
(
File
.
dirname
(
__FILE__
),
'test.db'
)
)
class
CreateSchema
<
ActiveRecord
::
Migration
def
self
.
up
create_table
:users
,
:force
=>
true
do
|
t
|
t
.
string
:first_name
t
.
string
:last_name
t
.
timestamps
end
create_table
:journals
,
:force
=>
true
do
|
t
|
t
.
belongs_to
:journaled
,
:polymorphic
=>
true
t
.
belongs_to
:user
,
:polymorphic
=>
true
t
.
string
:user_name
t
.
text
:changes
t
.
integer
:number
t
.
string
:tag
t
.
timestamps
end
end
end
CreateSchema
.
suppress_messages
do
CreateSchema
.
migrate
(
:up
)
end
class
User
<
ActiveRecord
::
Base
journaled
def
name
[
first_name
,
last_name
].
compact
.
join
(
' '
)
end
def
name
=
(
names
)
self
[
:first_name
],
self
[
:last_name
]
=
names
.
split
(
' '
,
2
)
end
end
class
MyCustomVersion
<
VestalVersions
::
Version
end
vendor/plugins/acts_as_journalized/test/tagging_test.rb
0 → 100644
View file @
b1845fcf
require
File
.
join
(
File
.
dirname
(
__FILE__
),
'test_helper'
)
class
TaggingTest
<
Test
::
Unit
::
TestCase
context
'Tagging a journal'
do
setup
do
@user
=
User
.
create
(
:name
=>
'Steve Richert'
)
@user
.
update_attribute
(
:last_name
,
'Jobs'
)
end
should
"update the journal record's tag column"
do
tag_name
=
'TAG'
last_journal
=
@user
.
journals
.
last
assert_not_equal
tag_name
,
last_journal
.
tag
@user
.
tag_journal
(
tag_name
)
assert_equal
tag_name
,
last_journal
.
reload
.
tag
end
should
'create a journal record for an initial journal'
do
@user
.
revert_to
(
1
)
assert_nil
@user
.
journals
.
at
(
1
)
@user
.
tag_journal
(
'TAG'
)
assert_not_nil
@user
.
journals
.
at
(
1
)
end
end
context
'A tagged journal'
do
setup
do
user
=
User
.
create
(
:name
=>
'Steve Richert'
)
user
.
update_attribute
(
:last_name
,
'Jobs'
)
user
.
tag_journal
(
'TAG'
)
@journal
=
user
.
journals
.
last
end
should
'return true for the "tagged?" method'
do
assert
@journal
.
respond_to?
(
:tagged?
)
assert_equal
true
,
@journal
.
tagged?
end
end
end
vendor/plugins/acts_as_journalized/test/test_helper.rb
0 → 100644
View file @
b1845fcf
$:
<<
File
.
join
(
File
.
dirname
(
__FILE__
),
'..'
,
'lib'
)
$:
<<
File
.
dirname
(
__FILE__
)
require
'rubygems'
require
'test/unit'
require
'active_record'
require
'shoulda'
require
'mocha'
require
'vestal_versions'
require
'schema'
begin
;
require
'redgreen'
;
rescue
LoadError
;
end
vendor/plugins/acts_as_journalized/test/users_test.rb
0 → 100644
View file @
b1845fcf
require
'test_helper'
class
UsersTest
<
Test
::
Unit
::
TestCase
context
'The user responsible for an update'
do
setup
do
@updated_by
=
User
.
create
(
:name
=>
'Steve Jobs'
)
@user
=
User
.
create
(
:name
=>
'Steve Richert'
)
end
should
'default to nil'
do
@user
.
update_attributes
(
:first_name
=>
'Stephen'
)
assert_nil
@user
.
journals
.
last
.
user
end
should
'accept and return an ActiveRecord user'
do
@user
.
update_attributes
(
:first_name
=>
'Stephen'
,
:updated_by
=>
@updated_by
)
assert_equal
@updated_by
,
@user
.
journals
.
last
.
user
end
should
'accept and return a string user name'
do
@user
.
update_attributes
(
:first_name
=>
'Stephen'
,
:updated_by
=>
@updated_by
.
name
)
assert_equal
@updated_by
.
name
,
@user
.
journals
.
last
.
user
end
end
end
vendor/plugins/acts_as_journalized/test/version_test.rb
0 → 100644
View file @
b1845fcf
require
File
.
join
(
File
.
dirname
(
__FILE__
),
'test_helper'
)
class
VersionTest
<
Test
::
Unit
::
TestCase
context
'Versions'
do
setup
do
@user
=
User
.
create
(
:name
=>
'Stephen Richert'
)
@user
.
update_attribute
(
:name
,
'Steve Jobs'
)
@user
.
update_attribute
(
:last_name
,
'Richert'
)
@first_journal
,
@last_journal
=
@user
.
journals
.
first
,
@user
.
journals
.
last
end
should
'be comparable to another journal based on journal number'
do
assert
@first_journal
==
@first_journal
assert
@last_journal
==
@last_journal
assert
@first_journal
!=
@last_journal
assert
@last_journal
!=
@first_journal
assert
@first_journal
<
@last_journal
assert
@last_journal
>
@first_journal
assert
@first_journal
<=
@last_journal
assert
@last_journal
>=
@first_journal
end
should
"not equal a separate model's journal with the same number"
do
user
=
User
.
create
(
:name
=>
'Stephen Richert'
)
user
.
update_attribute
(
:name
,
'Steve Jobs'
)
user
.
update_attribute
(
:last_name
,
'Richert'
)
first_journal
,
last_journal
=
user
.
journals
.
first
,
user
.
journals
.
last
assert_not_equal
@first_journal
,
first_journal
assert_not_equal
@last_journal
,
last_journal
end
should
'default to ordering by number when finding through association'
do
order
=
@user
.
journals
.
send
(
:scope
,
:find
)[
:order
]
assert_equal
'journals.number ASC'
,
order
end
should
'return true for the "initial?" method when the journal number is 1'
do
journal
=
@user
.
journals
.
build
(
:number
=>
1
)
assert_equal
1
,
journal
.
number
assert_equal
true
,
journal
.
initial?
end
end
end
vendor/plugins/acts_as_journalized/test/versioned_test.rb
0 → 100644
View file @
b1845fcf
require
File
.
join
(
File
.
dirname
(
__FILE__
),
'test_helper'
)
class
VersionedTest
<
Test
::
Unit
::
TestCase
context
'ActiveRecord models'
do
should
'respond to the "journaled?" method'
do
assert
ActiveRecord
::
Base
.
respond_to?
(
:journaled?
)
assert
User
.
respond_to?
(
:journaled?
)
end
should
'return true for the "journaled?" method if the model is journaled'
do
assert_equal
true
,
User
.
journaled?
end
should
'return false for the "journaled?" method if the model is not journaled'
do
assert_equal
false
,
ActiveRecord
::
Base
.
journaled?
end
end
end
vendor/plugins/acts_as_journalized/test/versions_test.rb
0 → 100644
View file @
b1845fcf
require
File
.
join
(
File
.
dirname
(
__FILE__
),
'test_helper'
)
class
VersionsTest
<
Test
::
Unit
::
TestCase
context
'A collection of associated journals'
do
setup
do
@user
,
@times
=
User
.
new
,
{}
names
=
[
'Steve Richert'
,
'Stephen Richert'
,
'Stephen Jobs'
,
'Steve Jobs'
]
time
=
names
.
size
.
hours
.
ago
names
.
each
do
|
name
|
@user
.
update_attribute
(
:name
,
name
)
@user
.
tag_journal
(
@user
.
journal
.
to_s
)
time
+=
1
.
hour
@user
.
journals
.
last
.
update_attribute
(
:created_at
,
time
)
@times
[
@user
.
journal
]
=
time
end
end
should
'be searchable between two valid journal values'
do
@times
.
keys
.
each
do
|
number
|
@times
.
values
.
each
do
|
time
|
assert_kind_of
Array
,
@user
.
journals
.
between
(
number
,
number
)
assert_kind_of
Array
,
@user
.
journals
.
between
(
number
,
time
)
assert_kind_of
Array
,
@user
.
journals
.
between
(
time
,
number
)
assert_kind_of
Array
,
@user
.
journals
.
between
(
time
,
time
)
assert
!
@user
.
journals
.
between
(
number
,
number
).
empty?
assert
!
@user
.
journals
.
between
(
number
,
time
).
empty?
assert
!
@user
.
journals
.
between
(
time
,
number
).
empty?
assert
!
@user
.
journals
.
between
(
time
,
time
).
empty?
end
end
end
should
'return an empty array when searching between a valid and an invalid journal value'
do
@times
.
each
do
|
number
,
time
|
assert_equal
[],
@user
.
journals
.
between
(
number
,
nil
)
assert_equal
[],
@user
.
journals
.
between
(
time
,
nil
)
assert_equal
[],
@user
.
journals
.
between
(
nil
,
number
)
assert_equal
[],
@user
.
journals
.
between
(
nil
,
time
)
end
end
should
'return an empty array when searching between two invalid journal values'
do
assert_equal
[],
@user
.
journals
.
between
(
nil
,
nil
)
end
should
'be searchable before a valid journal value'
do
@times
.
sort
.
each_with_index
do
|
(
number
,
time
),
i
|
assert_equal
i
,
@user
.
journals
.
before
(
number
).
size
assert_equal
i
,
@user
.
journals
.
before
(
time
).
size
end
end
should
'return an empty array when searching before an invalid journal value'
do
assert_equal
[],
@user
.
journals
.
before
(
nil
)
end
should
'be searchable after a valid journal value'
do
@times
.
sort
.
reverse
.
each_with_index
do
|
(
number
,
time
),
i
|
assert_equal
i
,
@user
.
journals
.
after
(
number
).
size
assert_equal
i
,
@user
.
journals
.
after
(
time
).
size
end
end
should
'return an empty array when searching after an invalid journal value'
do
assert_equal
[],
@user
.
journals
.
after
(
nil
)
end
should
'be fetchable by journal number'
do
@times
.
keys
.
each
do
|
number
|
assert_kind_of
VestalVersions
::
Version
,
@user
.
journals
.
at
(
number
)
assert_equal
number
,
@user
.
journals
.
at
(
number
).
number
end
end
should
'be fetchable by tag'
do
@times
.
keys
.
map
{
|
n
|
[
n
,
n
.
to_s
]
}.
each
do
|
number
,
tag
|
assert_kind_of
VestalVersions
::
Version
,
@user
.
journals
.
at
(
tag
)
assert_equal
number
,
@user
.
journals
.
at
(
tag
).
number
end
end
should
"be fetchable by the exact time of a journal's creation"
do
@times
.
each
do
|
number
,
time
|
assert_kind_of
VestalVersions
::
Version
,
@user
.
journals
.
at
(
time
)
assert_equal
number
,
@user
.
journals
.
at
(
time
).
number
end
end
should
"be fetchable by any time after the model's creation"
do
@times
.
each
do
|
number
,
time
|
assert_kind_of
VestalVersions
::
Version
,
@user
.
journals
.
at
(
time
+
30
.
minutes
)
assert_equal
number
,
@user
.
journals
.
at
(
time
+
30
.
minutes
).
number
end
end
should
"return nil when fetching a time before the model's creation"
do
creation
=
@times
.
values
.
min
assert_nil
@user
.
journals
.
at
(
creation
-
1
.
second
)
end
should
'be fetchable by an association extension method'
do
assert_kind_of
VestalVersions
::
Version
,
@user
.
journals
.
at
(
:first
)
assert_kind_of
VestalVersions
::
Version
,
@user
.
journals
.
at
(
:last
)
assert_equal
@times
.
keys
.
min
,
@user
.
journals
.
at
(
:first
).
number
assert_equal
@times
.
keys
.
max
,
@user
.
journals
.
at
(
:last
).
number
end
should
'be fetchable by a journal object'
do
@times
.
keys
.
each
do
|
number
|
journal
=
@user
.
journals
.
at
(
number
)
assert_kind_of
VestalVersions
::
Version
,
journal
assert_kind_of
VestalVersions
::
Version
,
@user
.
journals
.
at
(
journal
)
assert_equal
number
,
@user
.
journals
.
at
(
journal
).
number
end
end
should
'return nil when fetching an invalid journal value'
do
assert_nil
@user
.
journals
.
at
(
nil
)
end
should
'provide a journal number for any given numeric journal value'
do
@times
.
keys
.
each
do
|
number
|
assert_kind_of
Fixnum
,
@user
.
journals
.
number_at
(
number
)
assert_kind_of
Fixnum
,
@user
.
journals
.
number_at
(
number
+
0.5
)
assert_equal
@user
.
journals
.
number_at
(
number
),
@user
.
journals
.
number_at
(
number
+
0.5
)
end
end
should
'provide a journal number for a valid tag'
do
@times
.
keys
.
map
{
|
n
|
[
n
,
n
.
to_s
]
}.
each
do
|
number
,
tag
|
assert_kind_of
Fixnum
,
@user
.
journals
.
number_at
(
tag
)
assert_equal
number
,
@user
.
journals
.
number_at
(
tag
)
end
end
should
'return nil when providing a journal number for an invalid tag'
do
assert_nil
@user
.
journals
.
number_at
(
'INVALID'
)
end
should
'provide a journal number of a journal corresponding to an association extension method'
do
assert_kind_of
VestalVersions
::
Version
,
@user
.
journals
.
at
(
:first
)
assert_kind_of
VestalVersions
::
Version
,
@user
.
journals
.
at
(
:last
)
assert_equal
@times
.
keys
.
min
,
@user
.
journals
.
number_at
(
:first
)
assert_equal
@times
.
keys
.
max
,
@user
.
journals
.
number_at
(
:last
)
end
should
'return nil when providing a journal number for an invalid association extension method'
do
assert_nil
@user
.
journals
.
number_at
(
:INVALID
)
end
should
"provide a journal number for any time after the model's creation"
do
@times
.
each
do
|
number
,
time
|
assert_kind_of
Fixnum
,
@user
.
journals
.
number_at
(
time
+
30
.
minutes
)
assert_equal
number
,
@user
.
journals
.
number_at
(
time
+
30
.
minutes
)
end
end
should
"provide a journal number of 1 for a time before the model's creation"
do
creation
=
@times
.
values
.
min
assert_equal
1
,
@user
.
journals
.
number_at
(
creation
-
1
.
second
)
end
should
'provide a journal number for a given journal object'
do
@times
.
keys
.
each
do
|
number
|
journal
=
@user
.
journals
.
at
(
number
)
assert_kind_of
VestalVersions
::
Version
,
journal
assert_kind_of
Fixnum
,
@user
.
journals
.
number_at
(
journal
)
assert_equal
number
,
@user
.
journals
.
number_at
(
journal
)
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment