summaryrefslogtreecommitdiff
path: root/app/models/node.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/node.rb')
-rw-r--r--app/models/node.rb110
1 files changed, 75 insertions, 35 deletions
diff --git a/app/models/node.rb b/app/models/node.rb
index 6c11fed..92ecc12 100644
--- a/app/models/node.rb
+++ b/app/models/node.rb
@@ -1,14 +1,14 @@
1class Node < ActiveRecord::Base 1class Node < ApplicationRecord
2 # Mixins and Plugins 2 # Mixins and Plugins
3 acts_as_nested_set 3 acts_as_nested_set
4 4
5 # Associations 5 # Associations
6 has_many :pages, :order => "revision ASC" 6 has_many :pages, -> { order("revision ASC") }, :dependent => :destroy
7 belongs_to :head, :class_name => "Page", :foreign_key => :head_id 7 belongs_to :head, :class_name => "Page", :foreign_key => :head_id, :dependent => :destroy, optional: true
8 belongs_to :draft, :class_name => "Page", :foreign_key => :draft_id 8 belongs_to :draft, :class_name => "Page", :foreign_key => :draft_id, :dependent => :destroy, optional: true
9 has_many :permissions 9 has_many :permissions, :dependent => :destroy
10 has_one :event 10 has_one :event, :dependent => :destroy
11 belongs_to :lock_owner, :class_name => "User", :foreign_key => :locking_user_id 11 belongs_to :lock_owner, :class_name => "User", :foreign_key => :locking_user_id, optional: true
12 12
13 # Callbacks 13 # Callbacks
14 after_create :initialize_empty_page 14 after_create :initialize_empty_page
@@ -16,20 +16,20 @@ class Node < ActiveRecord::Base
16 after_save :update_unique_names_of_children 16 after_save :update_unique_names_of_children
17 17
18 # Validations 18 # Validations
19 validates_length_of :slug, :within => 1..255, :unless => "parent_id.nil?" 19 validates_length_of :slug, :within => 1..255, :unless => -> { parent_id.nil? }
20 validates_presence_of :slug, :unless => "parent_id.nil?" 20 validates_presence_of :slug, :unless => -> { parent_id.nil? }
21 validates_uniqueness_of :slug, :scope => :parent_id, :unless => "parent_id.nil?" 21 validates_uniqueness_of :slug, :scope => :parent_id, :unless => -> { parent_id.nil? }
22 validates_presence_of :parent_id, :unless => "Node.root.nil?" 22 validates_presence_of :parent_id, :unless => -> { Node.root.nil? }
23 23
24 validate :borders # This should never ever happen. 24 validate :borders # This should never ever happen.
25 25
26 # Index for Fulltext Search 26 # Index for Fulltext Search
27 define_index do 27 # define_index do
28 indexes head.translations.title 28 # indexes head.translations.title
29 indexes slug 29 # indexes slug
30 indexes unique_name 30 # indexes unique_name
31 indexes head.translations.body 31 # indexes head.translations.body
32 end 32 # end
33 33
34 # Class methods 34 # Class methods
35 35
@@ -39,8 +39,8 @@ class Node < ActiveRecord::Base
39 # revision with -1. It raises an Argument error if the revision is not a 39 # revision with -1. It raises an Argument error if the revision is not a
40 # Fixnum 40 # Fixnum
41 def self.find_page path, revision = -1 41 def self.find_page path, revision = -1
42 unless revision.class == Fixnum 42 unless revision.is_a?(Integer)
43 raise ArgumentError, "revision must be a Fixnum" 43 raise ArgumentError, "revision must be a Integer"
44 end 44 end
45 45
46 node = Node.find_by_unique_name(path) 46 node = Node.find_by_unique_name(path)
@@ -60,6 +60,7 @@ class Node < ActiveRecord::Base
60 # Instance Methods 60 # Instance Methods
61 61
62 def find_or_create_draft current_user 62 def find_or_create_draft current_user
63 self.wipe_draft!
63 if draft && self.lock_owner == current_user 64 if draft && self.lock_owner == current_user
64 draft 65 draft
65 elsif draft && self.lock_owner.nil? 66 elsif draft && self.lock_owner.nil?
@@ -72,7 +73,7 @@ class Node < ActiveRecord::Base
72 raise( 73 raise(
73 LockedByAnotherUser, 74 LockedByAnotherUser,
74 "Page is locked by another user who is working on it! " \ 75 "Page is locked by another user who is working on it! " \
75 "Last modification: #{draft.updated_at.to_s(:db)}" 76 "Last modification: #{draft.updated_at.to_fs(:db)}"
76 ) 77 )
77 else 78 else
78 lock_for! current_user 79 lock_for! current_user
@@ -94,25 +95,55 @@ class Node < ActiveRecord::Base
94 end 95 end
95 96
96 def publish_draft! 97 def publish_draft!
98 # Return nil if nothing to publish and no staged changes
99 return nil unless self.draft || staged_slug || staged_parent_id
100
97 if self.draft 101 if self.draft
98 self.head = self.draft 102 self.head = self.draft
99 self.head.published_at ||= Time.now 103 self.head.published_at ||= Time.now
100 self.head.save! 104 self.head.save!
101
102 self.draft = nil 105 self.draft = nil
106 end
103 107
104 if staged_slug && (staged_slug != slug) 108 if staged_slug && (staged_slug != slug)
105 self.slug = staged_slug 109 self.slug = staged_slug
106 end 110 self.staged_slug = nil
111 end
107 112
108 if staged_parent_id && (staged_parent_id != parent_id) 113 if staged_parent_id && (staged_parent_id != parent_id)
109 self.parent_id = staged_parent_id 114 new_parent = Node.find(staged_parent_id)
115 self.staged_parent_id = nil
116 self.save!
117 self.move_to_child_of(new_parent)
118 else
119 unless self.save
120 raise ActiveRecord::RecordInvalid.new(self)
110 end 121 end
122 end
111 123
112 self.save! 124 self.reload
125 self.update_unique_name
126 self.send(:update_unique_names_of_children)
127 self.unlock!
128 self
129 end
130
131 # removes a draft and the lock if it is older than a day and still
132 # identical to head
133 def wipe_draft!
134 unless self.draft
113 self.unlock! 135 self.unlock!
114 self 136 return
115 end 137 end
138 return unless self.head
139 return unless self.draft.updated_at < 1.day.ago
140 return if self.head.has_changes_to? self.draft
141
142 self.draft.destroy
143 self.draft_id = nil
144 self.unlock!
145 self.save!
146 self.reload
116 end 147 end
117 148
118 def restore_revision! revision 149 def restore_revision! revision
@@ -126,7 +157,7 @@ class Node < ActiveRecord::Base
126 157
127 # returns an array with all parts of a unique_name rather than a string 158 # returns an array with all parts of a unique_name rather than a string
128 def unique_path 159 def unique_path
129 unique_name.split("/") rescue [unique_name] 160 unique_name.to_s.split("/")
130 end 161 end
131 162
132 # returns array with pages up to root excluding root 163 # returns array with pages up to root excluding root
@@ -180,6 +211,15 @@ class Node < ActiveRecord::Base
180 self.created_at < new_id_format_date ? unique_path : id 211 self.created_at < new_id_format_date ? unique_path : id
181 end 212 end
182 213
214 # Full-text search across all locale translations using PostgreSQL tsvector.
215 # Uses 'simple' dictionary (no stemming, no stopwords) so queries work
216 # across German and English content without language detection.
217 def self.search(term, _ = {})
218 joins(head: :translations)
219 .where("page_translations.search_vector @@ plainto_tsquery('simple', ?)", term)
220 .distinct
221 end
222
183 protected 223 protected
184 def lock_for! current_user 224 def lock_for! current_user
185 self.lock_owner = current_user 225 self.lock_owner = current_user
@@ -208,8 +248,12 @@ class Node < ActiveRecord::Base
208 # Hopefully until no childrens occur 248 # Hopefully until no childrens occur
209 def update_unique_names_of_children 249 def update_unique_names_of_children
210 unless root? 250 unless root?
211 self.descendants.each do |descendant| 251 # Use parent_id-based traversal instead of lft/rgt descendants
212 descendant.update_unique_name 252 # due to awesome_nested_set not refreshing parent lft/rgt in memory
253 Node.where(:parent_id => self.id).each do |child|
254 child.reload
255 child.update_unique_name
256 child.send(:update_unique_names_of_children)
213 end 257 end
214 end 258 end
215 end 259 end
@@ -220,7 +264,3 @@ class Node < ActiveRecord::Base
220 end 264 end
221 end 265 end
222end 266end
223
224class LockedByAnotherUser < StandardError; end
225
226