active_metadata 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/db/migrate/01_create_test_resources.rb +30 -0
- data/db/migrate/02_active_metadata_migrations.rb +71 -0
- data/db/test.sqlite3 +0 -0
- data/lib/active_metadata/base.rb +73 -16
- data/lib/active_metadata/helpers.rb +9 -0
- data/lib/active_metadata/persistence/active_record/history.rb +4 -4
- data/lib/active_metadata/version.rb +1 -1
- data/spec/concurrency_spec.rb +105 -0
- metadata +25 -38
- data/db/development.sqlite3 +0 -0
- data/db/migrate/001_create_document.rb +0 -12
- data/db/migrate/002_add_surname_to_document.rb +0 -9
- data/db/migrate/003_create_section.rb +0 -13
- data/db/migrate/004_create_user.rb +0 -14
- data/db/migrate/005_create_inboxes.rb +0 -19
- data/db/migrate/006_create_alert_message.rb +0 -37
- data/db/migrate/007_create_notes.rb +0 -22
- data/db/migrate/008_create_history.rb +0 -20
- data/db/migrate/009_create_watcher.rb +0 -21
- data/db/migrate/010_create_attachment.rb +0 -26
- data/db/migrate/011_add_created_by_to_histories.rb +0 -10
- data/lib/model/mongoid/active_meta.rb +0 -6
- data/lib/model/mongoid/attachment.rb +0 -25
- data/lib/model/mongoid/history.rb +0 -9
- data/lib/model/mongoid/label.rb +0 -14
- data/lib/model/mongoid/note.rb +0 -10
- data/lib/model/mongoid/watcher.rb +0 -24
@@ -0,0 +1,30 @@
|
|
1
|
+
class CreateTestResources < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :documents do |t|
|
4
|
+
t.string :name
|
5
|
+
t.string :surname
|
6
|
+
t.boolean :keep_alive
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
|
10
|
+
create_table :sections do |t|
|
11
|
+
t.string :title
|
12
|
+
t.integer :document_id
|
13
|
+
t.timestamps
|
14
|
+
end
|
15
|
+
|
16
|
+
create_table :users do |t|
|
17
|
+
t.string :email
|
18
|
+
t.string :firstname
|
19
|
+
t.string :lastname
|
20
|
+
t.timestamps
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.down
|
26
|
+
drop_table :documents
|
27
|
+
drop_table :sections
|
28
|
+
drop_table :users
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
class ActiveMetadataMigrations < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
|
4
|
+
create_table :notes do |t|
|
5
|
+
t.text :note
|
6
|
+
t.string :label
|
7
|
+
t.string :document_class
|
8
|
+
t.integer :document_id
|
9
|
+
t.integer :created_by
|
10
|
+
t.integer :updated_by
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
|
14
|
+
add_index :notes, :document_id
|
15
|
+
add_index :notes, :label
|
16
|
+
add_index :notes, :updated_at
|
17
|
+
|
18
|
+
create_table :histories do |t|
|
19
|
+
t.text :value
|
20
|
+
t.string :label
|
21
|
+
t.string :document_class
|
22
|
+
t.integer :document_id
|
23
|
+
t.integer :created_by
|
24
|
+
t.timestamps
|
25
|
+
end
|
26
|
+
|
27
|
+
add_index :histories, :document_id
|
28
|
+
add_index :histories, :label
|
29
|
+
add_index :histories, :created_at
|
30
|
+
|
31
|
+
create_table :attachments do |t|
|
32
|
+
t.string :label
|
33
|
+
t.integer :document_id
|
34
|
+
t.string :document_class
|
35
|
+
t.integer :created_by
|
36
|
+
t.integer :updated_by
|
37
|
+
t.integer :counter
|
38
|
+
t.string :attach_file_name
|
39
|
+
t.string :attach_content_type
|
40
|
+
t.integer :attach_file_size
|
41
|
+
t.datetime :attach_updated_at
|
42
|
+
t.timestamps
|
43
|
+
end
|
44
|
+
|
45
|
+
add_index :attachments, :document_id
|
46
|
+
add_index :attachments, :label
|
47
|
+
add_index :attachments, :attach_updated_at
|
48
|
+
|
49
|
+
create_table :watchers do |t|
|
50
|
+
t.integer :owner_id
|
51
|
+
t.string :label
|
52
|
+
t.string :document_class
|
53
|
+
t.integer :document_id
|
54
|
+
t.timestamps
|
55
|
+
end
|
56
|
+
|
57
|
+
add_index :watchers, :document_id
|
58
|
+
add_index :watchers, :label
|
59
|
+
add_index :watchers, :owner_id
|
60
|
+
add_index :watchers, :created_at
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.down
|
65
|
+
drop_table :notes
|
66
|
+
drop_table :histories
|
67
|
+
drop_table :attachments
|
68
|
+
drop_table :watchers
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
data/db/test.sqlite3
CHANGED
Binary file
|
data/lib/active_metadata/base.rb
CHANGED
@@ -2,12 +2,13 @@ module ActiveMetadata
|
|
2
2
|
|
3
3
|
CONFIG = File.exists?('config/active_metadata.yml') ? YAML.load_file('config/active_metadata.yml')[Rails.env] : {}
|
4
4
|
CONFIG['cache_expires_in'] ||= 60
|
5
|
-
|
5
|
+
|
6
6
|
## Define ModelMethods
|
7
7
|
module Base
|
8
|
-
|
8
|
+
|
9
9
|
require 'paperclip'
|
10
10
|
require "active_metadata/persistence/persistence"
|
11
|
+
require "active_metadata/helpers"
|
11
12
|
|
12
13
|
def self.included(klass)
|
13
14
|
klass.class_eval do
|
@@ -19,24 +20,26 @@ module ActiveMetadata
|
|
19
20
|
|
20
21
|
def acts_as_metadata *args
|
21
22
|
after_save :save_history
|
22
|
-
|
23
|
+
|
23
24
|
class_variable_set("@@metadata_id_from", args.empty? ? nil : args[0][:metadata_id_from])
|
24
25
|
|
25
26
|
include ActiveMetadata::Base::InstanceMethods
|
26
|
-
include ActiveMetadata::Persistence
|
27
|
-
|
27
|
+
include ActiveMetadata::Persistence
|
28
|
+
|
28
29
|
end
|
29
30
|
|
30
31
|
end
|
31
32
|
|
32
33
|
module InstanceMethods
|
33
|
-
|
34
|
+
|
35
|
+
include ActiveMetadata::Helpers
|
36
|
+
|
34
37
|
def self.included(klass)
|
35
|
-
[:notes
|
36
|
-
klass.send(:define_method,"#{item.to_s}_cache_key".to_sym) do |field|
|
37
|
-
"#{Rails.env}/active_metadata/#{item.to_s}/#{self.class}/#{metadata_id}/#{field}/"
|
38
|
-
end
|
39
|
-
end
|
38
|
+
[:notes, :attachments, :history].each do |item|
|
39
|
+
klass.send(:define_method, "#{item.to_s}_cache_key".to_sym) do |field|
|
40
|
+
"#{Rails.env}/active_metadata/#{item.to_s}/#{self.class}/#{metadata_id}/#{field}/"
|
41
|
+
end
|
42
|
+
end
|
40
43
|
end
|
41
44
|
|
42
45
|
def metadata_id
|
@@ -48,16 +51,70 @@ module ActiveMetadata
|
|
48
51
|
end
|
49
52
|
receiver.id
|
50
53
|
end
|
51
|
-
|
54
|
+
|
52
55
|
def current_user_id
|
53
56
|
if User.respond_to?(:current) && !User.current.nil?
|
54
|
-
|
57
|
+
User.current.id
|
55
58
|
else
|
56
59
|
nil
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Resolve concurrency using the passed timestamps and the active_metadata histories
|
64
|
+
# To be called from controller before updating the model. Params that contains a conflict are removed from the params list.
|
65
|
+
# Returns 2 values containing the the deleted params with the related history:
|
66
|
+
# [{:key => [passed_value,history]}]
|
67
|
+
#
|
68
|
+
# first result is the WARNINGS array: conflict appears on a field not touched by the user that submit the value
|
69
|
+
# first result is the FATALS Array : if the conflict appears on a field modified by the user that submit the value
|
70
|
+
# an empty array is returned by default
|
71
|
+
def manage_concurrency(params, timestamp)
|
72
|
+
warnings = []
|
73
|
+
fatals = []
|
74
|
+
|
75
|
+
# scan params
|
76
|
+
params.each do |key, val|
|
77
|
+
# ensure the query order
|
78
|
+
histories = history_for key.to_sym, "created_at DESC"
|
79
|
+
latest_history = histories.first
|
80
|
+
|
81
|
+
# if form timestamp is subsequent the history last change go on
|
82
|
+
# if history does not exists yet go on
|
83
|
+
next if latest_history.nil? || timestamp > latest_history.created_at
|
84
|
+
|
85
|
+
#if the timestamp is previous of the last history change
|
86
|
+
if timestamp < latest_history.created_at
|
87
|
+
#remove the key from the update process
|
88
|
+
params.delete key
|
89
|
+
|
90
|
+
# We have a conflict.
|
91
|
+
# Check if the actual submission has been modified
|
92
|
+
histories.each do |h|
|
93
|
+
# Looking for the value that was loaded by the user. First history with a ts that is younger than the form ts
|
94
|
+
next if timestamp > h.created_at
|
95
|
+
|
96
|
+
# History stores values as strings so any boolean is stored as "0" or "1"
|
97
|
+
# We need to translate the params passed for a safer comparison.
|
98
|
+
if self.column_for_attribute(key).type == :boolean
|
99
|
+
b_val = to_bool(h.value)
|
100
|
+
end
|
101
|
+
|
102
|
+
if [h.value, b_val].include? val
|
103
|
+
warnings << {key => [val, h]}
|
104
|
+
else
|
105
|
+
fatals << {key => [val, h]}
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
return warnings, fatals
|
114
|
+
end
|
115
|
+
|
60
116
|
end # InstanceMethods
|
117
|
+
|
61
118
|
end
|
62
119
|
|
63
120
|
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module ActiveMetadata::Helpers
|
2
|
+
|
3
|
+
def to_bool str
|
4
|
+
return true if str == true || str =~ (/(true|t|yes|y|1)$/i)
|
5
|
+
return false if str == false || str.blank? || str =~ (/(false|f|no|n|0)$/i)
|
6
|
+
raise ArgumentError.new("invalid value for Boolean: \"#{str}\"")
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
@@ -15,9 +15,9 @@ module ActiveMetadata::Persistence::ActiveRecord::History
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
def history_for field
|
18
|
+
def history_for field, order="created_at DESC"
|
19
19
|
Rails.cache.fetch(history_cache_key(field), :expires_in => ActiveMetadata::CONFIG['cache_expires_in'].minutes) do
|
20
|
-
fetch_histories_for field
|
20
|
+
fetch_histories_for field, order
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -27,8 +27,8 @@ module ActiveMetadata::Persistence::ActiveRecord::History
|
|
27
27
|
Rails.cache.delete history_cache_key(field)
|
28
28
|
end
|
29
29
|
|
30
|
-
def fetch_histories_for field
|
31
|
-
History.all(:conditions => {:document_id => metadata_id,:label => field}, :order =>
|
30
|
+
def fetch_histories_for field, order
|
31
|
+
History.all(:conditions => {:document_id => metadata_id,:label => field}, :order => order)
|
32
32
|
end
|
33
33
|
|
34
34
|
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Manage Concurrency" do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@document = Document.create! { |d| d.name = "John" }
|
7
|
+
@document.reload
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "when a field is modified and the form ts is subsequent of the history ts" do
|
11
|
+
|
12
|
+
it "should save the new value and history must be updated with the latest change" do
|
13
|
+
sleep 0.2.seconds
|
14
|
+
|
15
|
+
params = {:name => "nuovo nome"}
|
16
|
+
warn,fatal = @document.manage_concurrency params,Time.now
|
17
|
+
@document.update_attributes(params)
|
18
|
+
|
19
|
+
warn.should be_empty
|
20
|
+
fatal.should be_empty
|
21
|
+
hs = @document.history_for(:name)
|
22
|
+
hs.count.should eq 2
|
23
|
+
hs.first.value.should eq "nuovo nome"
|
24
|
+
Document.last.name.should eq "nuovo nome"
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "when a field is modified and the form ts is preceding the history ts" do
|
30
|
+
|
31
|
+
it "should not change the model value and the history if the newest history value is equal to the submitted once, param should be retuned as warning" do
|
32
|
+
form_timestamp = Time.now
|
33
|
+
params = {:name => "nuovo nome"}
|
34
|
+
|
35
|
+
#someone change the field value
|
36
|
+
sleep 0.2.seconds
|
37
|
+
warn,fatal = @document.manage_concurrency params,Time.now
|
38
|
+
@document.update_attributes(params)
|
39
|
+
|
40
|
+
# user submit pushing the same value that was already saved by another user
|
41
|
+
sleep 0.2.seconds
|
42
|
+
warn,fatal = @document.manage_concurrency params,form_timestamp
|
43
|
+
@document.update_attributes(params)
|
44
|
+
|
45
|
+
warn.size.should eq 1
|
46
|
+
warn[0][:name][0].should eq "nuovo nome"
|
47
|
+
fatal.should be_empty
|
48
|
+
hs = @document.history_for(:name)
|
49
|
+
#last change shoudl not be recorded in history
|
50
|
+
hs.count.should eq 2
|
51
|
+
hs.first.value.should eq "nuovo nome"
|
52
|
+
Document.last.name.should eq "nuovo nome"
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should reject the change if the history newest value is different from the submitted once, param should be returned as fatal" do
|
57
|
+
form_timestamp = Time.now
|
58
|
+
params = {:name => "nuovo nome"}
|
59
|
+
|
60
|
+
#someone change the field value
|
61
|
+
sleep 0.2.seconds
|
62
|
+
warn,fatal = @document.manage_concurrency params,Time.now
|
63
|
+
@document.update_attributes(params)
|
64
|
+
|
65
|
+
# user submit a new value
|
66
|
+
sleep 0.2.seconds
|
67
|
+
different_params = {:name => "altro nome"}
|
68
|
+
warn,fatal = @document.manage_concurrency different_params,form_timestamp
|
69
|
+
@document.update_attributes(different_params)
|
70
|
+
|
71
|
+
fatal.size.should eq 1
|
72
|
+
fatal[0][:name][0].should eq "altro nome"
|
73
|
+
warn.should be_empty
|
74
|
+
hs = @document.history_for(:name)
|
75
|
+
#last change shoudl not be recorded in history
|
76
|
+
hs.count.should eq 2
|
77
|
+
hs.first.value.should eq "nuovo nome"
|
78
|
+
Document.last.name.should eq "nuovo nome"
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should return both fatals and warnings if required" do
|
83
|
+
form_timestamp = Time.now
|
84
|
+
params = {:name => "nuovo nome", :keep_alive => false}
|
85
|
+
|
86
|
+
#someone change the field value
|
87
|
+
sleep 0.2.seconds
|
88
|
+
warn,fatal = @document.manage_concurrency params,Time.now
|
89
|
+
@document.update_attributes(params)
|
90
|
+
|
91
|
+
# user submit a new value
|
92
|
+
sleep 0.2.seconds
|
93
|
+
different_params = {:name => "altro nome", :keep_alive => false}
|
94
|
+
warn,fatal = @document.manage_concurrency different_params,form_timestamp
|
95
|
+
@document.update_attributes(different_params)
|
96
|
+
|
97
|
+
fatal.size.should eq 1
|
98
|
+
fatal[0][:name][0].should eq "altro nome"
|
99
|
+
warn.size.should eq 1
|
100
|
+
warn[0][:keep_alive][0].should eq false
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_metadata
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2011-10-
|
13
|
+
date: 2011-10-19 00:00:00.000000000Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec-rails
|
17
|
-
requirement: &
|
17
|
+
requirement: &2168675080 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :development
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *2168675080
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: sqlite3
|
28
|
-
requirement: &
|
28
|
+
requirement: &2168674400 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *2168674400
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: sqlite3-ruby
|
39
|
-
requirement: &
|
39
|
+
requirement: &2168673660 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :development
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *2168673660
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: cucumber
|
50
|
-
requirement: &
|
50
|
+
requirement: &2168672720 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,10 +55,10 @@ dependencies:
|
|
55
55
|
version: '0'
|
56
56
|
type: :development
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *2168672720
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: ci_reporter
|
61
|
-
requirement: &
|
61
|
+
requirement: &2168672140 !ruby/object:Gem::Requirement
|
62
62
|
none: false
|
63
63
|
requirements:
|
64
64
|
- - ! '>='
|
@@ -66,10 +66,10 @@ dependencies:
|
|
66
66
|
version: '0'
|
67
67
|
type: :development
|
68
68
|
prerelease: false
|
69
|
-
version_requirements: *
|
69
|
+
version_requirements: *2168672140
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: rails
|
72
|
-
requirement: &
|
72
|
+
requirement: &2168671320 !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
75
|
- - =
|
@@ -77,10 +77,10 @@ dependencies:
|
|
77
77
|
version: 3.0.1
|
78
78
|
type: :runtime
|
79
79
|
prerelease: false
|
80
|
-
version_requirements: *
|
80
|
+
version_requirements: *2168671320
|
81
81
|
- !ruby/object:Gem::Dependency
|
82
82
|
name: activerecord
|
83
|
-
requirement: &
|
83
|
+
requirement: &2168670740 !ruby/object:Gem::Requirement
|
84
84
|
none: false
|
85
85
|
requirements:
|
86
86
|
- - =
|
@@ -88,10 +88,10 @@ dependencies:
|
|
88
88
|
version: 3.0.1
|
89
89
|
type: :runtime
|
90
90
|
prerelease: false
|
91
|
-
version_requirements: *
|
91
|
+
version_requirements: *2168670740
|
92
92
|
- !ruby/object:Gem::Dependency
|
93
93
|
name: paperclip
|
94
|
-
requirement: &
|
94
|
+
requirement: &2168670280 !ruby/object:Gem::Requirement
|
95
95
|
none: false
|
96
96
|
requirements:
|
97
97
|
- - ! '>='
|
@@ -99,10 +99,10 @@ dependencies:
|
|
99
99
|
version: '0'
|
100
100
|
type: :runtime
|
101
101
|
prerelease: false
|
102
|
-
version_requirements: *
|
102
|
+
version_requirements: *2168670280
|
103
103
|
- !ruby/object:Gem::Dependency
|
104
104
|
name: to_xls
|
105
|
-
requirement: &
|
105
|
+
requirement: &2168669560 !ruby/object:Gem::Requirement
|
106
106
|
none: false
|
107
107
|
requirements:
|
108
108
|
- - ! '>='
|
@@ -110,7 +110,7 @@ dependencies:
|
|
110
110
|
version: '0'
|
111
111
|
type: :runtime
|
112
112
|
prerelease: false
|
113
|
-
version_requirements: *
|
113
|
+
version_requirements: *2168669560
|
114
114
|
description: First implementation will write metadata on mongodb
|
115
115
|
email:
|
116
116
|
- acampolonghi@gmail.com
|
@@ -120,6 +120,7 @@ extensions: []
|
|
120
120
|
extra_rdoc_files: []
|
121
121
|
files:
|
122
122
|
- lib/active_metadata/base.rb
|
123
|
+
- lib/active_metadata/helpers.rb
|
123
124
|
- lib/active_metadata/persistence/active_record/attachment.rb
|
124
125
|
- lib/active_metadata/persistence/active_record/history.rb
|
125
126
|
- lib/active_metadata/persistence/active_record/note.rb
|
@@ -136,12 +137,6 @@ files:
|
|
136
137
|
- lib/model/active_record/history.rb
|
137
138
|
- lib/model/active_record/note.rb
|
138
139
|
- lib/model/active_record/watcher.rb
|
139
|
-
- lib/model/mongoid/active_meta.rb
|
140
|
-
- lib/model/mongoid/attachment.rb
|
141
|
-
- lib/model/mongoid/history.rb
|
142
|
-
- lib/model/mongoid/label.rb
|
143
|
-
- lib/model/mongoid/note.rb
|
144
|
-
- lib/model/mongoid/watcher.rb
|
145
140
|
- lib/rails/railties/tasks.rake
|
146
141
|
- lib/rake/active_record_tasks.rb
|
147
142
|
- lib/rake/task.rb
|
@@ -169,18 +164,8 @@ files:
|
|
169
164
|
- config/initializers/inflections.rb
|
170
165
|
- config/mongoid.yml
|
171
166
|
- config/routes.rb
|
172
|
-
- db/
|
173
|
-
- db/migrate/
|
174
|
-
- db/migrate/002_add_surname_to_document.rb
|
175
|
-
- db/migrate/003_create_section.rb
|
176
|
-
- db/migrate/004_create_user.rb
|
177
|
-
- db/migrate/005_create_inboxes.rb
|
178
|
-
- db/migrate/006_create_alert_message.rb
|
179
|
-
- db/migrate/007_create_notes.rb
|
180
|
-
- db/migrate/008_create_history.rb
|
181
|
-
- db/migrate/009_create_watcher.rb
|
182
|
-
- db/migrate/010_create_attachment.rb
|
183
|
-
- db/migrate/011_add_created_by_to_histories.rb
|
167
|
+
- db/migrate/01_create_test_resources.rb
|
168
|
+
- db/migrate/02_active_metadata_migrations.rb
|
184
169
|
- db/test.sqlite3
|
185
170
|
- features/step_definitions/add_a_user_to_a_watcher_steps.rb
|
186
171
|
- features/step_definitions/trigger_alert_on_modify_steps.rb
|
@@ -191,6 +176,7 @@ files:
|
|
191
176
|
- features/watchlist/trigger_alert_on_modify.feature
|
192
177
|
- spec/active_metadata_spec.rb
|
193
178
|
- spec/benchmark_spec.rb
|
179
|
+
- spec/concurrency_spec.rb
|
194
180
|
- spec/controllers/metadata_controller_spec.rb
|
195
181
|
- spec/spec_helper.rb
|
196
182
|
- spec/support/document.rb
|
@@ -233,6 +219,7 @@ test_files:
|
|
233
219
|
- features/watchlist/trigger_alert_on_modify.feature
|
234
220
|
- spec/active_metadata_spec.rb
|
235
221
|
- spec/benchmark_spec.rb
|
222
|
+
- spec/concurrency_spec.rb
|
236
223
|
- spec/controllers/metadata_controller_spec.rb
|
237
224
|
- spec/spec_helper.rb
|
238
225
|
- spec/support/document.rb
|
data/db/development.sqlite3
DELETED
Binary file
|
@@ -1,19 +0,0 @@
|
|
1
|
-
class CreateInboxes < ActiveRecord::Migration
|
2
|
-
def self.up
|
3
|
-
create_table :inboxes do |t|
|
4
|
-
t.string :label
|
5
|
-
t.string :object_class
|
6
|
-
t.integer :object_id
|
7
|
-
t.string :alert_type
|
8
|
-
t.string :old_value
|
9
|
-
t.string :new_value
|
10
|
-
t.text :content
|
11
|
-
t.integer :user_id
|
12
|
-
t.timestamps
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.down
|
17
|
-
drop_table :inboxes
|
18
|
-
end
|
19
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
class CreateAlertMessage < ActiveRecord::Migration
|
2
|
-
def self.up
|
3
|
-
drop_table :inboxes
|
4
|
-
|
5
|
-
create_table :inboxes do |t|
|
6
|
-
t.integer :user_id
|
7
|
-
end
|
8
|
-
|
9
|
-
create_table :alert_messages do |t|
|
10
|
-
t.string :label
|
11
|
-
t.string :model_class
|
12
|
-
t.integer :model_id
|
13
|
-
t.string :alert_type
|
14
|
-
t.text :old_value
|
15
|
-
t.text :new_value
|
16
|
-
t.integer :inbox_id
|
17
|
-
t.boolean :read
|
18
|
-
|
19
|
-
t.timestamps
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.down
|
24
|
-
drop_table :alert_messages
|
25
|
-
create_table :inboxes do |t|
|
26
|
-
t.string :label
|
27
|
-
t.string :object_class
|
28
|
-
t.integer :object_id
|
29
|
-
t.string :alert_type
|
30
|
-
t.string :old_value
|
31
|
-
t.string :new_value
|
32
|
-
t.text :content
|
33
|
-
t.integer :user_id
|
34
|
-
t.timestamps
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
class CreateNotes < ActiveRecord::Migration
|
2
|
-
def self.up
|
3
|
-
create_table :notes do |t|
|
4
|
-
t.text :note
|
5
|
-
t.string :label
|
6
|
-
t.integer :document_id
|
7
|
-
t.integer :created_by
|
8
|
-
t.integer :updated_by
|
9
|
-
t.timestamps
|
10
|
-
end
|
11
|
-
|
12
|
-
add_index :notes, :document_id
|
13
|
-
add_index :notes, :label
|
14
|
-
add_index :notes, :updated_at
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.down
|
19
|
-
drop_table :notes
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
class CreateHistory < ActiveRecord::Migration
|
2
|
-
def self.up
|
3
|
-
create_table :histories do |t|
|
4
|
-
t.text :value
|
5
|
-
t.string :label
|
6
|
-
t.integer :document_id
|
7
|
-
t.timestamps
|
8
|
-
end
|
9
|
-
|
10
|
-
add_index :histories, :document_id
|
11
|
-
add_index :histories, :label
|
12
|
-
add_index :histories, :created_at
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.down
|
17
|
-
drop_table :histories
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
class CreateWatcher < ActiveRecord::Migration
|
2
|
-
def self.up
|
3
|
-
create_table :watchers do |t|
|
4
|
-
t.integer :owner_id
|
5
|
-
t.string :label
|
6
|
-
t.integer :document_id
|
7
|
-
t.timestamps
|
8
|
-
end
|
9
|
-
|
10
|
-
add_index :watchers, :document_id
|
11
|
-
add_index :watchers, :label
|
12
|
-
add_index :watchers, :owner_id
|
13
|
-
add_index :watchers, :created_at
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.down
|
18
|
-
drop_table :watchers
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
class CreateAttachment < ActiveRecord::Migration
|
2
|
-
def self.up
|
3
|
-
create_table :attachments do |t|
|
4
|
-
t.string :label
|
5
|
-
t.integer :document_id
|
6
|
-
t.integer :created_by
|
7
|
-
t.integer :updated_by
|
8
|
-
t.integer :counter
|
9
|
-
t.string :attach_file_name
|
10
|
-
t.string :attach_content_type
|
11
|
-
t.integer :attach_file_size
|
12
|
-
t.datetime :attach_updated_at
|
13
|
-
t.timestamps
|
14
|
-
end
|
15
|
-
|
16
|
-
add_index :attachments, :document_id
|
17
|
-
add_index :attachments, :label
|
18
|
-
add_index :attachments, :attach_updated_at
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.down
|
23
|
-
drop_table :attachments
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
class Attachment
|
2
|
-
include Mongoid::Document
|
3
|
-
include Mongoid::Paperclip
|
4
|
-
|
5
|
-
belongs_to :label
|
6
|
-
has_mongoid_attached_file :attach,
|
7
|
-
:path => "#{ActiveMetadata::CONFIG['attachment_base_path']}/:document_id/:label/:counter/:basename.:extension",
|
8
|
-
:url => "#{ActiveMetadata::CONFIG['attachment_base_url']}/:document_id/:label/:counter/:basename.:extension"
|
9
|
-
|
10
|
-
field :created_by, :type => Integer
|
11
|
-
field :counter, :type => Integer
|
12
|
-
|
13
|
-
Paperclip.interpolates :document_id do |attachment,style|
|
14
|
-
attachment.instance.label.active_meta.document_id
|
15
|
-
end
|
16
|
-
|
17
|
-
Paperclip.interpolates :label do |attachment,style|
|
18
|
-
attachment.instance.label.name
|
19
|
-
end
|
20
|
-
|
21
|
-
Paperclip.interpolates :counter do |attachment,style|
|
22
|
-
attachment.instance.counter
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
data/lib/model/mongoid/label.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
class Label
|
2
|
-
include Mongoid::Document
|
3
|
-
field :name
|
4
|
-
|
5
|
-
belongs_to :active_meta, :class_name => "ActiveMeta"
|
6
|
-
|
7
|
-
has_many :notes, :class_name => "Note"
|
8
|
-
has_many :histories, :class_name => "History"
|
9
|
-
has_many :attachments, :class_name => "Attachment"
|
10
|
-
has_many :watchers, :class_name => "Watcher"
|
11
|
-
|
12
|
-
index :name
|
13
|
-
|
14
|
-
end
|
data/lib/model/mongoid/note.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
class Watcher
|
2
|
-
include Mongoid::Document
|
3
|
-
|
4
|
-
belongs_to :label
|
5
|
-
|
6
|
-
field :owner_id, :type => Integer
|
7
|
-
|
8
|
-
def notify_changes(matched_label, old_value, new_value, model_class, model_id)
|
9
|
-
create_inbox_alert(User.find(owner_id).inbox, matched_label, old_value, new_value, model_class, model_id)
|
10
|
-
end
|
11
|
-
|
12
|
-
def create_inbox_alert(inbox, label, old_value, new_value, model_class, model_id)
|
13
|
-
Message.create! do |message|
|
14
|
-
message.label = label
|
15
|
-
message.model_class = model_class.to_s
|
16
|
-
message.model_id = model_id
|
17
|
-
message.alert_type = :model_value_changed
|
18
|
-
message.old_value = old_value
|
19
|
-
message.new_value = new_value
|
20
|
-
message.inbox_id = inbox.id
|
21
|
-
message.read = false
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|