edgarj 0.01.12

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.
Files changed (185) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +23 -0
  4. data/Rakefile +40 -0
  5. data/app/assets/javascripts/edgarj/base.js +49 -0
  6. data/app/assets/javascripts/edgarj/menu.js +39 -0
  7. data/app/assets/javascripts/edgarj/operator_selection.js +133 -0
  8. data/app/assets/stylesheets/edgarj/base.css +304 -0
  9. data/app/assets/stylesheets/edgarj/menu.css +65 -0
  10. data/app/controllers/edgarj/authentication_mixin.rb.sample +30 -0
  11. data/app/controllers/edgarj/controller_mixin_common.rb +80 -0
  12. data/app/controllers/edgarj/controller_mixin_for_app.rb +71 -0
  13. data/app/controllers/edgarj/edgarj_controller.rb +535 -0
  14. data/app/controllers/edgarj/model_permissions_controller.rb +8 -0
  15. data/app/controllers/edgarj/permission_mixin.rb +84 -0
  16. data/app/controllers/edgarj/popup_controller.rb +128 -0
  17. data/app/controllers/edgarj/rescue_mixin.rb +37 -0
  18. data/app/controllers/edgarj/user_group_users_controller.rb +8 -0
  19. data/app/controllers/edgarj/user_groups_controller.rb +9 -0
  20. data/app/controllers/edgarj/user_groups_popup_controller.rb +8 -0
  21. data/app/helpers/edgarj/assoc_helper.rb +369 -0
  22. data/app/helpers/edgarj/common_helper.rb +37 -0
  23. data/app/helpers/edgarj/edgarj_helper.rb +20 -0
  24. data/app/helpers/edgarj/field_helper.rb +397 -0
  25. data/app/helpers/edgarj/form_drawer.rb +322 -0
  26. data/app/helpers/edgarj/list_drawer.rb +169 -0
  27. data/app/helpers/edgarj/menu_helper.rb +92 -0
  28. data/app/helpers/edgarj/model_permissions_helper.rb +9 -0
  29. data/app/helpers/edgarj/popup_helper.rb +40 -0
  30. data/app/helpers/edgarj/search_helper.rb +14 -0
  31. data/app/helpers/edgarj/sessions_helper.rb +9 -0
  32. data/app/helpers/edgarj/user_group_users_helper.rb +9 -0
  33. data/app/helpers/edgarj/user_groups_helper.rb +9 -0
  34. data/app/helpers/edgarj/user_groups_popup_helper.rb +9 -0
  35. data/app/models/edgarj/drawer/base.rb +234 -0
  36. data/app/models/edgarj/drawer/normal.rb +6 -0
  37. data/app/models/edgarj/drawer/popup.rb +47 -0
  38. data/app/models/edgarj/drawer.rb +13 -0
  39. data/app/models/edgarj/model_permission.rb +41 -0
  40. data/app/models/edgarj/page_info.rb +47 -0
  41. data/app/models/edgarj/search.rb +81 -0
  42. data/app/models/edgarj/search_form.rb +255 -0
  43. data/app/models/edgarj/search_popup.rb +44 -0
  44. data/app/models/edgarj/sssn.rb +120 -0
  45. data/app/models/edgarj/user_group.rb +67 -0
  46. data/app/models/edgarj/user_group_user.rb +18 -0
  47. data/app/models/edgarj.rb +5 -0
  48. data/app/views/edgarj/edgarj/_form.html.erb +25 -0
  49. data/app/views/edgarj/edgarj/_list.html.erb +52 -0
  50. data/app/views/edgarj/edgarj/_message_popup.html.erb +15 -0
  51. data/app/views/edgarj/edgarj/_search_form.html.erb +64 -0
  52. data/app/views/edgarj/edgarj/_search_operator.html.erb +17 -0
  53. data/app/views/edgarj/edgarj/_search_operator_selection.html.erb +12 -0
  54. data/app/views/edgarj/edgarj/clear.js.erb +1 -0
  55. data/app/views/edgarj/edgarj/create.js.erb +4 -0
  56. data/app/views/edgarj/edgarj/destroy.js.erb +2 -0
  57. data/app/views/edgarj/edgarj/index.html.erb +37 -0
  58. data/app/views/edgarj/edgarj/index.js.erb +1 -0
  59. data/app/views/edgarj/edgarj/message_popup.js.erb +3 -0
  60. data/app/views/edgarj/edgarj/page_info_save.js.erb +1 -0
  61. data/app/views/edgarj/edgarj/search.js.erb +4 -0
  62. data/app/views/edgarj/edgarj/search_clear.js.erb +1 -0
  63. data/app/views/edgarj/edgarj/show.js.erb +1 -0
  64. data/app/views/edgarj/edgarj/top.html.erb +4 -0
  65. data/app/views/edgarj/edgarj/update.js.erb +4 -0
  66. data/app/views/edgarj/popup/_index.html.erb +16 -0
  67. data/app/views/edgarj/popup/_list.html.erb +42 -0
  68. data/app/views/edgarj/popup/_message_popup.html.erb +15 -0
  69. data/app/views/edgarj/popup/_search.html.erb +42 -0
  70. data/app/views/edgarj/popup/_search_save_popup.html.erb +16 -0
  71. data/app/views/edgarj/popup/index.js.erb +5 -0
  72. data/app/views/edgarj/popup/message_popup.js.erb +3 -0
  73. data/app/views/edgarj/popup/page_info_save.js.erb +1 -0
  74. data/app/views/edgarj/popup/search.js.erb +15 -0
  75. data/app/views/edgarj/popup/view_status_save.js.erb +1 -0
  76. data/config/routes.rb +15 -0
  77. data/config/settings.yml +5 -0
  78. data/db/migrate/20131118084600_create_edgar_sssns.rb +14 -0
  79. data/db/migrate/20131123124730_create_edgar_page_infos.rb +15 -0
  80. data/db/migrate/20140116062252_create_edgar_user_groups.rb +18 -0
  81. data/db/migrate/20140116062327_create_edgar_user_group_users.rb +10 -0
  82. data/db/migrate/20140206222308_create_edgar_model_permissions.rb +14 -0
  83. data/db/migrate/20141209053055_rename_edgar_to_edgarj.rb +17 -0
  84. data/lib/core_ext/active_record.rb +123 -0
  85. data/lib/core_ext/resources.rb +71 -0
  86. data/lib/edgarj/engine.rb +64 -0
  87. data/lib/edgarj/enum_cache.rb +46 -0
  88. data/lib/edgarj/templates/rails/helper/helper.rb +10 -0
  89. data/lib/edgarj/templates/test_unit/scaffold/functional_test.rb +575 -0
  90. data/lib/edgarj/version.rb +3 -0
  91. data/lib/edgarj.rb +14 -0
  92. data/lib/generators/edgarj/popup_scaffold/USAGE +6 -0
  93. data/lib/generators/edgarj/popup_scaffold/popup_scaffold_generator.rb +35 -0
  94. data/lib/generators/edgarj/popup_scaffold/templates/controller.rb +13 -0
  95. data/lib/generators/edgarj/popup_scaffold/templates/functional_test.rb +197 -0
  96. data/lib/generators/edgarj/popup_scaffold/templates/helper.rb +9 -0
  97. data/lib/generators/edgarj/scaffold/USAGE +17 -0
  98. data/lib/generators/edgarj/scaffold/scaffold_generator.rb +40 -0
  99. data/lib/generators/edgarj/scaffold/templates/controller.rb +13 -0
  100. data/lib/tasks/edgarj_tasks.rake +32 -0
  101. data/lib/tasks/pakcage.rake +18 -0
  102. data/locale/en.yml +94 -0
  103. data/locale/ja.yml +100 -0
  104. data/test/dummy/README.rdoc +28 -0
  105. data/test/dummy/Rakefile +6 -0
  106. data/test/dummy/app/assets/javascripts/application.js +21 -0
  107. data/test/dummy/app/assets/javascripts/authors.js +2 -0
  108. data/test/dummy/app/assets/stylesheets/application.css +16 -0
  109. data/test/dummy/app/assets/stylesheets/authors.css +4 -0
  110. data/test/dummy/app/assets/stylesheets/scaffold.css +56 -0
  111. data/test/dummy/app/controllers/application_controller.rb +15 -0
  112. data/test/dummy/app/controllers/authors_controller.rb +6 -0
  113. data/test/dummy/app/controllers/authors_popup_controller.rb +6 -0
  114. data/test/dummy/app/controllers/books_controller.rb +6 -0
  115. data/test/dummy/app/controllers/dummy_auth_mixin.rb +36 -0
  116. data/test/dummy/app/decorators/models/edgarj/user_group_decorator.rb +1 -0
  117. data/test/dummy/app/helpers/application_helper.rb +3 -0
  118. data/test/dummy/app/helpers/authors_helper.rb +7 -0
  119. data/test/dummy/app/helpers/authors_popup_helper.rb +7 -0
  120. data/test/dummy/app/helpers/books_helper.rb +7 -0
  121. data/test/dummy/app/models/author.rb +32 -0
  122. data/test/dummy/app/models/book.rb +5 -0
  123. data/test/dummy/app/models/user.rb +13 -0
  124. data/test/dummy/app/views/layouts/application.html.erb +32 -0
  125. data/test/dummy/app/views/layouts/login.html.erb +20 -0
  126. data/test/dummy/bin/bundle +3 -0
  127. data/test/dummy/bin/rails +4 -0
  128. data/test/dummy/bin/rake +4 -0
  129. data/test/dummy/config/application.rb +59 -0
  130. data/test/dummy/config/boot.rb +10 -0
  131. data/test/dummy/config/database.yml +15 -0
  132. data/test/dummy/config/edgarj/menu_config.rb +28 -0
  133. data/test/dummy/config/environment.rb +5 -0
  134. data/test/dummy/config/environments/development.rb +42 -0
  135. data/test/dummy/config/environments/production.rb +79 -0
  136. data/test/dummy/config/environments/test.rb +34 -0
  137. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  138. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  139. data/test/dummy/config/initializers/inflections.rb +16 -0
  140. data/test/dummy/config/initializers/mime_types.rb +5 -0
  141. data/test/dummy/config/initializers/secret_token.rb +12 -0
  142. data/test/dummy/config/initializers/session_store.rb +3 -0
  143. data/test/dummy/config/initializers/strong_parameter.rb +3 -0
  144. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  145. data/test/dummy/config/locales/en.yml +26 -0
  146. data/test/dummy/config/routes.rb +60 -0
  147. data/test/dummy/config.ru +4 -0
  148. data/test/dummy/db/migrate/20131107120635_create_authors.rb +9 -0
  149. data/test/dummy/db/migrate/20131218011851_create_books.rb +10 -0
  150. data/test/dummy/db/migrate/20140201000000_add_user_group_id_to_authors.rb +5 -0
  151. data/test/dummy/db/migrate/20140807065420_create_users.rb +10 -0
  152. data/test/dummy/db/schema.rb +93 -0
  153. data/test/dummy/public/404.html +58 -0
  154. data/test/dummy/public/422.html +58 -0
  155. data/test/dummy/public/500.html +57 -0
  156. data/test/dummy/public/favicon.ico +0 -0
  157. data/test/dummy/script/rails +6 -0
  158. data/test/dummy/test/functional/authors_controller_test.rb +631 -0
  159. data/test/dummy/test/functional/books_controller_test.rb +516 -0
  160. data/test/dummy/test/helpers/authors_helper_test.rb +4 -0
  161. data/test/dummy/test/unit/author_test.rb +7 -0
  162. data/test/dummy/test/unit/book_test.rb +7 -0
  163. data/test/edgar_test.rb +7 -0
  164. data/test/fixtures/authors.yml +32 -0
  165. data/test/fixtures/books.yml +56 -0
  166. data/test/fixtures/edgarj/model_permissions.yml +97 -0
  167. data/test/fixtures/edgarj/page_infos.yml +84 -0
  168. data/test/fixtures/edgarj/sssns.yml +38 -0
  169. data/test/fixtures/edgarj/user_group_users.yml +114 -0
  170. data/test/fixtures/edgarj/user_groups.yml +95 -0
  171. data/test/fixtures/users.yml +49 -0
  172. data/test/functional/edgarj/edgarj_controller_test.rb +24 -0
  173. data/test/functional/edgarj/model_permissions_controller_test.rb +554 -0
  174. data/test/functional/edgarj/user_group_users_controller_test.rb +567 -0
  175. data/test/integration/navigation_test.rb +10 -0
  176. data/test/support/edgarj/controller_supporter.rb +23 -0
  177. data/test/test_helper.rb +23 -0
  178. data/test/unit/edgarj/model_permission_test.rb +27 -0
  179. data/test/unit/edgarj/page_info_test.rb +7 -0
  180. data/test/unit/edgarj/sssn_test.rb +10 -0
  181. data/test/unit/edgarj/user_group_test.rb +32 -0
  182. data/test/unit/edgarj/user_group_user_test.rb +9 -0
  183. data/test/unit/helpers/edgarj/model_permissions_helper_test.rb +6 -0
  184. data/test/unit/helpers/edgarj/user_group_users_helper_test.rb +6 -0
  185. metadata +456 -0
@@ -0,0 +1,255 @@
1
+ module Edgarj
2
+ # 'SearchForm' instance contains search-conditions entered at search-form as:
3
+ # 1. search conditions (mainly string, but integers for timestamp)
4
+ # for eash attribute of model
5
+ # 1. operator (=, <, >, ...) for each attribute
6
+ # 1. parent name for redraw
7
+ #
8
+ # Model(ActiveRecord) intance itself (e.g. Customer.new) doesn't satisfy to keep
9
+ # search condition because:
10
+ #
11
+ # 1. id cannot be set because of protection.
12
+ # 1. search condition may have operator (like '=', '>=')
13
+ #
14
+ # This is why SearchForm class is created.
15
+ #
16
+ # NOTE: model is stored in SearhForm as model_str.constantize to avoid following error:
17
+ # ArgumentError (undefined class/module Customer)
18
+ #
19
+ # === Operator
20
+ # Operator for some search-fields (e.g. integer, date) are initialized
21
+ # by params[:edgarj_search_form_operator]. For example, when search condition
22
+ # for Question screen GUI is:
23
+ #
24
+ # Priority < 3
25
+ #
26
+ # then, params[:search] is:
27
+ #
28
+ # :priority=>3, :search_form_operator=>{:priority=>'<'}
29
+ #
30
+ # and SearchForm object is built as:
31
+ #
32
+ # s = SearchForm.new(Question, params[:search])
33
+ #
34
+ # and finally it generates SQL condition as follows:
35
+ #
36
+ # s.conditions # ["priority<?", 3]
37
+ #
38
+ # === Parent name
39
+ # In order to hold parent object 'name' value for redraw, _parent[] hash is
40
+ # used. It is passed from params[:search_form_parent].
41
+ #
42
+ # === BUGS
43
+ # date-type(e.g. 'created_at(1i)'=2010, 'created_at(2i)'=2, ...) and
44
+ # datetime-type are not supported now while jQuery datepicker is OK.
45
+ #
46
+ class SearchForm < Edgarj::Search
47
+ attr_accessor :_operator, :_parent
48
+ validate :validate_data_type
49
+
50
+ module Dbms
51
+ MYSQL = 1
52
+ ELSE = 99
53
+ end
54
+
55
+ # Store comparison-operator for each search field
56
+ class Operator
57
+ # required at 'fields_for' helper
58
+ extend ActiveModel::Naming
59
+ extend ActiveModel::Conversion
60
+
61
+ ALLOWED = HashWithIndifferentAccess.new.tap do |a|
62
+ %w(= <> > >= < <=).each do |op|
63
+ a[op] = true
64
+ end
65
+ end
66
+
67
+ # accepts only allowed operators to avoid SQL injection
68
+ def initialize(attrs = {})
69
+ @attrs = HashWithIndifferentAccess.new
70
+
71
+ for k, v in (attrs || {}) do
72
+ if ALLOWED[v]
73
+ @attrs[k] = v
74
+ end
75
+ end
76
+ end
77
+
78
+ # generate a part of expression like '=?', ' in(?)', etc.
79
+ #
80
+ # When operator contains place-holder '?', it is not appended.
81
+ def exp(attr)
82
+ if @attrs[attr]
83
+ if @attrs[attr].index('?')
84
+ @attrs[attr]
85
+ else
86
+ @attrs[attr] + '?'
87
+ end
88
+ else
89
+ '=?'
90
+ end
91
+ end
92
+
93
+ def method_missing(method_name, *args)
94
+ @attrs[method_name.to_sym]
95
+ end
96
+ end
97
+
98
+ # Build SearchForm object from ActiveRecord 'klass' and attrs.
99
+ #
100
+ # === INPUTS
101
+ # klass:: ActiveRecord
102
+ # attrs:: hash of key=>value pair
103
+ def initialize(klass, attrs={})
104
+ super(klass)
105
+ @_table_name = klass.table_name
106
+ @attrs = attrs.dup
107
+ @_operator = Operator.new(attrs[:edgarj_search_form_operator])
108
+ @_parent = attrs[:search_form_parent]
109
+ end
110
+
111
+ # map attribute name to hash entry.
112
+ # This mechanism is required to be used in 'form_for' helper.
113
+ #
114
+ # When column type is integer and has digits value, return integer.
115
+ # This is required for selection helper.
116
+ # Even it is integer but has no value, keeps blank.
117
+ #
118
+ # When attribute name ends '=', assignment to hash works.
119
+ #
120
+ # === EXAMPLE
121
+ # s = Searchform.new(Product, :name=>'a')
122
+ # s.name
123
+ # s.conditions # ["name=?", "a"]
124
+ # s.name = 'b' # method_missing('name=', 'b') is called
125
+ # s.conditions # ["name=?", "b"]
126
+ #
127
+ def method_missing(method_name, *args)
128
+ if method_name.to_s =~ /^(.*)=$/
129
+ @attrs[$1.to_sym] = args[0]
130
+ else
131
+ val = @attrs[method_name.to_sym]
132
+ case column_type(method_name)
133
+ when :integer
134
+ if val =~ /^\d+$/
135
+ val.to_i
136
+ else
137
+ val
138
+ end
139
+ else
140
+ val
141
+ end
142
+ end
143
+ end
144
+
145
+ DEFAULT_TIMEZONE_FOR_TIMESTAMP_DATE_COMPARISON = '9'
146
+
147
+ # Generate search-conditions.
148
+ # Wildcard search by '*' is supported on string attribute.
149
+ #
150
+ # === RETURN
151
+ # condition_string, value_array:: values for :conditions option on model
152
+ def conditions
153
+ return ['1=0'] if !valid?
154
+
155
+ conds = []
156
+ values = []
157
+ for col in @_klass_str.constantize.columns do
158
+ col_str = col_name(col)
159
+ val = @attrs[encode_name(col)]
160
+ if !val.blank?
161
+ case col.type
162
+ when :string, :text
163
+ if val =~ /\*$/
164
+ conds << col_str + ' like ?'
165
+ values << val.gsub(/\*$/, '%')
166
+ else
167
+ conds << col_str + '=?'
168
+ values << val
169
+ end
170
+ when :datetime
171
+ case is_dbms?
172
+ when Dbms::MYSQL
173
+ # conds << col_str + @_operator.exp(encode_name(col))
174
+ conds << sprintf("date(%s)",
175
+ col_str) +
176
+ @_operator.exp(encode_name(col))
177
+ else
178
+ conds << sprintf("date(timezone('%s',%s))",
179
+ DEFAULT_TIMEZONE_FOR_TIMESTAMP_DATE_COMPARISON,
180
+ col_str) +
181
+ @_operator.exp(encode_name(col))
182
+ end
183
+ values << val.to_s
184
+ when :boolean
185
+ case is_dbms?
186
+ when Dbms::MYSQL
187
+ conds << col_str + @_operator.exp(encode_name(col))
188
+ values << (val=='true')
189
+ else
190
+ conds << col_str + @_operator.exp(encode_name(col))
191
+ values << val
192
+ end
193
+ else
194
+ conds << col_str + @_operator.exp(encode_name(col))
195
+ values << val
196
+ end
197
+ end
198
+ end
199
+ return [conds.join(' and ')] + values
200
+ end
201
+
202
+ private
203
+ def is_dbms?
204
+ @is_dbms ||=
205
+ if (Edgarj::Sssn.connection.class.to_s =~ /mysql/i)
206
+ Dbms::MYSQL
207
+ else
208
+ Dbms::ELSE
209
+ end
210
+ end
211
+
212
+ # 'rec.id' is unintentionally interpreted as Object.id rather than
213
+ # rec.attrs['id'] so encode it to _id.
214
+ #
215
+ # 'rec.type' has the same issue so to _type.
216
+ #
217
+ # === SEE ALSO
218
+ # decode_name()
219
+ def encode_name(col)
220
+ if col.name == 'id'
221
+ :_id
222
+ elsif col.name == 'type'
223
+ :_type
224
+ else
225
+ col.name.to_sym
226
+ end
227
+ end
228
+
229
+ #
230
+ # === SEE ALSO
231
+ # encode_name()
232
+ def decode_name(col)
233
+ end
234
+
235
+ # generate full-qualified column name. Example: authors.name
236
+ def col_name(col)
237
+ [@_table_name, col.name].join('.')
238
+ end
239
+
240
+ def validate_data_type
241
+ for col in @_klass_str.constantize.columns do
242
+ col_str = col_name(col)
243
+ encoded_col = encode_name(col)
244
+ val = @attrs[encoded_col]
245
+ case col.type
246
+ when :integer
247
+ if val.present? && val !~ /^[\d\.\-]+$/
248
+ errors.add(encoded_col, :not_an_integer)
249
+ end
250
+ else
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end
@@ -0,0 +1,44 @@
1
+ module Edgarj
2
+ # Search condition for popup
3
+ class SearchPopup < Search
4
+ attr_accessor :klass_str, :col, :val
5
+
6
+ validates_format_of :col, with: /\A[a-zA-Z_0-9\.]+\z/, allow_nil: true
7
+ validate :validate_integer
8
+
9
+ def initialize(klass, hash = nil)
10
+ super(klass)
11
+ @col = hash ? hash[:col] : nil
12
+ @val = hash ? hash[:val] : nil
13
+ end
14
+
15
+ # implement to generate search-conditions
16
+ def conditions
17
+ return ['1=0'] if !valid?
18
+
19
+ if @val.blank?
20
+ []
21
+ else
22
+ # FIXME: assume type is just string
23
+ op = '=?'
24
+ val = @val
25
+ if val =~ /\*$/
26
+ op = ' like ?'
27
+ val = @val.gsub(/\*/, '%')
28
+ end
29
+ ["#{@col}#{op}", val]
30
+ end
31
+ end
32
+
33
+ private
34
+ def validate_integer
35
+ case column_type(col)
36
+ when :integer
37
+ if val.present? && val !~ /^[\d\.\-]+$/
38
+ errors.add(:val, :not_an_integer)
39
+ end
40
+ else
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,120 @@
1
+ module Edgarj
2
+ # Edgarj specific session
3
+ #
4
+ # ActiveRecord::SessionStore::Session and Sssn are merged into Sssn because:
5
+ #
6
+ # * I could not find the way to build/prepare session for test;-(
7
+ # * It was verbose to Sync Sssn and Session.
8
+ #
9
+ # See ActiveRecord::SessionStore how to do that.
10
+ class Sssn < ActiveRecord::Base
11
+ self.table_name = 'edgarj_sssns'
12
+
13
+ #has_many :cart_items, dependent: :destroy
14
+ #has_many :album_slide_shows, dependent: :destroy,
15
+ # :class_name=>'Album::SlideShow'
16
+ belongs_to :user
17
+ has_many :page_infos, dependent: :destroy, autosave: true
18
+
19
+ #-----------------------------------------
20
+ # implementation section required by Rails
21
+ #-----------------------------------------
22
+
23
+ before_save :marshal_data!
24
+ before_save :raise_on_session_data_overflow!
25
+
26
+ class << self
27
+ def data_column_size_limit
28
+ @data_column_size_limit ||= columns_hash['data'].limit
29
+ end
30
+
31
+ def find_by_session_id(session_id)
32
+ where(session_id: session_id).first
33
+ end
34
+
35
+ def marshal(data)
36
+ Base64.encode64(Marshal.dump(data)) if data
37
+ end
38
+
39
+ def unmarshal(data)
40
+ Marshal.load(Base64.decode64(data)) if data
41
+ end
42
+ end
43
+
44
+ =begin
45
+ def initialize(attributes = nil)
46
+ @data = nil
47
+ super
48
+ end
49
+ =end
50
+
51
+ # Lazy-unmarshal session state.
52
+ def data
53
+ @data ||= self.class.unmarshal(read_attribute('data')) || {}
54
+ end
55
+
56
+ attr_writer :data
57
+
58
+ # Has the session been loaded yet?
59
+ def loaded?
60
+ !!@data
61
+ end
62
+
63
+ private
64
+ def marshal_data!
65
+ return false unless loaded?
66
+ write_attribute('data', self.class.marshal(data))
67
+ end
68
+
69
+ # Ensures that the data about to be stored in the database is not
70
+ # larger than the data storage column. Raises
71
+ # ActionController::SessionOverflowError.
72
+ def raise_on_session_data_overflow!
73
+ return false unless loaded?
74
+ limit = self.class.data_column_size_limit
75
+ if limit and read_attribute('data').size > limit
76
+ raise ActionController::SessionOverflowError
77
+ end
78
+ end
79
+
80
+ #---------------------------------------------
81
+ # End implementation section required by Rails
82
+ #---------------------------------------------
83
+
84
+ public
85
+ # delete stale sessions no longer active than SESSION_TIME_OUT minutes ago
86
+ #
87
+ # === INPUTS
88
+ # dry_run:: dry-run mode (default = true)
89
+ #
90
+ def self.delete_stale_sessions(dry_run=true)
91
+ self.transaction do
92
+ for s in Sssn.all(
93
+ :conditions=>['updated_at<?', Edgarj::BaseConfig::SESSION_TIME_OUT.minutes.ago.utc]) do
94
+ begin
95
+ session_id = s.session_id
96
+ s.destroy
97
+ logger.info("deleting session(#{session_id})")
98
+ rescue ActiveRecord::RecordNotFound => ex
99
+ logger.warn("session not found(#{session_id})")
100
+ end
101
+ end
102
+ raise ActiveRecord::Rollback if dry_run
103
+ end
104
+ end
105
+
106
+ def name
107
+ user.name + ' session'
108
+ end
109
+
110
+ def before_destroy
111
+ if Edgarj::Login::ENABLE_LOGGING
112
+ a = ActionEntry.new
113
+ a.user = self.user
114
+ a.action = Action::Login.new(:kind=>Action::Login::Kind::LOGOUT)
115
+ a.save!
116
+ end
117
+ true
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,67 @@
1
+ # UserGroup can be used for several types of user group like the followings:
2
+ #
3
+ # * user organization
4
+ # * user role
5
+ module Edgarj
6
+ class UserGroup < ActiveRecord::Base
7
+ self.table_name = 'edgarj_user_groups'
8
+
9
+ acts_as_nested_set scope: :kind
10
+
11
+ has_many :user_group_users, dependent: :destroy
12
+ has_many :users, through: :user_group_users
13
+ has_many :model_permissions, dependent: :destroy
14
+
15
+ # 'Kind' value is to identify what kind of user-group many-to-many
16
+ # relation is established. Following two values are reserved:
17
+ #
18
+ # ROLE:: controller-permission
19
+ # USER_ORG:: organization of users
20
+ #
21
+ # Any uniq value can be added for application usage. One example
22
+ # is in test/dummy/app/decorators/models/edgarj/user_group_decorator.rb
23
+ module Kind
24
+ ROLE = 100
25
+ USER_ORG = 200
26
+ end
27
+
28
+ def validate
29
+ super
30
+ validate_tree_kind
31
+ end
32
+
33
+ # return true if the role has enough permission on the controller.
34
+ #
35
+ # If user role is 'admin' then all operations are permitted.
36
+ #
37
+ # Always return false if the user-group is not ROLE.
38
+ #
39
+ # if requested_flags is omitted, just checks existence of
40
+ # model_permissions and doesn't check CRUD level.
41
+ def permitted?(model_name, requested_flags = 0)
42
+ return false if self.kind != Kind::ROLE
43
+ return true if admin?
44
+
45
+ p = self.model_permissions.find_by_model(model_name)
46
+ if requested_flags == 0
47
+ p
48
+ else
49
+ p && p.permitted?(requested_flags)
50
+ end
51
+ end
52
+
53
+ def admin?
54
+ self.kind == Kind::ROLE && name == 'admin'
55
+ end
56
+
57
+ private
58
+ # USER_ORG's parent must be USER_ORG
59
+ def validate_tree_kind
60
+ if parent_id
61
+ if kind != parent.kind
62
+ err_on(:kind, 'different_kind_from_parent')
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,18 @@
1
+ # UserGroup - User intersection model
2
+ #
3
+ module Edgarj
4
+ class UserGroupUser < ActiveRecord::Base
5
+ self.table_name = 'edgarj_user_group_users'
6
+
7
+ belongs_to :user_group
8
+ belongs_to :user
9
+
10
+ validates_presence_of :user_group_id
11
+ validates_presence_of :user_id
12
+ validates_uniqueness_of :user_id, :scope=>:user_group_id
13
+
14
+ def name
15
+ self.user.name + ' of ' + self.user_group.name
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ module Edgarj
2
+ def self.table_name_prefix
3
+ 'edgarj_'
4
+ end
5
+ end
@@ -0,0 +1,25 @@
1
+ <%#
2
+ Form for record detail
3
+
4
+ = INPUTS
5
+
6
+ @drawer:: drawer instance
7
+ @record:: form value
8
+
9
+ = SEE ALSO
10
+
11
+ _search_form.htm.erb:: search form
12
+ %>
13
+ <div id=edgarj_form>
14
+ <% if @record.errors.any? %>
15
+ <div class="error_explanation">
16
+ <h2><%= t('error.form.title', count: @record.errors.count) %></h2>
17
+ <ul>
18
+ <% @record.errors.full_messages.each do |msg| %>
19
+ <li><%= msg %></li>
20
+ <% end %>
21
+ </ul>
22
+ </div>
23
+ <% end %>
24
+ <%= @drawer.draw_form(@record) %>
25
+ </div>
@@ -0,0 +1,52 @@
1
+ <%#
2
+ = INPUTS
3
+
4
+ @list:: model instance list
5
+ @count:: model instance list count
6
+ @page_info:: page_info instance
7
+ %>
8
+ <div id=edgarj_list> <!-- edgarj/_list.html.erb -->
9
+ <table width="100%">
10
+ <tr>
11
+ <td><%= t('edgarj.default.total_records') % @count %></td>
12
+ <td>
13
+ <%= paginate @list,
14
+ remote: true,
15
+ params: {action: 'index'} %>
16
+ </td>
17
+ <td align=right>
18
+ <%=
19
+ form_for(@page_info,
20
+ remote: true,
21
+ url: {action: 'page_info_save', id: @page_info.id,
22
+ controller: params[:controller]},
23
+ html: {id: 'edgarj_form_lines_per_page', method: :put}
24
+ ) do |f| %>
25
+ <%= f.select('lines', Edgarj::LINES_PER_PAGE.map{|x| [x,x]}) %>
26
+ <%= v('records_per_page') %>
27
+ <% end %>
28
+ </td>
29
+ <td>
30
+ <%= button_to v('csv_download'), {
31
+ controller: params[:controller],
32
+ action: 'csv_download'},
33
+ {method: :get} %>
34
+ </td>
35
+ </tr>
36
+ </table>
37
+ <%= drawer.draw_list(@list) %>
38
+
39
+ <%= javascript_tag do %>
40
+ $(function(){
41
+ /* action on changing records/page at the selection in list */
42
+ $('#edgarj_page_info_lines').change(function(){
43
+ $("#edgarj_form_lines_per_page").trigger("submit.rails");
44
+ });
45
+
46
+ /* show detail on clicking a list row */
47
+ $('._edgarj_list_column').click(function(){
48
+ $.ajax($(this).attr('data-url'));
49
+ });
50
+ });
51
+ <% end %>
52
+ </div>
@@ -0,0 +1,15 @@
1
+ <!-- edgarj/_message_popup.html.erb -->
2
+ <%#
3
+ message popup template.
4
+ %>
5
+
6
+ <center>
7
+ <div id=edgarj_message_error ><%= flash[:error] || '' %></div>
8
+ <div id=edgarj_message_notice><%= flash[:notice] || '' %></div>
9
+ <hr>
10
+ <%= button_tag t('close'),
11
+ type: 'button',
12
+ id: 'edgarj_message_popup_close',
13
+ onClick: "$('#edgarj_message_popup').dialog('close');"
14
+ %>
15
+ </center>
@@ -0,0 +1,64 @@
1
+ <%#
2
+ Form for search condition.
3
+
4
+ = INPUTS
5
+
6
+ @drawer:: Edgarj::Drawer::Normal object
7
+ @search:: form value
8
+ @notice:: notice message
9
+ @error:: error message
10
+
11
+ = SEE ALSO
12
+
13
+ _form.html.erb:: record form
14
+ %>
15
+
16
+ <div id=edgarj_search_form> <!-- edgarj/_search_form.html.erb -->
17
+ <% if @search.errors.any? %>
18
+ <div class="error_explanation">
19
+ <h2><%= t('error.search_form.title', count: @search.errors.count) %></h2>
20
+ <ul>
21
+ <% @search.errors.full_messages.each do |msg| %>
22
+ <li><%= msg %></li>
23
+ <% end %>
24
+ </ul>
25
+ </div>
26
+ <% end %>
27
+ <%= form_for(@search, url: {action: 'search'}, html: {
28
+ id: '_edgarj_search_form',
29
+ remote: true,
30
+ method: :get}) do |f| %>
31
+ <%= f.fields_for(@search._operator) do |o| %>
32
+ <%= Edgarj::FormDrawer::Search.new(@drawer, @search, f, o).draw() %>
33
+ <%# to avoid submit on 1-textfield form when hit [ENTER] key: %>
34
+ <input type="text" name="dummy" style="visibility:hidden" size=0>
35
+ <% end %>
36
+ <% end %>
37
+ <%= draw_search_form_buttons %>
38
+
39
+ <%= javascript_tag do %>
40
+ <% id = 'edgarj_search_operator_selection' %>
41
+ $('div.search_operator').contextMenu('<%= id -%>', {
42
+ bindings: {
43
+ '<%= id + '_eq' %>': function(target){
44
+ Edgarj.OperatorSelection.on_select(target, '=');
45
+ },
46
+ '<%= id + '_ne' %>': function(target){
47
+ Edgarj.OperatorSelection.on_select(target, '<>');
48
+ },
49
+ '<%= id + '_gt' %>': function(target){
50
+ Edgarj.OperatorSelection.on_select(target, '>');
51
+ },
52
+ '<%= id + '_ge' %>': function(target){
53
+ Edgarj.OperatorSelection.on_select(target, '>=');
54
+ },
55
+ '<%= id + '_lt' %>': function(target){
56
+ Edgarj.OperatorSelection.on_select(target, '<');
57
+ },
58
+ '<%= id + '_le' %>': function(target){
59
+ Edgarj.OperatorSelection.on_select(target, '<=');
60
+ },
61
+ }
62
+ });
63
+ <% end %>
64
+ </div>
@@ -0,0 +1,17 @@
1
+ <%#
2
+ Template for search_operator() helper.
3
+
4
+ === INPUTS
5
+ o:: operator form builder
6
+ method:: attribute name of the object
7
+ %>
8
+
9
+ <%
10
+ name = "edgarj_search_form[edgarj_search_form_operator][#{method.to_s}]"
11
+ id = name.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")
12
+ op = o.object.send(method).blank? ? '=' : o.object.send(method)
13
+ %>
14
+ <div id='<%= id + "_label" -%>' class='search_operator'>
15
+ <%= h(op) %>
16
+ </div>
17
+ <%= o.hidden_field method %>