lportal 1.0.9 → 1.0.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/ChangeLog +71 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README +6 -5
  4. data/Rakefile +23 -0
  5. data/init.rb +1 -1
  6. data/lib/acts/resourceful.rb +104 -0
  7. data/lib/company.rb +25 -0
  8. data/lib/group.rb +83 -29
  9. data/lib/journal/article.rb +8 -4
  10. data/lib/mb/category.rb +30 -59
  11. data/lib/mb/message.rb +24 -67
  12. data/lib/permission.rb +16 -0
  13. data/lib/release.rb +9 -0
  14. data/lib/resource.rb +19 -0
  15. data/lib/resource_code.rb +21 -1
  16. data/lib/role.rb +7 -27
  17. data/lib/tag/asset.rb +26 -4
  18. data/lib/user.rb +20 -23
  19. data/lib/web/layout.rb +134 -39
  20. data/lib/web/layout_set.rb +8 -4
  21. data/lib/web/portlet.rb +92 -20
  22. data/lib/web/portlet_preferences.rb +176 -13
  23. data/lib/web/portlet_properties.rb +32 -0
  24. data/lib/web/typesettings.rb +32 -7
  25. data/lportal.rb +30 -3
  26. data/migrations/20090101000001_add_sequences.rb +64 -0
  27. data/migrations/20090309000001_portlet_properties.rb +19 -0
  28. data/portlets.rb +76 -0
  29. data/schema.rb +34 -0
  30. data/test/unit/company_test.rb +21 -9
  31. data/test/unit/dl_file_test.rb +2 -1
  32. data/test/unit/group_test.rb +74 -16
  33. data/test/unit/journal/article_test.rb +15 -1
  34. data/test/unit/mb/category_test.rb +12 -15
  35. data/test/unit/mb/message_test.rb +3 -2
  36. data/test/unit/mb/thread_test.rb +1 -1
  37. data/test/unit/organization_test.rb +7 -2
  38. data/test/unit/phone_test.rb +2 -0
  39. data/test/unit/release_test.rb +25 -0
  40. data/test/unit/role_test.rb +7 -7
  41. data/test/unit/tag/asset_test.rb +59 -2
  42. data/test/unit/user_test.rb +73 -77
  43. data/test/unit/web/layout_set_test.rb +18 -1
  44. data/test/unit/web/layout_test.rb +191 -5
  45. data/test/unit/web/portlet_preferences_test.rb +314 -17
  46. data/test/unit/web/portlet_properties_test.rb +36 -0
  47. data/test/unit/web/portlet_test.rb +121 -19
  48. data/test/unit/web/typesettings_test.rb +24 -11
  49. data/version.rb +1 -2
  50. metadata +20 -6
  51. data/install.rb +0 -1
data/lib/web/layout.rb CHANGED
@@ -5,7 +5,10 @@ module Web
5
5
  set_table_name :layout
6
6
  set_primary_key :plid
7
7
 
8
- validates_uniqueness_of :layoutid, :scope => [:groupid, :privatelayout]
8
+ acts_as_resourceful
9
+
10
+ # FIXME: does not work properly. even if the layoutid is available, this causes self.errors
11
+ #validates_uniqueness_of :layoutid, :scope => [:groupid, :privatelayout]
9
12
 
10
13
 
11
14
  # com.liferay.portal.model.Layout
@@ -34,6 +37,7 @@ module Web
34
37
  # Optional extra parameters:
35
38
  # - locale
36
39
  def initialize(params)
40
+ logger.debug params.inspect
37
41
  raise 'No groupid given' unless (params[:groupid] or params[:group])
38
42
  raise 'No privatelayout given' if params[:privatelayout].nil?
39
43
  _name = params.delete(:name) || 'New layout'
@@ -52,11 +56,13 @@ module Web
52
56
  name += _name
53
57
  name += '</name></root>'
54
58
  self.name = name
59
+ self.save
55
60
 
56
61
  # perhaps layoutid could be sequenced.
57
62
  layouts = (self.is_public? ? self.group.public_layouts : self.group.private_layouts)
58
63
  _ids = (layouts.any? ? layouts.collect(&:layoutid) : nil)
59
64
  self.layoutid = (_ids.nil? ? 1 : _ids.sort.max+1)
65
+ self.save
60
66
 
61
67
  # increment pagecount
62
68
  _set = self.layoutset
@@ -88,34 +94,11 @@ module Web
88
94
  # +201 2 10166
89
95
  # +202 3 10301
90
96
 
91
- rc = self.resource_code(2)
92
- unless rc
93
- rc = ResourceCode.create(
94
- :companyid => self.companyid,
95
- :name => self.liferay_class,
96
- :scope => 2
97
- )
98
- end
99
- unless Resource.find(:first, :conditions => "codeid=#{rc.id} AND primkey='#{self.group.id}'")
100
- Resource.create(
101
- :codeid => rc.id,
102
- :primkey => self.group.id
103
- )
104
- end
97
+ self.get_resource(:scope => 2)
105
98
 
106
99
  # Create a resource with scope=4 for this Layout.
107
- rc = self.resource_code(4)
108
- unless rc
109
- rc = ResourceCode.create(
110
- :companyid => self.companyid,
111
- :name => self.liferay_class,
112
- :scope => 4
113
- )
114
- end
115
- resource = Resource.create(
116
- :codeid => rc.id,
117
- :primkey => self.id
118
- )
100
+ resource = self.get_resource(:scope => 4)
101
+ logger.debug 'resource: %s' % resource.inspect
119
102
 
120
103
  # COPY permission_ (permissionid, companyid, actionid, resourceid) FROM stdin;
121
104
  # +301 10109 ADD_DISCUSSION 202
@@ -123,7 +106,7 @@ module Web
123
106
  # +303 10109 VIEW 202
124
107
 
125
108
  self.class.actions.each do |actionid|
126
- p = Permission.create(
109
+ p = Permission.get(
127
110
  :companyid => self.companyid,
128
111
  :actionid => actionid,
129
112
  :resourceid => resource.id
@@ -133,21 +116,50 @@ module Web
133
116
  # +10129 301
134
117
  # +10129 302
135
118
  # +10129 303
136
- # +10111 303
137
119
 
120
+ # admins can do everything
138
121
  self.company.administrators.each do |user|
139
- user.user_permissions << p
122
+ user.permissions << p
140
123
  end
141
124
 
142
125
  # COPY groups_permissions (groupid, permissionid) FROM stdin;
143
126
  # +10166 301
144
127
  # +10166 303
145
- group = self.group
146
- self.group.permissions << p
128
+
129
+ # group members can ADD_DISCUSSION and VIEW
130
+ if (actionid=='ADD_DISCUSSION' or actionid=='VIEW')
131
+ self.group.permissions << p
132
+ end
133
+
134
+ # COPY users_permissions (userid, permissionid) FROM stdin;
135
+ # +10111 303
136
+
137
+ # guest is permitted to VIEW if the layout is public.
138
+ if self.is_public? and actionid=='VIEW'
139
+ self.company.guest.permissions << p
140
+ end
141
+
147
142
  end
143
+
144
+ # the layout management portlet (new in 5.2.x?)
145
+
146
+ # COPY portletpreferences (portletpreferencesid, ownerid, ownertype, plid, portletid, preferences) FROM stdin;
147
+ # +10259 0 3 10301 88 <portlet-preferences />
148
+
149
+ # perhaps this will create itself?
150
+ # Web::PortletPreferences.create(:plid => self.plid, :portletid => 88)
151
+
148
152
  return self
149
153
  end
150
154
 
155
+ def save
156
+ super
157
+ if self.errors.any?
158
+ logger.error self.errors.inspect
159
+ raise self.errors[:layoutid] if self.errors[:layoutid]
160
+ end
161
+ end
162
+
151
163
  public
152
164
 
153
165
  belongs_to :group,
@@ -207,17 +219,100 @@ module Web
207
219
 
208
220
  # the URL path to this Layout
209
221
  def path
210
- self.layoutset.url_prefix + self.group.friendlyurl + self.friendlyurl
222
+ self.layoutset ?
223
+ self.layoutset.url_prefix + self.group.friendlyurl + self.friendlyurl : ''
224
+ end
225
+
226
+ # Settings for this Layout.
227
+ #
228
+ # Returns the object model of the string "typesettings".
229
+ def settings
230
+ Typesettings.new(self.typesettings)
211
231
  end
212
232
 
213
- # ResourceCode associated to this instance (and scope)
214
- def resource_code(scope=4)
215
- ResourceCode.find(:first,
216
- :conditions => "companyid=#{self.companyid} AND name='#{self.liferay_class}' AND scope=#{scope}")
233
+ # Save settings. Parses them to typesettings string.
234
+ #
235
+ # Parameters:
236
+ # - ts = Typesettings instance
237
+ def settings=(ts)
238
+ raise 'parameter must be a Typesettings instance' unless ts.is_a?(Typesettings)
239
+ self.typesettings = ts.to_s
217
240
  end
218
241
 
219
- def contents
220
- Typesettings.new(self.typesettings)
242
+ # As the method 'name' returns the name in XML, name_string is the string representation.
243
+ def name_string
244
+ self.name[/([^>]*)<\/name/,1]
245
+ end
246
+
247
+ # Insert the name string to XML.
248
+ def name_string=(name)
249
+ self.name = "<?xml version='1.0' encoding='UTF-8'?>"+\
250
+ '<root available-locales="en_US" default-locale="en_US"><name language-id="en_US">%s</name></root>' % name
251
+ end
252
+
253
+ # sets the number of columns in this layout
254
+ def columns=(nr)
255
+ s = self.settings
256
+ s.columns = nr
257
+ self.settings = s
258
+ end
259
+
260
+ # Add a portlet to this layout.
261
+ def <<(portlet, params={})
262
+ unless portlet
263
+ logger.debug 'No portlet given'
264
+ return false
265
+ end
266
+
267
+ if portlet.is_a?(Web::PortletPreferences)
268
+ preferences = portlet
269
+ portlet = preferences.portlet
270
+ else
271
+ preferences = portlet.preferences
272
+ end
273
+
274
+ # define the layout
275
+ preferences.layout = self
276
+ preferences.save
277
+
278
+ # not very OO..
279
+ settings = self.settings
280
+ location = (params[:location] ||= {:column => 1})
281
+ #puts location.inspect
282
+
283
+ # accept either a string or a symbol or Portlet
284
+ # puts portlet.inspect
285
+ # puts settings.portlets.inspect
286
+ settings.portlets.update(
287
+ location[:column] => [preferences || portlet]
288
+ )
289
+ # puts settings.portlets.inspect
290
+ self.settings=settings
291
+
292
+ [1,2].each do |scope|
293
+ preferences.get_resource(:scope => scope)
294
+ end
295
+
296
+ # guest permissions are given if the layout is public.
297
+ # (TODO: AND IF THE GROUP IS GUEST)
298
+
299
+ resource = preferences.get_resource(:scope => 4)
300
+ preferences.class.actions.each do |actionid|
301
+ p = Permission.get(
302
+ :companyid => self.companyid,
303
+ :actionid => actionid,
304
+ :resourceid => resource.id
305
+ )
306
+ if actionid=='VIEW'
307
+ self.group.permissions << p
308
+ if self.is_public?
309
+ guest = self.company.guest
310
+ guest.permissions << p
311
+ end
312
+ end
313
+ end
314
+
315
+ self
221
316
  end
222
317
 
223
318
  end
@@ -45,14 +45,18 @@ module Web
45
45
  end
46
46
 
47
47
  def layouts
48
+ return 0 unless self.group
48
49
  Web::Layout.find(:all, :conditions => "groupid=#{self.groupid} AND privatelayout=#{self.privatelayout}" )
49
50
  end
50
51
 
51
52
  # lookup the path prefix for this LayoutSet
52
53
  def url_prefix
54
+ return '' unless self.group
53
55
  return '/web' if self.is_public?
54
-
55
- _class = Classname.model(Classname.find(self.group.classnameid).value)
56
+ _class = (
57
+ self.group.classnameid==0 ?
58
+ Group : Classname.model(Classname.find(self.group.classnameid).value)
59
+ )
56
60
  if _class == User
57
61
  return '/user' #if self.is_private?
58
62
  #return '/web'
@@ -62,8 +66,8 @@ module Web
62
66
  #return '/web'
63
67
 
64
68
  else
65
- logger.debug 'FIXME: ' + _class
66
- return nil
69
+ logger.debug 'FIXME: %s' % _class
70
+ return ''
67
71
  end
68
72
  end
69
73
 
data/lib/web/portlet.rb CHANGED
@@ -1,47 +1,119 @@
1
- module Web
2
- # Not all portlets are necessarily saved in the database.
1
+ module Web # :nodoc:
2
+ # Portlets can be included onto a Layout. Portlets are not instantiated per se; when one is
3
+ # inserted on a Layout, PortletPreferences is created. This instance (from ActiveRecord's point-of-view),
4
+ # may be instantiated or not, from Liferay's POV. Instantiation in this sense means that each PortletPreferences
5
+ # may have session-based customization.
6
+ #
7
+ # Caterpillar can gather this information from the Liferay XML files, see its documentation.
8
+ #
3
9
  class Portlet < ActiveRecord::Base
4
10
  set_table_name :portlet
5
11
  set_primary_key :id_
6
12
 
7
13
  public
8
14
 
15
+ # com.liferay.portal.model.Portlet
16
+ def liferay_class
17
+ 'com.liferay.portal.model.Portlet'
18
+ end
19
+
9
20
  belongs_to :company,
10
21
  :foreign_key => "companyid"
11
22
 
12
- def name
13
- self.portletid
23
+ # Creates a portlet instance with preferences.
24
+ def initialize(params={})
25
+ super(params)
26
+ self.roles ||= ''
27
+ self.active_ = true if self.active_.nil?
28
+
29
+ self
14
30
  end
15
31
 
16
- # primkey in resource_ table
17
- def primkey(plid)
18
- "#{plid}_LAYOUT_#{self.portletid}"
32
+
33
+ # Searches from PortletProperties.
34
+ # Returns nil unless one is found. Returns a Portlet if the properties are found.
35
+ def self.find_by_name(name)
36
+ pp = Web::PortletProperties.find_by_name(name)
37
+ unless pp
38
+ logger.warn 'Portlet by name was not found -- are portletproperties up-to-date?'
39
+ return nil
40
+ end
41
+ pp.portlet
19
42
  end
20
43
 
21
- def resource(plid)
22
- Resource.find_by_primkey(self.primkey(plid))
44
+
45
+ # PortletPreferences for this instance (@preferences)
46
+ #
47
+ # This Web::Portlet instance may have several "instances of itself", each of which are stored
48
+ # in PortletPreferences. Each of these are unique rows in the database,
49
+ # and these are accessible through the 'instances' association.
50
+ #
51
+ # PortletPreferences are created when the Portlet is added to a Layout.
52
+ # Its portletid, on the other hand, depends on whether this portlet is instanceable.
53
+ def preferences
54
+ unless @preferences
55
+ @preferences = Web::PortletPreferences.create({:portlet => self})
56
+ end
57
+ return @preferences
23
58
  end
24
59
 
25
- # all instances
26
- def resources
27
- # Resource.find_by_primkey(self.primkey)
28
- # Resource.find(:all, :conditions => "primkey='#{self.primkey}'")
29
- resources = []
30
- ResourceCode.find(:all, :conditions => "name='#{portletid}'").each do |rc|
31
- resources << Resource.find(:all, :conditions => "codeid='#{rc.id}'")
60
+ attr_writer :preferences
61
+
62
+ # All instances of a specific portlet. See also preferences.
63
+ def instances
64
+ unless @instances
65
+ @instances = Web::PortletPreferences.find_all_by_portletid(self.portletid)
32
66
  end
67
+ return @instances
68
+ end
69
+
70
+ # Various static properties of the portlet instance and the portlet in general.
71
+ # Requires custom migrations for PortletProperties.
72
+ # The tables within are filled by Caterpillar, since it knows the location of the
73
+ # portlet XML files.
74
+ def properties
75
+ unless @properties
76
+ @properties = Web::PortletProperties.find_by_portletid(self.portletid)
77
+ end
78
+ return @properties
79
+ end
33
80
 
34
- return resources.flatten
81
+ # The default title string that is displayed.
82
+ #
83
+ # Requires custom migrations for PortletProperties. Defaults to an empty string.
84
+ #
85
+ # PortletPreferences may override this, see PortletPreferences#title.
86
+ #
87
+ def title
88
+ self.properties ?
89
+ self.properties.title : ''
90
+ end
91
+
92
+ # Portlet's JSR286 name.
93
+ #
94
+ # Requires custom migrations for PortletProperties. Defaults to portletid.
95
+ #
96
+ def name
97
+ self.properties ?
98
+ self.properties.name : self.portletid
35
99
  end
36
100
 
37
101
  def is_active?
38
102
  self.active_
39
103
  end
40
104
 
41
- # comply API with Web::PortletPreferences
42
- def preferences_
43
- ""
105
+ # Is the portlet instanceable? This is defined in the XML configuration.
106
+ # Requires custom migrations for PortletProperties.
107
+ #
108
+ # Defaults to true.
109
+ def instanceable?
110
+ return @instanceable if !@instanceable.nil? # test value
111
+ self.properties ?
112
+ self.properties.instanceable : true
44
113
  end
45
114
 
115
+ # for testing and debugging
116
+ attr_writer :instanceable
117
+
46
118
  end
47
119
  end
@@ -1,38 +1,167 @@
1
1
  module Web
2
+ # While PortletPreferences acts_as_resourceful, it is a resource as the portlet it represents.
3
+ # The ResourceCode has a 'name' value that is the Portlet's portletid.
4
+ #
5
+ # Also see Lportal::Portlets, that adds a method +path+.
2
6
  class PortletPreferences < ActiveRecord::Base
3
7
  set_table_name :portletpreferences
4
8
  set_primary_key :portletpreferencesid
5
9
 
10
+ acts_as_resourceful
11
+
12
+ include Lportal::Portlets
13
+
6
14
  public
7
15
 
16
+ # com.liferay.portal.model.PortletPreferences
17
+ def liferay_class
18
+ 'com.liferay.portal.model.PortletPreferences'
19
+ end
20
+
21
+ # add portlets to layouts via Layout#<<
8
22
  belongs_to :layout,
9
23
  :class_name => 'Web::Layout',
10
24
  :foreign_key => 'plid'
11
25
 
12
- belongs_to :owner,
13
- :class_name => 'User',
14
- :foreign_key => 'ownerid'
26
+ # this is more complicated than this.
27
+ # belongs_to :owner,
28
+ # :class_name => 'User',
29
+ # :foreign_key => 'ownerid'
15
30
 
16
- def name
31
+
32
+ # Actions for Permissions.
33
+ def self.actions
34
+ %w{
35
+ CONFIGURATION
36
+ VIEW
37
+ }
38
+ end
39
+
40
+ # PortletPreferences instance keeps record of unique Portlet preferences.
41
+ #
42
+ # Parameteres:
43
+ # - portletid (String) (or portlet)
44
+ # - portlet Web::Portlet
45
+ # - preferences String
46
+ def initialize(params={})
47
+ portlet = params.delete(:portlet) if params[:portlet]
48
+
49
+ super(params)
50
+
51
+ self.preferences ||= '<portlet-preferences />'
52
+ self.ownerid ||= 0 # ??
53
+ self.ownertype ||= 3 # ??
54
+
55
+ # since the instance in not yet saved, the portletid might be integer
56
+ portlet ||= Web::Portlet.find_by_portletid("#{self.portletid}")
57
+ if portlet
58
+ self.portlet = portlet # instantiates if applicaple
59
+ else
60
+ # nil is most likely an error. the portlet database is not populated?
61
+ # in this case default to fallback action and instantiate the portlet.
62
+ self.portletid = self.class.instance_id(self.portletid)
63
+ end
64
+ self
65
+ end
66
+
67
+ # generates a random instance id
68
+ def self.instance_id(portletid)
69
+ '%s_INSTANCE_%s' % [portletid, random_string(4)]
70
+ end
71
+
72
+ # Defines the portlet that the preferences describe.
73
+ # Instantiates if the portlet can instantiated.
74
+ def portlet=(portlet)
75
+ self.portletid = (
76
+ portlet.instanceable? ?
77
+ self.class.instance_id(portlet.portletid) : portlet.portletid
78
+ )
79
+ end
80
+
81
+ # The Web::Portlet of this "preferences".
82
+ def portlet
83
+ unless @portlet
84
+ unless self.companyid
85
+ logger.warn 'Requested portlet of portletpreferences -- yet no companyid could be fetched.'
86
+ @portlet = nil
87
+ else
88
+ logger.debug 'ok'
89
+ logger.debug self.portlet_id
90
+ @portlet = Web::Portlet.find(:first,
91
+ :conditions => "companyid=#{self.companyid} AND portletid='#{self.portlet_id}'")
92
+ end
93
+ end
94
+ logger.debug @portlet.inspect
95
+ return @portlet
96
+ end
97
+
98
+ # Various static properties of the portlet instance and the portlet in general.
99
+ # Requires custom migrations for PortletProperties.
100
+ # The tables within are filled by Caterpillar, since it knows the location of the
101
+ # portlet XML files.
102
+ #
103
+ # This is intentionally duplicated for Web::Portlet to minimize database queries.
104
+ def properties
105
+ unless @properties
106
+ @properties = Web::PortletProperties.find_by_portletid(self.portlet_id)
107
+ end
108
+ return @properties
109
+ end
110
+
111
+ # The portletid of the Web::Portlet. <tt>portletid</tt> is still the actual portletid of the instance.
112
+ def portlet_id
17
113
  self.portletid.split(/_INSTANCE_/)[0]
18
114
  end
19
115
 
20
- # primkey in resource_ table
116
+ # the 4-char random string
117
+ def instance_id
118
+ self.portletid.split(/_INSTANCE_/)[1]
119
+ end
120
+
121
+ # The default title string that is displayed. Requires custom migrations for PortletProperties.
122
+ # Rails-portlets override this, with the value of <head><title>.
123
+ # There are no Ruby setters yet, this value is read-only.
124
+ #
125
+ # TODO: parse self.preferences:
126
+ # <portlet-preferences>
127
+ # <preference>
128
+ # <name>portlet-setup-title-fi_FI</name>
129
+ # <value>my custom title</value>
130
+ # </preference>
131
+ # <preference>
132
+ # <name>portlet-setup-use-custom-title</name>
133
+ # <value>true</value>
134
+ # </preference>
135
+ # </portlet-preferences>
136
+ def title
137
+ self.properties ?
138
+ self.properties.title : ''
139
+ end
140
+
141
+ # Portlet's JSR286 name.
142
+ #
143
+ # Requires custom migrations for PortletProperties. Defaults to portlet's portletid.
144
+ #
145
+ def name
146
+ self.properties ?
147
+ self.properties.name : self.portlet_id
148
+ end
149
+
150
+ # primkey is the foreign key in the resource_ table.
21
151
  def primkey
152
+ logger.debug 'primkey'
22
153
  "#{self.plid}_LAYOUT_#{self.portletid}"
23
154
  end
24
155
 
25
- # argument plid is to comply API with Web::Portlet.resource
26
- def resource(plid=nil)
27
- Resource.find_by_primkey(self.primkey)
28
- # Resource.find(:all, :conditions => "primkey='#{self.primkey}'")
156
+ # Parses the preferences string to an XML structure
157
+ def to_xml
158
+ REXML::Document.new(self.preferences)
29
159
  end
30
160
 
31
- # loads the preferences XML structure to Ruby Hash
32
- def preferences_
33
- xml = REXML::Document.new(self.preferences)
161
+ # Translates the preferences XML structure to Array of Hashes.
162
+ def to_a
34
163
  preferences = []
35
- xml.elements.each("portlet-preferences/preference") do |pref|
164
+ self.to_xml.elements.each("portlet-preferences/preference") do |pref|
36
165
  phash = {
37
166
  :name => pref.elements["name"].text,
38
167
  :value => (pref.elements["value"] ? pref.elements["value"].text : "")
@@ -42,5 +171,39 @@ module Web
42
171
  return preferences
43
172
  end
44
173
 
174
+ attr_writer :companyid
175
+
176
+ # @companyid can be set temporarily.
177
+ # if layout is set, its companyid is used.
178
+ def companyid
179
+ ( self.layout ? self.layout.companyid : @companyid
180
+ ) or nil
181
+ end
182
+
183
+ # Override acts_as_resourceful. Use portlet's portletid (without INSTANCE) as the ResourceCode name.
184
+ def resource_code(scope=4)
185
+ ResourceCode.get({
186
+ :companyid => self.companyid,
187
+ :name => self.portlet_id,
188
+ :scope => scope
189
+ })
190
+ end
191
+
192
+ def scope2_primkey
193
+ self.layout ?
194
+ self.layout.groupid : nil
195
+ end
196
+
197
+ def scope4_primkey
198
+ self.primkey
199
+ end
200
+
201
+ private
202
+
203
+ def self.random_string(len=10)
204
+ chars = ('a'..'z').to_a + ('A'..'Z').to_a
205
+ (0...len).collect { chars[Kernel.rand(chars.length)] }.join
206
+ end
207
+
45
208
  end
46
209
  end
@@ -0,0 +1,32 @@
1
+ module Web # :nodoc:
2
+ # This table is not in the original lportal database.
3
+ # This is created by a ActiveRecord migration and contains metadata about portlets.
4
+ class PortletProperties < ActiveRecord::Base
5
+ set_table_name :portletproperties
6
+
7
+ # Returns a portlet from a random company unless @companyid is set.
8
+ def portlet
9
+ unless @portlet
10
+ conditions = ["portletid='#{self.portletid}'"]
11
+ conditions << "companyid=#{@companyid}" if @companyid
12
+ @portlet = Web::Portlet.find(:first, :conditions => conditions.join(' AND '))
13
+ unless @portlet
14
+ # create
15
+ p = Web::Portlet.create(
16
+ :portletid => self.portletid
17
+ )
18
+ if @companyid
19
+ p.companyid = @companyid
20
+ p.save
21
+ end
22
+ @portlet = p.reload
23
+ end
24
+ end
25
+ return @portlet
26
+ end
27
+
28
+ # @companyid can be set temporarily.
29
+ attr_accessor :companyid
30
+
31
+ end
32
+ end