edgarj 0.01.12

Sign up to get free protection for your applications and to get access to all the features.
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 %>