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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +23 -0
- data/Rakefile +40 -0
- data/app/assets/javascripts/edgarj/base.js +49 -0
- data/app/assets/javascripts/edgarj/menu.js +39 -0
- data/app/assets/javascripts/edgarj/operator_selection.js +133 -0
- data/app/assets/stylesheets/edgarj/base.css +304 -0
- data/app/assets/stylesheets/edgarj/menu.css +65 -0
- data/app/controllers/edgarj/authentication_mixin.rb.sample +30 -0
- data/app/controllers/edgarj/controller_mixin_common.rb +80 -0
- data/app/controllers/edgarj/controller_mixin_for_app.rb +71 -0
- data/app/controllers/edgarj/edgarj_controller.rb +535 -0
- data/app/controllers/edgarj/model_permissions_controller.rb +8 -0
- data/app/controllers/edgarj/permission_mixin.rb +84 -0
- data/app/controllers/edgarj/popup_controller.rb +128 -0
- data/app/controllers/edgarj/rescue_mixin.rb +37 -0
- data/app/controllers/edgarj/user_group_users_controller.rb +8 -0
- data/app/controllers/edgarj/user_groups_controller.rb +9 -0
- data/app/controllers/edgarj/user_groups_popup_controller.rb +8 -0
- data/app/helpers/edgarj/assoc_helper.rb +369 -0
- data/app/helpers/edgarj/common_helper.rb +37 -0
- data/app/helpers/edgarj/edgarj_helper.rb +20 -0
- data/app/helpers/edgarj/field_helper.rb +397 -0
- data/app/helpers/edgarj/form_drawer.rb +322 -0
- data/app/helpers/edgarj/list_drawer.rb +169 -0
- data/app/helpers/edgarj/menu_helper.rb +92 -0
- data/app/helpers/edgarj/model_permissions_helper.rb +9 -0
- data/app/helpers/edgarj/popup_helper.rb +40 -0
- data/app/helpers/edgarj/search_helper.rb +14 -0
- data/app/helpers/edgarj/sessions_helper.rb +9 -0
- data/app/helpers/edgarj/user_group_users_helper.rb +9 -0
- data/app/helpers/edgarj/user_groups_helper.rb +9 -0
- data/app/helpers/edgarj/user_groups_popup_helper.rb +9 -0
- data/app/models/edgarj/drawer/base.rb +234 -0
- data/app/models/edgarj/drawer/normal.rb +6 -0
- data/app/models/edgarj/drawer/popup.rb +47 -0
- data/app/models/edgarj/drawer.rb +13 -0
- data/app/models/edgarj/model_permission.rb +41 -0
- data/app/models/edgarj/page_info.rb +47 -0
- data/app/models/edgarj/search.rb +81 -0
- data/app/models/edgarj/search_form.rb +255 -0
- data/app/models/edgarj/search_popup.rb +44 -0
- data/app/models/edgarj/sssn.rb +120 -0
- data/app/models/edgarj/user_group.rb +67 -0
- data/app/models/edgarj/user_group_user.rb +18 -0
- data/app/models/edgarj.rb +5 -0
- data/app/views/edgarj/edgarj/_form.html.erb +25 -0
- data/app/views/edgarj/edgarj/_list.html.erb +52 -0
- data/app/views/edgarj/edgarj/_message_popup.html.erb +15 -0
- data/app/views/edgarj/edgarj/_search_form.html.erb +64 -0
- data/app/views/edgarj/edgarj/_search_operator.html.erb +17 -0
- data/app/views/edgarj/edgarj/_search_operator_selection.html.erb +12 -0
- data/app/views/edgarj/edgarj/clear.js.erb +1 -0
- data/app/views/edgarj/edgarj/create.js.erb +4 -0
- data/app/views/edgarj/edgarj/destroy.js.erb +2 -0
- data/app/views/edgarj/edgarj/index.html.erb +37 -0
- data/app/views/edgarj/edgarj/index.js.erb +1 -0
- data/app/views/edgarj/edgarj/message_popup.js.erb +3 -0
- data/app/views/edgarj/edgarj/page_info_save.js.erb +1 -0
- data/app/views/edgarj/edgarj/search.js.erb +4 -0
- data/app/views/edgarj/edgarj/search_clear.js.erb +1 -0
- data/app/views/edgarj/edgarj/show.js.erb +1 -0
- data/app/views/edgarj/edgarj/top.html.erb +4 -0
- data/app/views/edgarj/edgarj/update.js.erb +4 -0
- data/app/views/edgarj/popup/_index.html.erb +16 -0
- data/app/views/edgarj/popup/_list.html.erb +42 -0
- data/app/views/edgarj/popup/_message_popup.html.erb +15 -0
- data/app/views/edgarj/popup/_search.html.erb +42 -0
- data/app/views/edgarj/popup/_search_save_popup.html.erb +16 -0
- data/app/views/edgarj/popup/index.js.erb +5 -0
- data/app/views/edgarj/popup/message_popup.js.erb +3 -0
- data/app/views/edgarj/popup/page_info_save.js.erb +1 -0
- data/app/views/edgarj/popup/search.js.erb +15 -0
- data/app/views/edgarj/popup/view_status_save.js.erb +1 -0
- data/config/routes.rb +15 -0
- data/config/settings.yml +5 -0
- data/db/migrate/20131118084600_create_edgar_sssns.rb +14 -0
- data/db/migrate/20131123124730_create_edgar_page_infos.rb +15 -0
- data/db/migrate/20140116062252_create_edgar_user_groups.rb +18 -0
- data/db/migrate/20140116062327_create_edgar_user_group_users.rb +10 -0
- data/db/migrate/20140206222308_create_edgar_model_permissions.rb +14 -0
- data/db/migrate/20141209053055_rename_edgar_to_edgarj.rb +17 -0
- data/lib/core_ext/active_record.rb +123 -0
- data/lib/core_ext/resources.rb +71 -0
- data/lib/edgarj/engine.rb +64 -0
- data/lib/edgarj/enum_cache.rb +46 -0
- data/lib/edgarj/templates/rails/helper/helper.rb +10 -0
- data/lib/edgarj/templates/test_unit/scaffold/functional_test.rb +575 -0
- data/lib/edgarj/version.rb +3 -0
- data/lib/edgarj.rb +14 -0
- data/lib/generators/edgarj/popup_scaffold/USAGE +6 -0
- data/lib/generators/edgarj/popup_scaffold/popup_scaffold_generator.rb +35 -0
- data/lib/generators/edgarj/popup_scaffold/templates/controller.rb +13 -0
- data/lib/generators/edgarj/popup_scaffold/templates/functional_test.rb +197 -0
- data/lib/generators/edgarj/popup_scaffold/templates/helper.rb +9 -0
- data/lib/generators/edgarj/scaffold/USAGE +17 -0
- data/lib/generators/edgarj/scaffold/scaffold_generator.rb +40 -0
- data/lib/generators/edgarj/scaffold/templates/controller.rb +13 -0
- data/lib/tasks/edgarj_tasks.rake +32 -0
- data/lib/tasks/pakcage.rake +18 -0
- data/locale/en.yml +94 -0
- data/locale/ja.yml +100 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +21 -0
- data/test/dummy/app/assets/javascripts/authors.js +2 -0
- data/test/dummy/app/assets/stylesheets/application.css +16 -0
- data/test/dummy/app/assets/stylesheets/authors.css +4 -0
- data/test/dummy/app/assets/stylesheets/scaffold.css +56 -0
- data/test/dummy/app/controllers/application_controller.rb +15 -0
- data/test/dummy/app/controllers/authors_controller.rb +6 -0
- data/test/dummy/app/controllers/authors_popup_controller.rb +6 -0
- data/test/dummy/app/controllers/books_controller.rb +6 -0
- data/test/dummy/app/controllers/dummy_auth_mixin.rb +36 -0
- data/test/dummy/app/decorators/models/edgarj/user_group_decorator.rb +1 -0
- data/test/dummy/app/helpers/application_helper.rb +3 -0
- data/test/dummy/app/helpers/authors_helper.rb +7 -0
- data/test/dummy/app/helpers/authors_popup_helper.rb +7 -0
- data/test/dummy/app/helpers/books_helper.rb +7 -0
- data/test/dummy/app/models/author.rb +32 -0
- data/test/dummy/app/models/book.rb +5 -0
- data/test/dummy/app/models/user.rb +13 -0
- data/test/dummy/app/views/layouts/application.html.erb +32 -0
- data/test/dummy/app/views/layouts/login.html.erb +20 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config/application.rb +59 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +15 -0
- data/test/dummy/config/edgarj/menu_config.rb +28 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +42 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +34 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +12 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/strong_parameter.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +26 -0
- data/test/dummy/config/routes.rb +60 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/migrate/20131107120635_create_authors.rb +9 -0
- data/test/dummy/db/migrate/20131218011851_create_books.rb +10 -0
- data/test/dummy/db/migrate/20140201000000_add_user_group_id_to_authors.rb +5 -0
- data/test/dummy/db/migrate/20140807065420_create_users.rb +10 -0
- data/test/dummy/db/schema.rb +93 -0
- data/test/dummy/public/404.html +58 -0
- data/test/dummy/public/422.html +58 -0
- data/test/dummy/public/500.html +57 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/test/functional/authors_controller_test.rb +631 -0
- data/test/dummy/test/functional/books_controller_test.rb +516 -0
- data/test/dummy/test/helpers/authors_helper_test.rb +4 -0
- data/test/dummy/test/unit/author_test.rb +7 -0
- data/test/dummy/test/unit/book_test.rb +7 -0
- data/test/edgar_test.rb +7 -0
- data/test/fixtures/authors.yml +32 -0
- data/test/fixtures/books.yml +56 -0
- data/test/fixtures/edgarj/model_permissions.yml +97 -0
- data/test/fixtures/edgarj/page_infos.yml +84 -0
- data/test/fixtures/edgarj/sssns.yml +38 -0
- data/test/fixtures/edgarj/user_group_users.yml +114 -0
- data/test/fixtures/edgarj/user_groups.yml +95 -0
- data/test/fixtures/users.yml +49 -0
- data/test/functional/edgarj/edgarj_controller_test.rb +24 -0
- data/test/functional/edgarj/model_permissions_controller_test.rb +554 -0
- data/test/functional/edgarj/user_group_users_controller_test.rb +567 -0
- data/test/integration/navigation_test.rb +10 -0
- data/test/support/edgarj/controller_supporter.rb +23 -0
- data/test/test_helper.rb +23 -0
- data/test/unit/edgarj/model_permission_test.rb +27 -0
- data/test/unit/edgarj/page_info_test.rb +7 -0
- data/test/unit/edgarj/sssn_test.rb +10 -0
- data/test/unit/edgarj/user_group_test.rb +32 -0
- data/test/unit/edgarj/user_group_user_test.rb +9 -0
- data/test/unit/helpers/edgarj/model_permissions_helper_test.rb +6 -0
- data/test/unit/helpers/edgarj/user_group_users_helper_test.rb +6 -0
- metadata +456 -0
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
require 'csv'
|
|
2
|
+
|
|
3
|
+
module Edgarj
|
|
4
|
+
# Generic CRUD(Create/Read/Update/Delte) controller with Ajax.
|
|
5
|
+
#
|
|
6
|
+
# === EdgarjController v.s. ApplicationController
|
|
7
|
+
# When concreate controller (e.g. CustomersController) inherits
|
|
8
|
+
# EdgarjController, it has the following features:
|
|
9
|
+
#
|
|
10
|
+
# * CRUD with default form on Ajax
|
|
11
|
+
# * form can be customized.
|
|
12
|
+
# * QBE (Query By Example) search form
|
|
13
|
+
# * popup-selection on 'belongs_to' column
|
|
14
|
+
# * sort on list
|
|
15
|
+
# * saving search-conditions and reuse it
|
|
16
|
+
#
|
|
17
|
+
# If these are not necessary, just inherits ApplicationController.
|
|
18
|
+
#
|
|
19
|
+
# === Tasks when adding new model which is handled under EdgarjController
|
|
20
|
+
# For example, when want to add Post model:
|
|
21
|
+
# 1. generate edgarj:scaffold:
|
|
22
|
+
# rails generate edgarj:scaffold post name:string body:text published:boolean
|
|
23
|
+
# 2. add controller entry to CONTROLLER_MENU (config/initializers/edgarj.rb)
|
|
24
|
+
#
|
|
25
|
+
# It will take about ~3 min.
|
|
26
|
+
#
|
|
27
|
+
# For the detail of customization, please see:
|
|
28
|
+
# http://sourceforge.net/apps/trac/jjedgarj/wiki/customize
|
|
29
|
+
#
|
|
30
|
+
# === Architecture
|
|
31
|
+
# see {architecture}[link:../architecture.odp] (OpenOffice Presentation)
|
|
32
|
+
#
|
|
33
|
+
# === Access Control
|
|
34
|
+
# There are two dimentions of access control:
|
|
35
|
+
# 1. Page level (Controller level) access control.
|
|
36
|
+
# * Edgarj::UserGroup with kind==ROLE and Edgarj::ModelPermission
|
|
37
|
+
# represents access control on each controller.
|
|
38
|
+
# * Admin user, who belongs to 'admin' user_group, can access any page.
|
|
39
|
+
# * When a user belongs to a user_group (kind==ROLE) and
|
|
40
|
+
# a model_permission belongs to the user_group, the user can
|
|
41
|
+
# access the controller which model is the model in model_permission.
|
|
42
|
+
# * More precisely, 4 kind of access controls, CREATE,
|
|
43
|
+
# READ, UPDATE, and DELETE can be set with any conbination on the
|
|
44
|
+
# controller.
|
|
45
|
+
# * See Edgarj::ModelPermission for more detail.
|
|
46
|
+
# 1. Data scope.
|
|
47
|
+
# * data scope access is controlled by 'user_scoped(user, context)'
|
|
48
|
+
# scope defined at each model.
|
|
49
|
+
# * Where, user is currently accessing person to the model.
|
|
50
|
+
# * context is any kind of 2nd parameter. Default is session object of
|
|
51
|
+
# Edgarj::Sssn, but it can be overwritten 'scope_context' method
|
|
52
|
+
# at the target controller.
|
|
53
|
+
# * See Author.user_scoped as an example.
|
|
54
|
+
#
|
|
55
|
+
# == Naming Convention
|
|
56
|
+
#
|
|
57
|
+
# * 'record' is an instance of 'Model'.
|
|
58
|
+
# * 'drawer' is an instance of 'Drawer' class.
|
|
59
|
+
#
|
|
60
|
+
# === Implementation Note
|
|
61
|
+
# Why not to choose mixin rather than class is because
|
|
62
|
+
# it is easier to use edgarj's view at client controller. For example,
|
|
63
|
+
# AuthorsController, which inherits from EdgarjController, can
|
|
64
|
+
# automatically use edgarj's view by rails view-selection feature.
|
|
65
|
+
#
|
|
66
|
+
# === SEE ALSO
|
|
67
|
+
# PopupController:: 'belongs_to' popup for EdgarjController
|
|
68
|
+
#
|
|
69
|
+
class EdgarjController < ApplicationController
|
|
70
|
+
include ControllerMixinCommon
|
|
71
|
+
include PermissionMixin
|
|
72
|
+
#include TopicPathControllerMixin
|
|
73
|
+
|
|
74
|
+
helper_method :model, :model_name, :drawer,
|
|
75
|
+
:draw_flash, :csv_proc
|
|
76
|
+
|
|
77
|
+
READ_ACTIONS = %w(
|
|
78
|
+
index show clear search search_clear search_save search_load
|
|
79
|
+
zip_complete csv_download file_download map page_info_save)
|
|
80
|
+
|
|
81
|
+
before_filter :require_create_permission, only: :create
|
|
82
|
+
before_filter :require_read_permission, only: READ_ACTIONS
|
|
83
|
+
before_filter :require_update_permission, only: :update
|
|
84
|
+
before_filter :require_delete_permission, only: :destroy
|
|
85
|
+
before_filter :require_other_permission, except: READ_ACTIONS + %w(
|
|
86
|
+
create update destroy top)
|
|
87
|
+
#after_filter :log_topic_path
|
|
88
|
+
after_filter :enum_cache_stat
|
|
89
|
+
|
|
90
|
+
# This page is for following purposes:
|
|
91
|
+
#
|
|
92
|
+
# * top page which contain latest info (TBD)
|
|
93
|
+
# * any error message on HTML format access
|
|
94
|
+
# * on Ajax access, rather edgarj_error_popup is used
|
|
95
|
+
def top
|
|
96
|
+
render :action => 'top'
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# draw search result in whole page.
|
|
100
|
+
# default update DOM id and template is as follows:
|
|
101
|
+
#
|
|
102
|
+
# DOM id:: 'edgarj_list'
|
|
103
|
+
# template:: 'edgarj/list'
|
|
104
|
+
#
|
|
105
|
+
# However, these can be replaced by params[:update] and params[:template]
|
|
106
|
+
#
|
|
107
|
+
# === Permission
|
|
108
|
+
# ModelPermission::READ on this controller is required.
|
|
109
|
+
#
|
|
110
|
+
# === SEE ALSO
|
|
111
|
+
# popup():: draw popup
|
|
112
|
+
def index
|
|
113
|
+
page_info
|
|
114
|
+
|
|
115
|
+
# update @page_info.page when page is specified.
|
|
116
|
+
# Otherwise, reset page to 1.
|
|
117
|
+
#
|
|
118
|
+
# Just set, not save. It will be done later when saving sssn with
|
|
119
|
+
# 'has_many page_infos ... autosave: true'
|
|
120
|
+
@page_info.page = (params[:page] || 1)
|
|
121
|
+
|
|
122
|
+
#clear_topic_path
|
|
123
|
+
prepare_list
|
|
124
|
+
|
|
125
|
+
@search = page_info.record
|
|
126
|
+
@record = model.new
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# save new record
|
|
130
|
+
#
|
|
131
|
+
# === Permission
|
|
132
|
+
# ModelPermission::CREATE on this controller is required.
|
|
133
|
+
#
|
|
134
|
+
def create
|
|
135
|
+
upsert do
|
|
136
|
+
# NOTE: create!() is not used because assign to @record to draw form.
|
|
137
|
+
# Otherwise, @record would be in nil so failure at edgarj/_form rendering.
|
|
138
|
+
#
|
|
139
|
+
# NOTE2: valid? after create() calls validate_on_update. This is not
|
|
140
|
+
# an expected behavior. So, new, valid?, then save.
|
|
141
|
+
@record = model.new(permitted_params(:create))
|
|
142
|
+
on_upsert
|
|
143
|
+
#upsert_files
|
|
144
|
+
raise ActiveRecord::RecordNotSaved if !@record.valid?
|
|
145
|
+
@record.save
|
|
146
|
+
|
|
147
|
+
# clear @record values for next data-entry
|
|
148
|
+
@record = model.new
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Show detail of one record. Format of html & js should be supported.
|
|
153
|
+
#
|
|
154
|
+
# === Permission
|
|
155
|
+
# ModelPermission::READ on this controller is required.
|
|
156
|
+
#
|
|
157
|
+
def show
|
|
158
|
+
@record = user_scoped.find(params[:id])
|
|
159
|
+
#add_topic_path
|
|
160
|
+
respond_to do |format|
|
|
161
|
+
format.html {
|
|
162
|
+
prepare_list
|
|
163
|
+
@search = page_info.record
|
|
164
|
+
render :action=>'index'
|
|
165
|
+
}
|
|
166
|
+
format.js
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# save existence modified record
|
|
171
|
+
#
|
|
172
|
+
# === Permission
|
|
173
|
+
# ModelPermission::UPDATE on this controller is required.
|
|
174
|
+
#
|
|
175
|
+
def update
|
|
176
|
+
upsert do
|
|
177
|
+
# NOTE:
|
|
178
|
+
# 1. update ++then++ valid to set new values in @record to draw form.
|
|
179
|
+
# 1. user_scoped may have joins so that record could be
|
|
180
|
+
# ActiveRecord::ReadOnlyRecord so that's why access again from
|
|
181
|
+
# model.
|
|
182
|
+
@record = model.find(user_scoped.find(params[:id]).id)
|
|
183
|
+
#upsert_files
|
|
184
|
+
if !@record.update_attributes(permitted_params(:update))
|
|
185
|
+
raise ActiveRecord::RecordInvalid.new(@record)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# === Permission
|
|
191
|
+
# ModelPermission::DELETE on this controller is required.
|
|
192
|
+
def destroy
|
|
193
|
+
m = model.find(user_scoped.find(params[:id]).id)
|
|
194
|
+
m.destroy
|
|
195
|
+
|
|
196
|
+
prepare_list
|
|
197
|
+
@record = model.new
|
|
198
|
+
@flash_notice = t('delete_ok')
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Ajax method to clear form
|
|
202
|
+
#
|
|
203
|
+
# === Permission
|
|
204
|
+
# ModelPermission::READ on this controller is required.
|
|
205
|
+
#
|
|
206
|
+
def clear
|
|
207
|
+
@record = model.new
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Ajax method to execute search
|
|
211
|
+
#
|
|
212
|
+
# Actually, this doesn't execute search. Rather, this just saves
|
|
213
|
+
# condition. Search will be executed at any listing action
|
|
214
|
+
# like 'index', 'create', or 'update'.
|
|
215
|
+
#
|
|
216
|
+
# === Permission
|
|
217
|
+
# ModelPermission::READ on this controller is required.
|
|
218
|
+
#
|
|
219
|
+
def search
|
|
220
|
+
pi = page_info
|
|
221
|
+
pi.record = SearchForm.new(model, params[:edgarj_search_form])
|
|
222
|
+
pi.page = 1
|
|
223
|
+
pi.save!
|
|
224
|
+
@search = pi.record
|
|
225
|
+
prepare_list if @search.valid?
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Ajax method to clear search conditions
|
|
229
|
+
#
|
|
230
|
+
# === Permission
|
|
231
|
+
# ModelPermission::READ on this controller is required.
|
|
232
|
+
#
|
|
233
|
+
def search_clear
|
|
234
|
+
@search = SearchForm.new(model)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Ajax method to save search conditions
|
|
238
|
+
#
|
|
239
|
+
# === call flow
|
|
240
|
+
# Edgarj.SearchSavePopup.open() (javascript)
|
|
241
|
+
# (show $('search_save_popup'))
|
|
242
|
+
# Edgarj.SearchSavePopup.submit() (javascript)
|
|
243
|
+
# (copy entered name into $('saved_page_info_name') in form)
|
|
244
|
+
# call :action=>'search_save'
|
|
245
|
+
#
|
|
246
|
+
# ==== TRICKY PART
|
|
247
|
+
# There are two requirements:
|
|
248
|
+
# 1. use modal-dialog to enter name to decrese busy in search form.
|
|
249
|
+
# 1. send Search Form with name to server.
|
|
250
|
+
#
|
|
251
|
+
# To comply these, Edgarj.SearchSavePopup copies the entered name to
|
|
252
|
+
# 'saved_page_info_name' hidden field and then sends the form which includes
|
|
253
|
+
# the copied name.
|
|
254
|
+
#
|
|
255
|
+
# === Permission
|
|
256
|
+
# ModelPermission::READ on this controller is required.
|
|
257
|
+
#
|
|
258
|
+
def search_save
|
|
259
|
+
svc = SavedVcontext.save(current_user, nil,
|
|
260
|
+
params[:saved_page_info_name], page_info)
|
|
261
|
+
|
|
262
|
+
render :update do |page|
|
|
263
|
+
page << "Edgarj.SearchSavePopup.close();"
|
|
264
|
+
page.replace 'edgarj_load_condition_menu',
|
|
265
|
+
:partial=>'edgarj/load_condition_menu'
|
|
266
|
+
end
|
|
267
|
+
rescue ActiveRecord::ActiveRecordError => ex
|
|
268
|
+
app_rescue
|
|
269
|
+
render :update do |page|
|
|
270
|
+
page.replace_html 'search_save_popup_flash_error', :text=>t('save_fail')
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# Ajax method to load search condition, lines, order_by, dir, and page.
|
|
275
|
+
#
|
|
276
|
+
def search_load
|
|
277
|
+
@search = current_user.saved_page_infos.find(params[:id]).load(@sssn).model
|
|
278
|
+
draw_search_form
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# zip -> address completion
|
|
282
|
+
#
|
|
283
|
+
# === INPUTS
|
|
284
|
+
# params[:zip]:: key to find address info. hyphen is supported.
|
|
285
|
+
# params[:adrs_prefix]:: address fields DOM id prefix. e.g. 'org_adrs_0_'
|
|
286
|
+
#
|
|
287
|
+
# === call flow
|
|
288
|
+
# ==== on drawing
|
|
289
|
+
# EdgarjHelper.draw_adrs() app/helpers/edgarj_helper.rb
|
|
290
|
+
# app/views/edgarj/_address.html.erb
|
|
291
|
+
# Example:
|
|
292
|
+
# :
|
|
293
|
+
# <input type=text name='org[adrs_0_zip]'>
|
|
294
|
+
# :
|
|
295
|
+
#
|
|
296
|
+
# ==== on clicking zip->address button
|
|
297
|
+
# Edgarj.zip_complete() public/javascripts/edgarj.js
|
|
298
|
+
# Ajax.Request()
|
|
299
|
+
# EdgarjController.zip_complete app/controllers/edgarj_controller.rb
|
|
300
|
+
# inline RJS to fill address info
|
|
301
|
+
#
|
|
302
|
+
=begin
|
|
303
|
+
def zip_complete
|
|
304
|
+
zip = params[:zip].gsub(/\D/, '')
|
|
305
|
+
@address = ZipAddress.find_by_zip(zip) || ZipAddress.new(
|
|
306
|
+
:prefecture => '?',
|
|
307
|
+
:city => '',
|
|
308
|
+
:other => '')
|
|
309
|
+
|
|
310
|
+
# sanitize
|
|
311
|
+
@adrs_prefix = params[:adrs_prefix].gsub(/[^a-zA-Z_0-9]/, '')
|
|
312
|
+
end
|
|
313
|
+
=end
|
|
314
|
+
|
|
315
|
+
# download model under current condition
|
|
316
|
+
#
|
|
317
|
+
# <tt>respond_to...format.csv</tt> approach was not used since
|
|
318
|
+
# \@list is different as follows:
|
|
319
|
+
# * csv returns all of records under the conditions
|
|
320
|
+
# * HTML returns *just* in specified 'page'.
|
|
321
|
+
#
|
|
322
|
+
# === Permission
|
|
323
|
+
# ModelPermission::READ on this controller is required.
|
|
324
|
+
#
|
|
325
|
+
# FIXME: file.close(true) deletes files *BEFORE* actually send file
|
|
326
|
+
# so that comment it out. Need to clean these work files.
|
|
327
|
+
def csv_download
|
|
328
|
+
filename = sprintf("%s-%s.csv",
|
|
329
|
+
model_name,
|
|
330
|
+
Time.now.strftime("%Y%m%d-%H%M%S"))
|
|
331
|
+
file = Tempfile.new(filename, Settings.edgarj.csv_dir)
|
|
332
|
+
csv_visitor = EdgarjHelper::CsvVisitor.new(view_context)
|
|
333
|
+
cond = {:conditions=>page_info.record.conditions}
|
|
334
|
+
file.write CSV.generate_line(model.columns.map{|c| c.name})
|
|
335
|
+
for rec in user_scoped.where(page_info.record.conditions).
|
|
336
|
+
order(
|
|
337
|
+
page_info.order_by.blank? ?
|
|
338
|
+
nil :
|
|
339
|
+
page_info.order_by + ' ' + page_info.dir) do
|
|
340
|
+
array = []
|
|
341
|
+
for col in model.columns do
|
|
342
|
+
array << csv_visitor.visit_column(rec, col)
|
|
343
|
+
end
|
|
344
|
+
file.write CSV.generate_line(array)
|
|
345
|
+
end
|
|
346
|
+
file.close
|
|
347
|
+
send_file(file.path, {
|
|
348
|
+
type: 'text/csv',
|
|
349
|
+
filename: filename})
|
|
350
|
+
#file.close(true)
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
# To prevent unassociated file access, do:
|
|
354
|
+
#
|
|
355
|
+
# 1. check if it is in model object
|
|
356
|
+
# 1. check if it is a edgarj_file column
|
|
357
|
+
#
|
|
358
|
+
# === Permission
|
|
359
|
+
# ModelPermission::READ on this controller is required.
|
|
360
|
+
def file_download
|
|
361
|
+
if !model.edgarj_file?(params[:column])
|
|
362
|
+
flash[:error] = t('edgarj_file.no_assoc')
|
|
363
|
+
return
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
file_info_id = user_scoped.find(params[:id]).send(params[:column])
|
|
367
|
+
if file_info_id
|
|
368
|
+
file_info = FileInfo.find(file_info_id)
|
|
369
|
+
if file_info
|
|
370
|
+
send_file(file_info.full_filename, :filename => file_info.filename)
|
|
371
|
+
return
|
|
372
|
+
end
|
|
373
|
+
end
|
|
374
|
+
logger.warn 'invalid file_info'
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# draw Google map.
|
|
378
|
+
#
|
|
379
|
+
# === Permission
|
|
380
|
+
# ModelPermission::READ on this controller is required.
|
|
381
|
+
#
|
|
382
|
+
def map
|
|
383
|
+
render :template=>'edgarj/map', :layout=>false
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
private
|
|
387
|
+
# derive model class from this controller.
|
|
388
|
+
#
|
|
389
|
+
# If controller cannot guess model class, overwrite this.
|
|
390
|
+
#
|
|
391
|
+
# === Examples:
|
|
392
|
+
# * AuthorsController -> Author
|
|
393
|
+
# * UsersController -> User
|
|
394
|
+
def model
|
|
395
|
+
@_model ||=
|
|
396
|
+
if self.class == Edgarj::EdgarjController
|
|
397
|
+
# dummy model for 'top' action:
|
|
398
|
+
Edgarj::Sssn
|
|
399
|
+
else
|
|
400
|
+
self.class.name.gsub(/Controller$/, '').singularize.constantize
|
|
401
|
+
end
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
# return model name.
|
|
405
|
+
#
|
|
406
|
+
# if each concreate controller cannot guess model name from its
|
|
407
|
+
# controller name, overwrite this.
|
|
408
|
+
#
|
|
409
|
+
# === Examples:
|
|
410
|
+
# * UsersController -> 'edgarj_user'
|
|
411
|
+
# * AuthorsController -> 'author'
|
|
412
|
+
#
|
|
413
|
+
def model_name
|
|
414
|
+
@_model_name ||= ActiveModel::Naming.param_key(model.new)
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
# return permitted params. Default is all.
|
|
418
|
+
#
|
|
419
|
+
# Derived Controller *MUST* customize this.
|
|
420
|
+
def permitted_params(action, kind=nil)
|
|
421
|
+
params.require(model_name).permit!
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
# return search-form object.
|
|
425
|
+
#
|
|
426
|
+
# called from page_info
|
|
427
|
+
def search_form
|
|
428
|
+
SearchForm.new(model)
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
# derive drawer class from this controller.
|
|
432
|
+
#
|
|
433
|
+
# If controller cannot guess drawer class, overwrite this.
|
|
434
|
+
#
|
|
435
|
+
# === Examples:
|
|
436
|
+
# * AuthorsController -> AuthorDrawer
|
|
437
|
+
# * UsersController -> UserDrawer
|
|
438
|
+
def drawer_class
|
|
439
|
+
@_drawer_cache ||=
|
|
440
|
+
if self.class == Edgarj::EdgarjController
|
|
441
|
+
Edgarj::Drawer::Normal
|
|
442
|
+
else
|
|
443
|
+
(self.class.name.gsub(/Controller$/, '').singularize +
|
|
444
|
+
'Drawer').constantize
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
# set drawer instance as drawer for later use on rendering view
|
|
449
|
+
def set_drawer
|
|
450
|
+
@drawer = drawer_class.new(view_context, params, page_info, model)
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
def drawer
|
|
454
|
+
@drawer
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
# additional behavior on upsert (default does nothing).
|
|
458
|
+
#
|
|
459
|
+
# Derived controller may overwrite this method if necessary, for example:
|
|
460
|
+
# * to upsert protected attributes.
|
|
461
|
+
# * to upsert server-side calculated values
|
|
462
|
+
def on_upsert
|
|
463
|
+
#
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
# update/insert common
|
|
467
|
+
def upsert(&block)
|
|
468
|
+
ActiveRecord::Base.transaction do
|
|
469
|
+
yield
|
|
470
|
+
@flash_notice = t('save_ok')
|
|
471
|
+
end
|
|
472
|
+
prepare_list
|
|
473
|
+
rescue ActiveRecord::RecordNotSaved, ActiveRecord::RecordInvalid => ex
|
|
474
|
+
logger.info "#{ex.class.to_s}: #{@record.class.to_s}: #{@record.errors.full_messages.join(' / ')}"
|
|
475
|
+
app_rescue
|
|
476
|
+
@flash_error = t('save_fail')
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
# At public action, just set any message into @flash_notice and/or
|
|
480
|
+
# \@flash_error. Then, any render in EdgarjController will display it
|
|
481
|
+
# by calling draw_flash().
|
|
482
|
+
#
|
|
483
|
+
# draw_flash() must be a helper because it is called in render block, which
|
|
484
|
+
# is a kind of view.
|
|
485
|
+
def draw_flash(page)
|
|
486
|
+
page.replace_html 'flash_notice', :text=>@flash_notice
|
|
487
|
+
page.replace_html 'flash_error', :text=>@flash_error
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
# insert/update uploaded file and point to it via file_NN column
|
|
491
|
+
=begin
|
|
492
|
+
def upsert_files
|
|
493
|
+
#@record.upsert_files(params[:file_info], params[model_name])
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
# Since 'render :text=>proc...' cannot be tested at functional test
|
|
497
|
+
# (see http://lightyearsoftware.com/2009/10/rails-bug-with-render-text-proc-in-tests/),
|
|
498
|
+
# move the logic inside the proc here to test
|
|
499
|
+
def csv_proc(output)
|
|
500
|
+
csv_visitor = EdgarjHelper::CsvVisitor.new(@template)
|
|
501
|
+
find_args = {:conditions=>page_info.record.conditions}
|
|
502
|
+
if !page_info.order_by.blank?
|
|
503
|
+
find_args.merge!(:order => page_info.order_by + ' ' + page_info.dir)
|
|
504
|
+
end
|
|
505
|
+
output.write CSV.generate_line(model.columns.map{|c| c.name}) + "\n"
|
|
506
|
+
for rec in model.find(:all, find_args) do
|
|
507
|
+
array = []
|
|
508
|
+
for col in model.columns do
|
|
509
|
+
array << csv_visitor.visit_column(rec, col)
|
|
510
|
+
end
|
|
511
|
+
output.write CSV.generate_line(array) + "\n"
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
=end
|
|
515
|
+
|
|
516
|
+
# This works as:
|
|
517
|
+
#
|
|
518
|
+
# before_render :set_drawer
|
|
519
|
+
#
|
|
520
|
+
# to set drawer just before rendering.
|
|
521
|
+
#
|
|
522
|
+
# See http://stackoverflow.com/questions/9281224/filter-to-execute-before-render-but-after-controller
|
|
523
|
+
#
|
|
524
|
+
def render(*args)
|
|
525
|
+
# set_drawer should be called only when finishing before_filters.
|
|
526
|
+
set_drawer if current_user
|
|
527
|
+
super
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
def enum_cache_stat
|
|
531
|
+
logger.debug 'EnumCache stat (hit/out/out_of_enum): ' +
|
|
532
|
+
EnumCache.instance.stat.inspect
|
|
533
|
+
end
|
|
534
|
+
end
|
|
535
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# permission check before-filters
|
|
2
|
+
#
|
|
3
|
+
# authorization('require_login' before_filter) should be prior to this.
|
|
4
|
+
module Edgarj
|
|
5
|
+
module PermissionMixin
|
|
6
|
+
def self.included(klass)
|
|
7
|
+
klass.helper_method(
|
|
8
|
+
:current_user_roles,
|
|
9
|
+
:current_model_permissions
|
|
10
|
+
)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
def respond_to_permission_error
|
|
15
|
+
respond_to do |format|
|
|
16
|
+
format.html {
|
|
17
|
+
flash[:error] = v('permission_no')
|
|
18
|
+
|
|
19
|
+
# FIXME: flash[:error] is not passed at redirected page
|
|
20
|
+
# so taht set it to parmas[:error].
|
|
21
|
+
# However, this change causes the test failure so that
|
|
22
|
+
# this change is applied *ONLY* on dev. & prod.
|
|
23
|
+
if Rails.env=='test'
|
|
24
|
+
redirect_to main_app.top_path
|
|
25
|
+
else
|
|
26
|
+
redirect_to main_app.top_path(error: v('permission_no'))
|
|
27
|
+
end
|
|
28
|
+
}
|
|
29
|
+
format.js {
|
|
30
|
+
flash.now[:error] = v('permission_no')
|
|
31
|
+
render 'message_popup'
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def current_user_roles
|
|
37
|
+
@_edgarj_current_user_roles ||= Edgarj::UserGroup.joins(:user_group_users).
|
|
38
|
+
where(
|
|
39
|
+
'edgarj_user_groups.kind' => Edgarj::UserGroup::Kind::ROLE,
|
|
40
|
+
'edgarj_user_group_users.user_id'=> current_user.id)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def current_model_permissions
|
|
44
|
+
@_edgarj_current_model_permissions ||= Edgarj::ModelPermission.
|
|
45
|
+
joins(user_group: :user_group_users).
|
|
46
|
+
where(
|
|
47
|
+
'model' => model.to_s,
|
|
48
|
+
'edgarj_user_groups.kind' => Edgarj::UserGroup::Kind::ROLE,
|
|
49
|
+
'edgarj_user_group_users.user_id'=> current_user.id)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# common method for all of 'require_*_permission' before_filter
|
|
53
|
+
def require_x_permission(flag)
|
|
54
|
+
if current_user && current_user_roles.any?{|ug| ug.admin?}
|
|
55
|
+
# if role is admin, then ok
|
|
56
|
+
elsif current_user && current_model_permissions.any?{|cp| cp.permitted?(flag)}
|
|
57
|
+
# if enough permission, then ok
|
|
58
|
+
else
|
|
59
|
+
respond_to_permission_error
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def require_create_permission
|
|
64
|
+
require_x_permission(Edgarj::ModelPermission::FlagsBitset::CREATE)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def require_read_permission
|
|
68
|
+
require_x_permission(Edgarj::ModelPermission::FlagsBitset::READ)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def require_update_permission
|
|
72
|
+
require_x_permission(Edgarj::ModelPermission::FlagsBitset::UPDATE)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def require_delete_permission
|
|
76
|
+
require_x_permission(Edgarj::ModelPermission::FlagsBitset::DELETE)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# fallback to catch public action which permisson is not declared
|
|
80
|
+
def require_other_permission
|
|
81
|
+
respond_to_permission_error
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|