1+ # frozen_string_literal: true
12class ApplicationController < ActionController ::Base
23 protect_from_forgery
34
45 before_action :set_universe_session
56 before_action :set_universe_scope
67
78 before_action :cache_most_used_page_information
8- before_action :cache_forums_unread_counts
99
1010 before_action :set_metadata
1111
@@ -27,7 +27,7 @@ def set_universe_session
2727 session . delete ( :universe_id )
2828 elsif params [ :universe ] . is_a? ( String ) && params [ :universe ] . to_i . to_s == params [ :universe ]
2929 found_universe = Universe . find_by ( id : params [ :universe ] )
30- found_universe = nil unless current_user . universes . include? ( found_universe ) || current_user . contributable_universes . include? ( found_universe )
30+ found_universe = nil unless found_universe . user_id == current_user . id || found_universe . contributors . pluck ( :user_id ) . include? ( current_user . id )
3131 session [ :universe_id ] = found_universe . id if found_universe
3232 end
3333 end
@@ -36,52 +36,116 @@ def set_universe_session
3636 def set_universe_scope
3737 if user_signed_in? && session . key? ( :universe_id )
3838 @universe_scope = Universe . find_by ( id : session [ :universe_id ] )
39- @universe_scope = nil unless current_user . universes . include? ( @universe_scope ) || current_user . contributable_universes . include? ( @universe_scope )
39+
40+ if @universe_scope && @universe_scope . user_id != current_user . try ( :id )
41+ # Verify the current user has access to this universe by looking up their
42+ # universe contributorship
43+ contributorship = Contributor . find_by (
44+ user : current_user ,
45+ universe : @universe_scope
46+ )
47+
48+ if contributorship . nil?
49+ # If the user doesn't have current contributor access to this universe,
50+ # then revert back to unscoped universe actions
51+ @universe_scope = nil
52+ end
53+ end
54+
4055 else
4156 @universe_scope = nil
4257 end
4358 end
4459
45- # Cache some super-common stuff we need for every page. For example, content lists for the side nav.
60+ # Cache some super-common stuff we need for every page. For example, content lists for the side nav. This is a catch-all for most pages that render
61+ # UI, but methods are also free to skip this filter and call the individual cache methods they need instead.
4662 def cache_most_used_page_information
63+ return unless user_signed_in?
64+
65+ cache_activated_content_types
66+ cache_current_user_content
67+ cache_notifications
68+ cache_recently_edited_pages
69+ cache_forums_unread_counts
70+ end
71+
72+ def cache_activated_content_types
73+ @activated_content_types ||= if user_signed_in?
74+ (
75+ # Use config to dictate order, but AND to only include what a user has turned on
76+ Rails . application . config . content_type_names [ :all ] & current_user . user_content_type_activators . pluck ( :content_type )
77+ )
78+ else
79+ [ ]
80+ end
81+ end
82+
83+ def cache_current_user_content
84+ return if @current_user_content
85+
4786 @current_user_content = { }
4887 return unless user_signed_in?
4988
50- @activated_content_types = (
51- Rails . application . config . content_types [ :all ] . map ( &:name ) & # Use config to dictate order, but AND to only include what a user has turned on
52- current_user . user_content_type_activators . pluck ( :content_type )
53- )
89+ cache_activated_content_types
5490
5591 # We always want to cache Universes, even if they aren't explicitly turned on.
56- @current_user_content = current_user . content ( content_types : @activated_content_types + [ 'Universe' ] , universe_id : @universe_scope . try ( :id ) )
92+ @current_user_content = current_user . content (
93+ content_types : @activated_content_types + [ Universe . name ] ,
94+ universe_id : @universe_scope . try ( :id )
95+ )
5796
5897 # Likewise, we should also always cache Timelines & Documents
5998 if @universe_scope
6099 @current_user_content [ 'Timeline' ] = current_user . timelines . where ( universe_id : @universe_scope . try ( :id ) ) . to_a
61- @current_user_content [ 'Document' ] = current_user . linkable_documents . includes ( [ :user ] ) . where ( universe_id : @universe_scope . try ( :id ) ) . order ( 'updated_at DESC' ) . to_a
100+ @current_user_content [ 'Document' ] = current_user . documents . where ( universe_id : @universe_scope . try ( :id ) ) . order ( 'updated_at DESC' ) . to_a
62101 else
63102 @current_user_content [ 'Timeline' ] = current_user . timelines . to_a
64- @current_user_content [ 'Document' ] = current_user . linkable_documents . includes ( [ :user ] ) . order ( 'updated_at DESC' ) . to_a
103+ @current_user_content [ 'Document' ] = current_user . documents . order ( 'updated_at DESC' ) . to_a
104+ end
105+ end
106+
107+ def cache_notifications
108+ @user_notifications ||= if user_signed_in?
109+ current_user . notifications . order ( 'happened_at DESC' ) . limit ( 100 )
110+ else
111+ [ ]
65112 end
113+ end
66114
67- # Fetch notifications
68- @user_notifications = current_user . notifications . order ( 'happened_at DESC' ) . limit ( 100 )
115+ def cache_recently_created_pages ( amount = 50 )
116+ cache_current_user_content
69117
70- # Cache recently-edited pages
71- @recently_edited_pages = @current_user_content . values . flatten
72- . sort_by ( &:updated_at )
73- . last ( 50 )
74- . reverse
118+ @recently_created_pages = if user_signed_in?
119+ @current_user_content . values . flatten
120+ . sort_by ( &:created_at )
121+ . last ( amount )
122+ . reverse
123+ else
124+ [ ]
125+ end
126+ end
127+
128+ def cache_recently_edited_pages ( amount = 50 )
129+ cache_current_user_content
130+
131+ @recently_edited_pages ||= if user_signed_in?
132+ @current_user_content . values . flatten
133+ . sort_by ( &:updated_at )
134+ . last ( amount )
135+ . reverse
136+ else
137+ [ ]
138+ end
75139 end
76140
77141 def cache_forums_unread_counts
78- @unread_threads = if user_signed_in?
142+ @unread_threads || = if user_signed_in?
79143 Thredded ::Topic . unread_followed_by ( current_user ) . count
80144 else
81145 0
82146 end
83147
84- @unread_private_messages = if user_signed_in?
148+ @unread_private_messages || = if user_signed_in?
85149 Thredded ::PrivateTopic
86150 . for_user ( current_user )
87151 . unread ( current_user )
@@ -91,33 +155,60 @@ def cache_forums_unread_counts
91155 end
92156 end
93157
94- def cache_linkable_content_for_each_content_type
95- linkable_classes = Rails . application . config . content_types [ :all ] . map ( &:name ) & current_user . user_content_type_activators . pluck ( :content_type )
96- linkable_classes += %w( Document Timeline )
158+ def cache_contributable_universe_ids
159+ cache_current_user_content
97160
98- @linkables_cache = { }
99- @linkables_raw = { }
100- linkable_classes . each do |class_name |
101- # class_name = "Character"
161+ @contributable_universe_ids ||= if user_signed_in?
162+ current_user . contributable_universe_ids + @current_user_content . fetch ( 'Universe' , [ ] ) . map ( &:id )
163+ else
164+ [ ]
165+ end
166+ end
102167
103- @linkables_cache [ class_name ] = current_user
104- . send ( "linkable_#{ class_name . downcase . pluralize } " )
105- . in_universe ( @universe_scope )
168+ def cache_linkable_content_for_each_content_type
169+ cache_contributable_universe_ids
170+ cache_current_user_content
171+
172+ linkable_classes = @activated_content_types
173+ linkable_classes += %w( Document Timeline )
106174
107- if @content . present? && @content . persisted?
108- @linkables_cache [ class_name ] = @linkables_cache [ class_name ]
109- . in_universe ( @content . universe )
110- . reject { |content | content . class . name == class_name && content . id == @content . id }
175+ @linkables_cache = { } # Cache is list of [[page_name, page_id], [page_name, page_id], ...]
176+ @linkables_raw = { } # Raw is list of objects [#{page}, #{page}, ...]
177+
178+ @current_user_content . each do |page_type , content_list |
179+ # We already have our own list of content by the current user in @current_user_content,
180+ # so all we need to grab is additional pages in contributable universes
181+ @linkables_raw [ page_type ] = @current_user_content [ page_type ]
182+
183+ if !@universe_scope && @contributable_universe_ids . any?
184+ existing_page_ids = @linkables_raw [ page_type ] . map ( &:id )
185+
186+ pages_to_add = if page_type == Universe . name
187+ page_type . constantize . where ( id : @contributable_universe_ids )
188+ . where . not ( id : existing_page_ids )
189+ else
190+ page_type . constantize . where ( universe_id : @contributable_universe_ids )
191+ . where . not ( id : existing_page_ids )
192+ end
193+
194+ filtered_fields = ContentPage . polymorphic_content_fields . map ( &:to_s )
195+ filtered_fields . push 'universe_id' unless page_type == Universe . name
196+ pages_to_add . each do |page_data |
197+ filtered_page_data = page_data . attributes . slice ( *filtered_fields )
198+ @linkables_raw [ page_type ] . push ContentPage . new ( filtered_page_data )
199+ end
111200 end
112201
113- @linkables_raw [ class_name ] = @linkables_cache [ class_name ]
114- . sort_by { |p | p . name . downcase }
115- . compact
202+ # We can't properly display or @-mention content without a name set, so we explicitly
203+ # reject it here. However, this is a bit of a code-smell: why is there content without
204+ # a name set?
205+ @linkables_raw [ page_type ] . reject! { |page | page . name . nil? }
206+
207+ # Finally, we want to sort our linkables cache once so we don't have to sort it again
208+ @linkables_raw [ page_type ] . sort_by! { |page | page . name . downcase } . compact!
116209
117- @linkables_cache [ class_name ] = @linkables_cache [ class_name ]
118- . sort_by { |p | p . name . downcase }
119- . map { |c | [ c . name , c . id ] }
120- . compact
210+ # Lastly, build our name/id cache as well
211+ @linkables_cache [ page_type ] = @linkables_raw [ page_type ] . map { |page | [ page . name , page . id ] }
121212 end
122213 end
123214end
0 commit comments