Status: | Needs review |
---|---|
Proposed branch: | lp:~mike-amy/sahana-eden/LA |
Merge into: | lp:sahana-eden |
Diff against target: |
38687 lines (+17935/-14451) 214 files modified
.bzrignore (+2/-0) VERSION (+1/-1) clean_la.cmd (+11/-0) controllers/admin.py (+52/-1) controllers/default.py (+638/-379) controllers/don.py (+693/-0) controllers/event.py (+11/-1) controllers/gis.py (+3/-2) controllers/hrm.py (+193/-0) controllers/master.py (+22/-0) controllers/org.py (+83/-0) controllers/project.py (+2/-59) controllers/req.py (+13/-9) controllers/supply.py (+1/-0) controllers/vol.py (+2350/-176) deployment-templates/models/000_config.py (+223/-205) languages/es.py (+917/-6599) models/00_db.py (+0/-1) models/00_settings.py (+71/-29) models/00_tables.py (+41/-61) models/00_utils.py (+11/-5) models/01_menu.py (+654/-340) models/02_pr.py (+2/-0) models/03_gis.py (+2/-1) models/04_pr.py (+21/-4) models/05_irs.py (+0/-1) models/05_org.py (+513/-95) models/06_hrm.py (+100/-31) models/06_supply.py (+44/-35) models/08_inv.py (+7/-1) models/09_project.py (+108/-11) models/don.py (+613/-0) models/event.py (+98/-2) models/req.py (+3064/-1922) models/vol.py (+1889/-342) models/zzz_1st_roles.py (+169/-89) models/zzz_1st_run.py (+86/-185) modules/s3/add_object_inline.py (+108/-0) modules/s3/s3aaa.py (+103/-27) modules/s3/s3cfg.py (+4/-0) modules/s3/s3export.py (+4/-4) modules/s3/s3gis.py (+5/-7) modules/s3/s3import.py (+57/-20) modules/s3/s3msg.py (+18/-2) modules/s3/s3pdf.py (+65/-14) modules/s3/s3search.py (+7/-2) modules/s3/s3tools.py (+138/-258) modules/s3/s3utils.py (+0/-1) modules/s3/s3widgets.py (+526/-382) modules/test_utils/__init__.py (+5/-0) modules/test_utils/load_unit.py (+32/-0) modules/test_utils/login.py (+19/-0) modules/test_utils/run.py (+13/-10) modules/test_utils/setup_request_environment.py (+23/-0) private/prepopulate/default/StandardItems.csv (+4/-0) private/prepopulate/demo/LA/California_L2.csv (+59/-0) private/prepopulate/demo/LA/LASkillList.csv (+62/-64) private/prepopulate/demo/LA/USA_L1.csv (+52/-0) private/prepopulate/demo/LA/office.csv (+16/-0) private/prepopulate/demo/LA/organisation.csv (+8/-0) private/prepopulate/demo/LA/people.csv (+86/-0) private/prepopulate/demo/LA/req_req.csv (+15/-4) private/prepopulate/demo/LA/req_skill.csv (+12/-0) private/prepopulate/demo/LA/sector.csv (+21/-0) private/prepopulate/demo/LA/tasks.cfg (+17/-1) private/prepopulate/demo/LA/users.csv (+86/-0) private/prepopulate/demo/LA/vol_application.csv (+41/-0) private/prepopulate/demo/LA/vol_assignment.csv (+41/-0) private/prepopulate/regression/office.csv (+1/-1) static/formats/edrm/export.xsl (+18/-0) static/formats/edrm/import.xsl (+14/-2) static/formats/s3csv/hrm/person.xsl (+44/-33) static/formats/s3csv/org/office.xsl (+47/-5) static/formats/s3csv/org/officela.xsl (+261/-0) static/formats/s3csv/org/organisation.xsl (+6/-1) static/formats/s3csv/org/sector.xsl (+38/-0) static/formats/s3csv/req/req.xsl (+32/-21) static/formats/s3csv/req/req_skill.xsl (+70/-0) static/formats/s3csv/vol/application.xsl (+76/-0) static/formats/s3csv/vol/assignment.xsl (+74/-0) static/formats/s3csv/vol/contact.xsl (+75/-0) static/formats/s3csv/vol/req.xsl (+77/-0) static/scripts/S3/S3.js (+4/-3) static/scripts/S3/S3.min.js (+4/-4) static/scripts/S3/anytimec.js (+0/-789) static/scripts/S3/jquery.ba-resize.js (+249/-0) static/scripts/S3/jquery.ba-resize.min.js (+9/-0) static/scripts/S3/jquery.hoverIntent.js (+106/-0) static/scripts/S3/jquery.hoverIntent.minified.js (+9/-0) static/scripts/S3/s3.dataTables.js (+10/-4) static/scripts/S3/s3.dataTables.min.js (+5/-5) static/scripts/S3/s3.select_object.js (+136/-0) static/scripts/S3/s3.select_person.js (+1/-1) static/scripts/S3/s3.select_person.min.js (+1/-1) static/scripts/S3/ui.multiselect.js (+3/-0) static/styles/S3/anytime.css (+0/-777) static/styles/S3/anytimec.css (+0/-44) static/styles/S3/sahana.css (+949/-833) static/styles/S3/sahana.min.css (+1/-1) tests/selenium/selenium-version (+2/-2) tests/smoke_tests.cmd (+2/-0) tests/unit_tests/controllers/hrm.py (+233/-0) tests/unit_tests/controllers/org.py (+121/-0) tests/unit_tests/models/01_menu.py (+128/-0) tests/unit_tests/modules/s3/s3gis/FeatureLayer.py (+7/-1) tests/unit_tests/modules/s3/s3gis/FeatureQueries.py (+7/-2) tests/unit_tests/modules/s3/s3gis/GPXLayer.py (+3/-1) tests/unit_tests/modules/s3/s3gis/GeoJSONLayer.py (+3/-1) tests/unit_tests/modules/s3/s3gis/GeoRSSLayer.py (+3/-1) tests/unit_tests/modules/s3/s3gis/KMLLayer.py (+1/-5) tests/unit_tests/modules/s3/s3gis/TrueCodePaths.py (+97/-135) tests/unit_tests/modules/s3/s3gis/WFSLayer.py (+2/-0) tests/unit_tests/modules/s3/s3gis/__init__.py (+1/-1) views/_create.html (+2/-2) views/_delete.html (+1/-1) views/_display.html (+2/-2) views/_list.html (+30/-27) views/_list_create.html (+4/-4) views/_merge.html (+2/-2) views/_ocr_page_upload.html (+1/-1) views/_ocr_upload.html (+1/-1) views/_search.html (+2/-2) views/_update.html (+2/-2) views/admin/export_data.html (+1/-1) views/admin/groups.html (+1/-1) views/admin/import_data.html (+1/-1) views/admin/index.html (+1/-1) views/admin/role_edit.html (+1/-1) views/admin/role_list.html (+1/-1) views/admin/role_users.html (+1/-1) views/admin/settings.html (+2/-1) views/admin/users.html (+1/-1) views/assess/basic_assess.html (+1/-1) views/assess/index.html (+1/-1) views/asset/index.html (+1/-1) views/auth/_login.html (+1/-1) views/breadcrumbs.html (+6/-0) views/budget/budget_staff_bundle_header.html (+1/-1) views/budget/bundle_kit_item_header.html (+1/-1) views/budget/kit_item_header.html (+1/-1) views/building/adminLevel.html (+1/-1) views/building/index.html (+1/-1) views/building/report.html (+1/-1) views/building/timeline.html (+1/-1) views/cr/index.html (+1/-1) views/dataTables.html (+37/-62) views/default/about.html (+1/-1) views/default/contact.html (+7/-17) views/default/disclaimer.html (+13/-0) views/default/faq.html (+9/-0) views/default/help.html (+11/-2) views/default/index.html (+24/-59) views/default/register.html (+14/-0) views/default/sitemap.html (+5/-0) views/default/user.html (+1/-1) views/default/why.html (+8/-0) views/delphi/index.html (+1/-1) views/don/index.html (+69/-0) views/dvi/index.html (+1/-1) views/dvr/index.html (+1/-1) views/errors/index.html (+1/-1) views/event/index.html (+1/-1) views/flood/index.html (+1/-1) views/footer.html (+15/-7) views/formats.html (+7/-6) views/gis/catalogue_toolbar.html (+1/-1) views/gis/legend.html (+11/-11) views/gis/location_duplicates.html (+1/-1) views/gis/location_resolve.html (+1/-1) views/hrm/index.html (+1/-1) views/importer/index.html (+1/-1) views/inner_form.html (+109/-0) views/inv/index.html (+1/-1) views/irs/index.html (+1/-1) views/key.html (+1/-1) views/layout.html (+56/-88) views/list_create_ext.html (+1/-1) views/list_ext.html (+1/-1) views/master/index.html (+15/-0) views/mobile/settings_update.html (+1/-1) views/mpr/index.html (+1/-1) views/msg/_compose.html (+1/-1) views/msg/api_settings_update.html (+1/-1) views/msg/contacts.html (+1/-1) views/msg/email_settings_update.html (+1/-1) views/msg/group_user_header.html (+1/-1) views/msg/index.html (+1/-1) views/msg/modem_settings_update.html (+1/-1) views/msg/outbox_create.html (+1/-1) views/msg/setting_display.html (+1/-1) views/msg/setting_update.html (+1/-1) views/msg/sms_to_smtp_settings_update.html (+1/-1) views/msg/tropo_settings_update.html (+1/-1) views/org/index.html (+1/-1) views/patient/index.html (+1/-1) views/pr/index.html (+1/-1) views/pr/person_duplicates.html (+1/-1) views/pr/person_presence_list.html (+1/-1) views/pr/person_presence_list_create.html (+1/-1) views/pr/person_resolve.html (+1/-1) views/project/index.html (+1/-1) views/project/project_search.html (+1/-1) views/req/index.html (+2/-2) views/req/req_assignment_update.html (+33/-0) views/req/req_item_inv_item.html (+1/-1) views/scenario/index.html (+1/-1) views/supply/index.html (+26/-0) views/survey/index.html (+1/-1) views/ticket/index.html (+1/-1) views/vehicle/index.html (+1/-1) views/vol/index.html (+5/-29) views/vol/profile.html (+10/-0) views/vol/register.html (+11/-0) views/vol/req_assignment_update.html (+32/-0) |
To merge this branch: | bzr merge lp:~mike-amy/sahana-eden/LA |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Fran Boon | Pending | ||
Review via email: mp+74669@code.launchpad.net |
This proposal supersedes a proposal from 2011-09-08.
Commit message
Description of the change
Add site (office) widget.
Implemented requested changes to the Add Human resource widget:
* Moved Close and Reset next to the Submit button
* Changed Close -> Cancel; Reset -> Clear; Submit -> Save
* Display throbber (static/
* Hide Main widget when displaying the inner form.
Please note revision 2586. Had some problems and got past it by commenting out a debug line. Not sure if that line is in error, but caused a missing page for me.
Unmerged revisions
- 2597. By Mike Amy
-
merged from LA
- 2596. By Mike Amy
-
fixed 'Additional 2' test => 'Address 2' :). Cleaned up 01_menu.py
- 2595. By Mike Amy
-
merged from la
- 2594. By Mike Amy
-
Add xyz widget refactoring and tests
- 2593. By Mike Amy
-
fixed a problem stopping offices being created from the inner forms
- 2592. By Mike Amy
-
merged from trunk
- 2591. By Mike Amy
-
Display throbber when loading inner form iframe to show something is happening, and hide main widget when it is displayed.
- 2590. By Mike Amy
-
Moved inner form buttons near to submit button and renamed as 'Cancel' and 'Close'
- 2589. By Mike Amy
-
stopped link showing for autocompleted sites (offices)
- 2588. By Mike Amy
-
merged from trunk
Preview Diff
1 | === modified file '.bzrignore' | |||
2 | --- .bzrignore 2011-08-10 21:33:23 +0000 | |||
3 | +++ .bzrignore 2011-09-14 11:00:06 +0000 | |||
4 | @@ -14,6 +14,8 @@ | |||
5 | 14 | !static/fonts/setfonts.py | 14 | !static/fonts/setfonts.py |
6 | 15 | !static/fonts/generatefontmapping.py | 15 | !static/fonts/generatefontmapping.py |
7 | 16 | *.ttf | 16 | *.ttf |
8 | 17 | !static/fonts/la/ | ||
9 | 18 | !static/fonts/la/*.ttf | ||
10 | 17 | static/scripts/ext/.docs/* | 19 | static/scripts/ext/.docs/* |
11 | 18 | static/scripts/ext/.examples/* | 20 | static/scripts/ext/.examples/* |
12 | 19 | static/scripts/ext/.test/* | 21 | static/scripts/ext/.test/* |
13 | 20 | 22 | ||
14 | === modified file 'VERSION' | |||
15 | --- VERSION 2011-09-14 07:02:18 +0000 | |||
16 | +++ VERSION 2011-09-14 11:00:06 +0000 | |||
17 | @@ -1,1 +1,1 @@ | |||
18 | 1 | r2745 (2011-09-14 08:02:17) | ||
19 | 2 | \ No newline at end of file | 1 | \ No newline at end of file |
20 | 2 | r2778 (2011-09-14 08:44:36) | ||
21 | 3 | \ No newline at end of file | 3 | \ No newline at end of file |
22 | 4 | 4 | ||
23 | === added file 'clean_la.cmd' | |||
24 | --- clean_la.cmd 1970-01-01 00:00:00 +0000 | |||
25 | +++ clean_la.cmd 2011-09-14 11:00:06 +0000 | |||
26 | @@ -0,0 +1,11 @@ | |||
27 | 1 | @echo off | ||
28 | 2 | rem CHOICE Do you want to delete and reinitialise the Sahana Eden Database | ||
29 | 3 | rem if ERRORLEVEL N goto end | ||
30 | 4 | |||
31 | 5 | rd /Q /S compiled | ||
32 | 6 | |||
33 | 7 | del databases\*.* /Q | ||
34 | 8 | del errors\*.* /Q | ||
35 | 9 | del sessions\*.* /Q | ||
36 | 10 | python ..\..\web2py.py -S la -M -R applications\la\static\scripts\tools\noop.py | ||
37 | 11 | PAUSE | ||
38 | 0 | \ No newline at end of file | 12 | \ No newline at end of file |
39 | 1 | 13 | ||
40 | === modified file 'controllers/admin.py' | |||
41 | --- controllers/admin.py 2011-09-13 14:56:01 +0000 | |||
42 | +++ controllers/admin.py 2011-09-14 11:00:06 +0000 | |||
43 | @@ -73,6 +73,37 @@ | |||
44 | 73 | 73 | ||
45 | 74 | 74 | ||
46 | 75 | # ----------------------------------------------------------------------------- | 75 | # ----------------------------------------------------------------------------- |
47 | 76 | def register_onaccept(form): | ||
48 | 77 | """ | ||
49 | 78 | LA-specific: | ||
50 | 79 | Ensure manually-created users get added to 'Staff' role & | ||
51 | 80 | have an HRM record created. | ||
52 | 81 | """ | ||
53 | 82 | # Usual Registration Tasks | ||
54 | 83 | # (PR record, Authenticated Role, Contacts) | ||
55 | 84 | person = auth.s3_register(form) | ||
56 | 85 | |||
57 | 86 | # LA-specific | ||
58 | 87 | # Add to 'Staff' role | ||
59 | 88 | table = db.auth_group | ||
60 | 89 | STAFF = db(table.uuid == "STAFF").select(table.id, | ||
61 | 90 | limitby=(0, 1)).first().id | ||
62 | 91 | table = db.pr_person | ||
63 | 92 | person_uuid = db(table.id == person).select(table.uuid, | ||
64 | 93 | limitby=(0, 1)).first().uuid | ||
65 | 94 | table = db.auth_user | ||
66 | 95 | query = (table.person_uuid == person_uuid) | ||
67 | 96 | user = db(query).select(table.id, | ||
68 | 97 | limitby=(0, 1)).first().id | ||
69 | 98 | table = db.auth_membership | ||
70 | 99 | table.insert(user_id = user, | ||
71 | 100 | group_id = STAFF) | ||
72 | 101 | |||
73 | 102 | # Create an HRM record so that the user appears in human_resource_id() lookups | ||
74 | 103 | table = db.hrm_human_resource | ||
75 | 104 | table.insert(person_id=person) | ||
76 | 105 | |||
77 | 106 | # ----------------------------------------------------------------------------- | ||
78 | 76 | @auth.s3_requires_membership(1) | 107 | @auth.s3_requires_membership(1) |
79 | 77 | def user(): | 108 | def user(): |
80 | 78 | """ RESTful CRUD controller """ | 109 | """ RESTful CRUD controller """ |
81 | @@ -84,7 +115,10 @@ | |||
82 | 84 | s3mgr.configure(tablename, | 115 | s3mgr.configure(tablename, |
83 | 85 | main="first_name", | 116 | main="first_name", |
84 | 86 | # Add users to Person Registry & 'Authenticated' role: | 117 | # Add users to Person Registry & 'Authenticated' role: |
86 | 87 | create_onaccept = auth.s3_register) | 118 | create_onaccept = register_onaccept) |
87 | 119 | |||
88 | 120 | # Staff don't need a Mobile Phone | ||
89 | 121 | deployment_settings.auth.registration_requests_mobile_phone = False | ||
90 | 88 | 122 | ||
91 | 89 | def disable_user(r): | 123 | def disable_user(r): |
92 | 90 | if not r.id: | 124 | if not r.id: |
93 | @@ -591,10 +625,13 @@ | |||
94 | 591 | @auth.s3_requires_membership(1) | 625 | @auth.s3_requires_membership(1) |
95 | 592 | def portable(): | 626 | def portable(): |
96 | 593 | """ Portable app creator""" | 627 | """ Portable app creator""" |
97 | 628 | |||
98 | 629 | |||
99 | 594 | from gluon.admin import apath | 630 | from gluon.admin import apath |
100 | 595 | import os | 631 | import os |
101 | 596 | from operator import itemgetter, attrgetter | 632 | from operator import itemgetter, attrgetter |
102 | 597 | 633 | ||
103 | 634 | |||
104 | 598 | app = request.application | 635 | app = request.application |
105 | 599 | uploadfolder=os.path.join(apath("%s" % app,r=request),'cache') | 636 | uploadfolder=os.path.join(apath("%s" % app,r=request),'cache') |
106 | 600 | web2py_source = None | 637 | web2py_source = None |
107 | @@ -715,6 +752,20 @@ | |||
108 | 715 | return response.stream(portable_app) | 752 | return response.stream(portable_app) |
109 | 716 | 753 | ||
110 | 717 | # ============================================================================= | 754 | # ============================================================================= |
111 | 755 | # LA Code | ||
112 | 756 | # ============================================================================= | ||
113 | 757 | @auth.s3_requires_membership(1) | ||
114 | 758 | def rostermail(): | ||
115 | 759 | """ | ||
116 | 760 | Email Addresses for the Volunteer Roster to be sent to | ||
117 | 761 | """ | ||
118 | 762 | |||
119 | 763 | return s3_rest_controller("vol", resourcename) | ||
120 | 764 | |||
121 | 765 | |||
122 | 766 | |||
123 | 767 | |||
124 | 768 | # ============================================================================= | ||
125 | 718 | # Deprecated Code below here | 769 | # Deprecated Code below here |
126 | 719 | # ============================================================================= | 770 | # ============================================================================= |
127 | 720 | @auth.s3_requires_membership(1) | 771 | @auth.s3_requires_membership(1) |
128 | 721 | 772 | ||
129 | === modified file 'controllers/default.py' | |||
130 | --- controllers/default.py 2011-09-12 13:46:38 +0000 | |||
131 | +++ controllers/default.py 2011-09-14 11:00:06 +0000 | |||
132 | @@ -26,350 +26,14 @@ | |||
133 | 26 | return response.download(request, db) | 26 | return response.download(request, db) |
134 | 27 | 27 | ||
135 | 28 | # ----------------------------------------------------------------------------- | 28 | # ----------------------------------------------------------------------------- |
136 | 29 | # Check the validity of entered Mobile Phone data | ||
137 | 30 | def register_validation(form): | ||
138 | 31 | """ Validate the fields in registration form """ | ||
139 | 32 | # Mobile Phone | ||
140 | 33 | if "mobile" in form.vars and form.vars.mobile: | ||
141 | 34 | regex = re.compile(single_phone_number_pattern) | ||
142 | 35 | if not regex.match(form.vars.mobile): | ||
143 | 36 | form.errors.mobile = T("Invalid phone number") | ||
144 | 37 | elif deployment_settings.get_auth_registration_mobile_phone_mandatory(): | ||
145 | 38 | form.errors.mobile = T("Phone number is required") | ||
146 | 39 | return | ||
147 | 40 | |||
148 | 41 | auth.settings.register_onvalidation = register_validation | ||
149 | 42 | # Add newly-registered users to Person Registry, add 'Authenticated' role | ||
150 | 43 | # If Organisation is provided, then: add HRM record & add to 'Org_X_Access' role | ||
151 | 44 | auth.settings.register_onaccept = auth.s3_register | ||
152 | 45 | |||
153 | 46 | _table_user = auth.settings.table_user | ||
154 | 47 | _table_user.first_name.label = T("First Name") | ||
155 | 48 | _table_user.first_name.comment = SPAN("*", _class="req") | ||
156 | 49 | _table_user.last_name.label = T("Last Name") | ||
157 | 50 | if deployment_settings.get_L10n_mandatory_lastname(): | ||
158 | 51 | _table_user.last_name.comment = SPAN("*", _class="req") | ||
159 | 52 | _table_user.email.label = T("E-mail") | ||
160 | 53 | _table_user.email.comment = SPAN("*", _class="req") | ||
161 | 54 | _table_user.password.comment = SPAN("*", _class="req") | ||
162 | 55 | _table_user.language.label = T("Language") | ||
163 | 56 | _table_user.language.comment = DIV(_class="tooltip", | ||
164 | 57 | _title="%s|%s" % (T("Language"), | ||
165 | 58 | T("The language you wish the site to be displayed in."))) | ||
166 | 59 | _table_user.language.represent = lambda opt: s3_languages.get(opt, UNKNOWN_OPT) | ||
167 | 60 | |||
168 | 61 | # Organisation widget for use in Registration Screen | ||
169 | 62 | # NB User Profile is only editable by Admin - using User Management | ||
170 | 63 | org_widget = IS_ONE_OF(db, "org_organisation.id", | ||
171 | 64 | organisation_represent, | ||
172 | 65 | orderby="org_organisation.name", | ||
173 | 66 | sort=True) | ||
174 | 67 | if deployment_settings.get_auth_registration_organisation_mandatory(): | ||
175 | 68 | _table_user.organisation_id.requires = org_widget | ||
176 | 69 | else: | ||
177 | 70 | _table_user.organisation_id.requires = IS_NULL_OR(org_widget) | ||
178 | 71 | |||
179 | 72 | # For the User Profile: | ||
180 | 73 | _table_user.organisation_id.represent = organisation_represent | ||
181 | 74 | _table_user.organisation_id.comment = DIV(_class="tooltip", | ||
182 | 75 | _title="%s|%s|%s" % (T("Organization"), | ||
183 | 76 | T("The default Organization for whom you are acting."), | ||
184 | 77 | T("This setting can only be controlled by the Administrator."))) | ||
185 | 78 | |||
186 | 79 | _table_user.site_id.represent = shn_site_represent | ||
187 | 80 | _table_user.site_id.comment = DIV(_class="tooltip", | ||
188 | 81 | _title="%s|%s|%s" % (T("Facility"), | ||
189 | 82 | T("The default Facility for which you are acting."), | ||
190 | 83 | T("This setting can only be controlled by the Administrator."))) | ||
191 | 84 | |||
192 | 85 | # ----------------------------------------------------------------------------- | ||
193 | 86 | def index(): | 29 | def index(): |
194 | 87 | """ Main Home Page """ | 30 | """ Main Home Page """ |
195 | 88 | 31 | ||
196 | 89 | title = deployment_settings.get_system_name() | 32 | title = deployment_settings.get_system_name() |
197 | 90 | response.title = title | 33 | response.title = title |
198 | 91 | 34 | ||
480 | 92 | if deployment_settings.has_module("cr"): | 35 | return dict(title = title) |
481 | 93 | s3mgr.load("cr_shelter") | 36 | |
201 | 94 | SHELTERS = s3.crud_strings["cr_shelter"].subtitle_list | ||
202 | 95 | else: | ||
203 | 96 | SHELTERS = "" | ||
204 | 97 | |||
205 | 98 | # Menu Boxes | ||
206 | 99 | menu_btns = [#div, label, app, function | ||
207 | 100 | ["facility", SHELTERS, "cr", "shelter"], | ||
208 | 101 | ["facility", T("Warehouses"), "inv", "warehouse"], | ||
209 | 102 | ["facility", T("Hospitals"), "hms", "hospital"], | ||
210 | 103 | ["facility", T("Offices"), "org", "office"], | ||
211 | 104 | ["sit", T("Incidents"), "irs", "ireport"], | ||
212 | 105 | ["sit", T("Assessments"), "assess", "assess"], | ||
213 | 106 | ["sit", T("Assets"), "asset", "asset"], | ||
214 | 107 | ["sit", T("Inventory Items"), "inv", "inv_item"], | ||
215 | 108 | ["dec", T("Gap Map"), "project", "gap_map"], | ||
216 | 109 | ["dec", T("Gap Report"), "project", "gap_report"], | ||
217 | 110 | ["dec", T("Requests"), "req", "req"], | ||
218 | 111 | ["res", T("Projects"), "project", "project"], | ||
219 | 112 | ["res", T("Activities"), "project", "assess"], | ||
220 | 113 | ["res", T("Commitments"), "req", "commit"], | ||
221 | 114 | ["res", T("Sent Shipments"), "inv", "send"], | ||
222 | 115 | ["res", T("Received Shipments"), "inv", "recv"], | ||
223 | 116 | ] | ||
224 | 117 | |||
225 | 118 | # Change to (Mitigation)/Preparedness/Response/Recovery? | ||
226 | 119 | menu_divs = {"facility": DIV( H3(T("Facilities")), | ||
227 | 120 | _id = "facility_box", _class = "menu_box"), | ||
228 | 121 | "sit": DIV( H3(T("Situation")), | ||
229 | 122 | _id = "menu_div_sit", _class = "menu_div"), | ||
230 | 123 | "dec": DIV( H3(T("Decision")), | ||
231 | 124 | _id = "menu_div_dec", _class = "menu_div"), | ||
232 | 125 | "res": DIV( H3(T("Response")), | ||
233 | 126 | _id = "menu_div_res", _class = "menu_div"), | ||
234 | 127 | } | ||
235 | 128 | |||
236 | 129 | for div, label, app, function in menu_btns: | ||
237 | 130 | if deployment_settings.has_module(app): | ||
238 | 131 | # @ToDo: Also check permissions (e.g. for anonymous users) | ||
239 | 132 | menu_divs[div].append(A( DIV(label, | ||
240 | 133 | _class = "menu-btn-r"), | ||
241 | 134 | _class = "menu-btn-l", | ||
242 | 135 | _href = URL(app,function) | ||
243 | 136 | ) | ||
244 | 137 | ) | ||
245 | 138 | |||
246 | 139 | div_arrow = DIV(IMG(_src = "/%s/static/img/arrow_blue_right.png" % \ | ||
247 | 140 | request.application), | ||
248 | 141 | _class = "div_arrow") | ||
249 | 142 | sit_dec_res_box = DIV(menu_divs["sit"], | ||
250 | 143 | div_arrow, | ||
251 | 144 | menu_divs["dec"], | ||
252 | 145 | div_arrow, | ||
253 | 146 | menu_divs["res"], | ||
254 | 147 | _id = "sit_dec_res_box", | ||
255 | 148 | _class = "menu_box fleft swidth" | ||
256 | 149 | #div_additional, | ||
257 | 150 | ) | ||
258 | 151 | facility_box = menu_divs["facility"] | ||
259 | 152 | facility_box.append( A( IMG(_src = "/%s/static/img/map_icon_128.png" % \ | ||
260 | 153 | request.application), | ||
261 | 154 | _href = URL(c="gis", f="index"), | ||
262 | 155 | _title = T("Map") | ||
263 | 156 | ) | ||
264 | 157 | ) | ||
265 | 158 | |||
266 | 159 | datatable_ajax_source = "" | ||
267 | 160 | # Check logged in AND permissions | ||
268 | 161 | if AUTHENTICATED in session.s3.roles and \ | ||
269 | 162 | auth.s3_has_permission("read", db.org_organisation): | ||
270 | 163 | org_items = organisation() | ||
271 | 164 | datatable_ajax_source = "/%s/default/organisation.aaData" % \ | ||
272 | 165 | request.application | ||
273 | 166 | response.s3.actions = None | ||
274 | 167 | response.view = "default/index.html" | ||
275 | 168 | auth.permission.controller = "org" | ||
276 | 169 | auth.permission.function = "site" | ||
277 | 170 | permitted_facilities = auth.permission.permitted_facilities(redirect_on_error=False) | ||
278 | 171 | manage_facility_box = "" | ||
279 | 172 | if permitted_facilities: | ||
280 | 173 | facility_list = s3_represent_facilities(db, permitted_facilities, | ||
281 | 174 | link=False) | ||
282 | 175 | facility_opts = [OPTION(opt[1], _value = opt[0]) | ||
283 | 176 | for opt in facility_list] | ||
284 | 177 | if facility_list: | ||
285 | 178 | manage_facility_box = DIV(H3(T("Manage Your Facilities")), | ||
286 | 179 | SELECT(_id = "manage_facility_select", | ||
287 | 180 | _style = "max-width:400px;", | ||
288 | 181 | *facility_opts | ||
289 | 182 | ), | ||
290 | 183 | A(T("Go"), | ||
291 | 184 | _href = URL(c="default", f="site", | ||
292 | 185 | args=[facility_list[0][0]]), | ||
293 | 186 | #_disabled = "disabled", | ||
294 | 187 | _id = "manage_facility_btn", | ||
295 | 188 | _class = "action-btn" | ||
296 | 189 | ), | ||
297 | 190 | _id = "manage_facility_box", | ||
298 | 191 | _class = "menu_box fleft") | ||
299 | 192 | response.s3.jquery_ready.append( """ | ||
300 | 193 | $('#manage_facility_select').change(function() { | ||
301 | 194 | $('#manage_facility_btn').attr('href', S3.Ap.concat('/default/site/', $('#manage_facility_select').val())); | ||
302 | 195 | })""" ) | ||
303 | 196 | else: | ||
304 | 197 | manage_facility_box = DIV() | ||
305 | 198 | |||
306 | 199 | org_box = DIV( H3(T("Organizations")), | ||
307 | 200 | A(T("Add Organization"), | ||
308 | 201 | _href = URL(c="org", f="organisation", | ||
309 | 202 | args=["create"]), | ||
310 | 203 | _id = "add-btn", | ||
311 | 204 | _class = "action-btn", | ||
312 | 205 | _style = "margin-right: 10px;"), | ||
313 | 206 | org_items["items"], | ||
314 | 207 | _id = "org_box", | ||
315 | 208 | _class = "menu_box fleft" | ||
316 | 209 | ) | ||
317 | 210 | else: | ||
318 | 211 | manage_facility_box = "" | ||
319 | 212 | org_box = "" | ||
320 | 213 | |||
321 | 214 | # @ToDo: Replace this with an easily-customisable section on the homepage | ||
322 | 215 | #settings = db(db.s3_setting.id == 1).select(limitby=(0, 1)).first() | ||
323 | 216 | #if settings: | ||
324 | 217 | # admin_name = settings.admin_name | ||
325 | 218 | # admin_email = settings.admin_email | ||
326 | 219 | # admin_tel = settings.admin_tel | ||
327 | 220 | #else: | ||
328 | 221 | # # db empty and prepopulate is false | ||
329 | 222 | # admin_name = T("Sahana Administrator").xml(), | ||
330 | 223 | # admin_email = "support@Not Set", | ||
331 | 224 | # admin_tel = T("Not Set").xml(), | ||
332 | 225 | |||
333 | 226 | # Login/Registration forms | ||
334 | 227 | self_registration = deployment_settings.get_security_self_registration() | ||
335 | 228 | registered = False | ||
336 | 229 | login_form = None | ||
337 | 230 | login_div = None | ||
338 | 231 | register_form = None | ||
339 | 232 | register_div = None | ||
340 | 233 | if AUTHENTICATED not in session.s3.roles: | ||
341 | 234 | # This user isn't yet logged-in | ||
342 | 235 | if request.cookies.has_key("registered"): | ||
343 | 236 | # This browser has logged-in before | ||
344 | 237 | registered = True | ||
345 | 238 | |||
346 | 239 | # Provide a login box on front page | ||
347 | 240 | request.args = ["login"] | ||
348 | 241 | auth.messages.submit_button = T("Login") | ||
349 | 242 | login_form = auth() | ||
350 | 243 | login_div = DIV(H3(T("Login")), | ||
351 | 244 | P(XML("%s <b>%s</b> %s" % (T("Registered users can"), | ||
352 | 245 | T("login"), | ||
353 | 246 | T("to access the system"))))) | ||
354 | 247 | |||
355 | 248 | if self_registration: | ||
356 | 249 | # Provide a Registration box on front page | ||
357 | 250 | request.args = ["register"] | ||
358 | 251 | if deployment_settings.get_terms_of_service(): | ||
359 | 252 | auth.messages.submit_button = T("I accept. Create my account.") | ||
360 | 253 | else: | ||
361 | 254 | auth.messages.submit_button = T("Register") | ||
362 | 255 | register_form = auth() | ||
363 | 256 | register_div = DIV(H3(T("Register")), | ||
364 | 257 | P(XML("%s <b>%s</b>" % (T("If you would like to help, then please"), | ||
365 | 258 | T("sign-up now"))))) | ||
366 | 259 | |||
367 | 260 | # Add client-side validation | ||
368 | 261 | s3_register_validation() | ||
369 | 262 | |||
370 | 263 | if session.s3.debug: | ||
371 | 264 | response.s3.scripts.append( "%s/jquery.validate.js" % s3_script_dir ) | ||
372 | 265 | else: | ||
373 | 266 | response.s3.scripts.append( "%s/jquery.validate.min.js" % s3_script_dir ) | ||
374 | 267 | if request.env.request_method == "POST": | ||
375 | 268 | post_script = """// Unhide register form | ||
376 | 269 | $('#register_form').removeClass('hide'); | ||
377 | 270 | // Hide login form | ||
378 | 271 | $('#login_form').addClass('hide');""" | ||
379 | 272 | else: | ||
380 | 273 | post_script = "" | ||
381 | 274 | register_script = """ | ||
382 | 275 | // Change register/login links to avoid page reload, make back button work. | ||
383 | 276 | $('#register-btn').attr('href', '#register'); | ||
384 | 277 | $('#login-btn').attr('href', '#login'); | ||
385 | 278 | %s | ||
386 | 279 | // Redirect Register Button to unhide | ||
387 | 280 | $('#register-btn').click(function() { | ||
388 | 281 | // Unhide register form | ||
389 | 282 | $('#register_form').removeClass('hide'); | ||
390 | 283 | // Hide login form | ||
391 | 284 | $('#login_form').addClass('hide'); | ||
392 | 285 | }); | ||
393 | 286 | |||
394 | 287 | // Redirect Login Button to unhide | ||
395 | 288 | $('#login-btn').click(function() { | ||
396 | 289 | // Hide register form | ||
397 | 290 | $('#register_form').addClass('hide'); | ||
398 | 291 | // Unhide login form | ||
399 | 292 | $('#login_form').removeClass('hide'); | ||
400 | 293 | });""" % post_script | ||
401 | 294 | response.s3.jquery_ready.append(register_script) | ||
402 | 295 | |||
403 | 296 | if deployment_settings.frontpage.rss: | ||
404 | 297 | response.s3.external_stylesheets.append( "http://www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.css" ) | ||
405 | 298 | response.s3.scripts.append( "http://www.google.com/jsapi?key=notsupplied-wizard" ) | ||
406 | 299 | response.s3.scripts.append( "http://www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.js" ) | ||
407 | 300 | counter = 0 | ||
408 | 301 | feeds = "" | ||
409 | 302 | for feed in deployment_settings.frontpage.rss: | ||
410 | 303 | counter += 1 | ||
411 | 304 | feeds = "".join((feeds, | ||
412 | 305 | "{title: '%s',\n" % feed["title"], | ||
413 | 306 | "url: '%s'}" % feed["url"])) | ||
414 | 307 | # Don't add a trailing comma for old IEs | ||
415 | 308 | if counter != len(deployment_settings.frontpage.rss): | ||
416 | 309 | feeds += ",\n" | ||
417 | 310 | feed_control = "".join((""" | ||
418 | 311 | function LoadDynamicFeedControl() { | ||
419 | 312 | var feeds = [ | ||
420 | 313 | """, feeds, """ | ||
421 | 314 | ]; | ||
422 | 315 | var options = { | ||
423 | 316 | // milliseconds before feed is reloaded (5 minutes) | ||
424 | 317 | feedCycleTime : 300000, | ||
425 | 318 | numResults : 5, | ||
426 | 319 | stacked : true, | ||
427 | 320 | horizontal : false, | ||
428 | 321 | title : '""", str(T("News")), """' | ||
429 | 322 | }; | ||
430 | 323 | new GFdynamicFeedControl(feeds, 'feed-control', options); | ||
431 | 324 | } | ||
432 | 325 | // Load the feeds API and set the onload callback. | ||
433 | 326 | google.load('feeds', '1'); | ||
434 | 327 | google.setOnLoadCallback(LoadDynamicFeedControl);""")) | ||
435 | 328 | response.s3.js_global.append( feed_control ) | ||
436 | 329 | |||
437 | 330 | return dict(title = title, | ||
438 | 331 | |||
439 | 332 | sit_dec_res_box = sit_dec_res_box, | ||
440 | 333 | facility_box = facility_box, | ||
441 | 334 | manage_facility_box = manage_facility_box, | ||
442 | 335 | org_box = org_box, | ||
443 | 336 | |||
444 | 337 | r = None, # Required for dataTable to work | ||
445 | 338 | datatable_ajax_source = datatable_ajax_source, | ||
446 | 339 | #admin_name=admin_name, | ||
447 | 340 | #admin_email=admin_email, | ||
448 | 341 | #admin_tel=admin_tel, | ||
449 | 342 | self_registration=self_registration, | ||
450 | 343 | registered=registered, | ||
451 | 344 | login_form=login_form, | ||
452 | 345 | login_div=login_div, | ||
453 | 346 | register_form=register_form, | ||
454 | 347 | register_div=register_div | ||
455 | 348 | ) | ||
456 | 349 | |||
457 | 350 | # ----------------------------------------------------------------------------- | ||
458 | 351 | def organisation(): | ||
459 | 352 | """ | ||
460 | 353 | Function to handle pagination for the org list on the homepage | ||
461 | 354 | """ | ||
462 | 355 | |||
463 | 356 | table = db.org_organisation | ||
464 | 357 | table.id.label = T("Organization") | ||
465 | 358 | table.id.represent = organisation_represent | ||
466 | 359 | |||
467 | 360 | response.s3.dataTable_sPaginationType = "two_button" | ||
468 | 361 | response.s3.dataTable_sDom = "rtip" #"frtip" - filter broken | ||
469 | 362 | response.s3.dataTable_iDisplayLength = 25 | ||
470 | 363 | |||
471 | 364 | s3mgr.configure("org_organisation", | ||
472 | 365 | listadd = False, | ||
473 | 366 | addbtn = True, | ||
474 | 367 | super_entity = db.pr_pentity, | ||
475 | 368 | linkto = "/%s/org/organisation/%s" % (request.application, | ||
476 | 369 | "%s"), | ||
477 | 370 | list_fields = ["id",]) | ||
478 | 371 | |||
479 | 372 | return s3_rest_controller("org", "organisation") | ||
482 | 373 | # ----------------------------------------------------------------------------- | 37 | # ----------------------------------------------------------------------------- |
483 | 374 | def site(): | 38 | def site(): |
484 | 375 | """ | 39 | """ |
485 | @@ -388,7 +52,7 @@ | |||
486 | 388 | args = [id])) | 52 | args = [id])) |
487 | 389 | else: | 53 | else: |
488 | 390 | raise HTTP(404) | 54 | raise HTTP(404) |
490 | 391 | 55 | ||
491 | 392 | # ----------------------------------------------------------------------------- | 56 | # ----------------------------------------------------------------------------- |
492 | 393 | def message(): | 57 | def message(): |
493 | 394 | #if "verify_email_sent" in request.args: | 58 | #if "verify_email_sent" in request.args: |
494 | @@ -425,12 +89,13 @@ | |||
495 | 425 | _table_user = auth.settings.table_user | 89 | _table_user = auth.settings.table_user |
496 | 426 | if request.args and request.args(0) == "profile": | 90 | if request.args and request.args(0) == "profile": |
497 | 427 | #_table_user.organisation.writable = False | 91 | #_table_user.organisation.writable = False |
500 | 428 | _table_user.utc_offset.readable = True | 92 | #_table_user.utc_offset.readable = True |
501 | 429 | _table_user.utc_offset.writable = True | 93 | #_table_user.utc_offset.writable = True |
502 | 94 | pass | ||
503 | 430 | 95 | ||
504 | 431 | login_form = register_form = None | 96 | login_form = register_form = None |
505 | 432 | if request.args and request.args(0) == "login": | 97 | if request.args and request.args(0) == "login": |
507 | 433 | auth.messages.submit_button = T("Login") | 98 | auth.messages.submit_button = T("Sign In") |
508 | 434 | form = auth() | 99 | form = auth() |
509 | 435 | login_form = form | 100 | login_form = form |
510 | 436 | if s3.crud.submit_style: | 101 | if s3.crud.submit_style: |
511 | @@ -555,46 +220,640 @@ | |||
512 | 555 | xlwt_version=xlwt_version | 220 | xlwt_version=xlwt_version |
513 | 556 | ) | 221 | ) |
514 | 557 | 222 | ||
515 | 223 | # ============================================================================= | ||
516 | 224 | # LA Custom Views | ||
517 | 225 | # ============================================================================= | ||
518 | 226 | def why(): | ||
519 | 227 | """ Custom View """ | ||
520 | 228 | response.title = T("Why?") | ||
521 | 229 | return dict() | ||
522 | 230 | |||
523 | 231 | # ----------------------------------------------------------------------------- | ||
524 | 232 | def contact(): | ||
525 | 233 | """ Custom View """ | ||
526 | 234 | response.title = T("Contact us") | ||
527 | 235 | return dict() | ||
528 | 236 | |||
529 | 558 | # ----------------------------------------------------------------------------- | 237 | # ----------------------------------------------------------------------------- |
530 | 559 | def help(): | 238 | def help(): |
531 | 560 | """ Custom View """ | 239 | """ Custom View """ |
532 | 561 | response.title = T("Help") | 240 | response.title = T("Help") |
570 | 562 | return dict() | 241 | entries = [] |
571 | 563 | 242 | question = T("How do I register as a volunteer?") | |
572 | 564 | # ----------------------------------------------------------------------------- | 243 | reply = T("Follow these steps, to register:") |
573 | 565 | def contact(): | 244 | list = [] |
574 | 566 | """ | 245 | list.append(T("On the Home Page, click the ‘Volunteer’ link. Review the ‘List of Requests for Volunteers’. To select a %(request)s (Volunteer Task), click on %(apply)s; OR You can register by clicking the ‘Register’ link located on the top of the web page.") % dict(request="<i>%s</i>" % T("Request for Volunteers"), |
575 | 567 | Give the user options to contact the site admins. | 246 | apply = "<strong>%s</strong>" % T("‘APPLY’"))) |
576 | 568 | Either: | 247 | list.append(T("Enter your information into the Required Fields. After you have entered your information, click %(accept)s to register.") % dict(accept="<strong>%s</strong" % T("‘I ACCEPT, CREATE MY ACCOUNT’"))) |
577 | 569 | An internal Support Requests database | 248 | entry = (question, reply, list) |
578 | 570 | or: | 249 | entries.append(entry) |
579 | 571 | Custom View | 250 | question = T("How do I update my Profile, Skills and Emergency Details?") |
580 | 572 | """ | 251 | reply = T("After you are signed-in, please follow these steps to edit your profile: ") |
581 | 573 | if auth.is_logged_in() and deployment_settings.get_options_support_requests(): | 252 | list = [] |
582 | 574 | # Provide an internal Support Requests ticketing system. | 253 | list.append(T("On the top menu, click %(volunteer)s.") % dict(volunteer="<strong>%s</strong>" % T("VOLUNTEER"))) |
583 | 575 | prefix = "support" | 254 | list.append(T("On the left menu, click %(profile)s .") % dict(profile="<strong>%s</strong>" % T("'My Profile'"))) |
584 | 576 | resourcename = "req" | 255 | list.append(T("On this page, you can update your profile.")) |
585 | 577 | tablename = "%s_%s" % (prefix, resourcename) | 256 | list.append(T("Additional information like %(notifications)s and other volunteer agency affiliations also can be updated in this page.") % dict(notifications="<strong>%s</strong>" % T("Notifications"))) |
586 | 578 | table = db[tablename] | 257 | list.append(T("Then click %(save)s") % dict(save="<strong>%s</strong>" % T("Save"))) |
587 | 579 | 258 | list.append(T("On the left menu, click %(skills)s.") % dict(skills="<strong>%s</strong>" % T("Skills"))) | |
588 | 580 | # Pre-processor | 259 | list.append(T("Click the %s sign next to the skill(s) that best describes how you can support the City.") % "<strong>'+'</strong>") |
589 | 581 | def prep(r): | 260 | list.append(T("You may also search for a skill by providing the first few characters in the search box. (Example: When searching for ‘Driving’ skills, enter the first letters of the word).")) |
590 | 582 | # Only Admins should be able to update ticket status | 261 | list.append(T("If your skill(s) is not listed, you may enter it in the %(extraSkills)s field below.") % dict(extraSkills="<strong>%s</strong>" % T("Skills"))) |
591 | 583 | if not auth.s3_has_role(ADMIN): | 262 | list.append(T("Then click %(save)s") % dict(save="<strong>%s</strong>") % T("Save")) |
592 | 584 | table.status.writable = False | 263 | list.append(T("You may also update your Emergency Contacts information by clicking on 'Emergency Contacts' located on the left menu.")) |
593 | 585 | table.actions.writable = False | 264 | list.append(T("Then click %(save)s") % dict(save="<strong>%s</strong>") % T("Save")) |
594 | 586 | if r.interactive and r.method == "create": | 265 | entry = (question, reply, list) |
595 | 587 | table.status.readable = False | 266 | entries.append(entry) |
596 | 588 | table.actions.readable = False | 267 | question = T("How do I apply for a Volunteer Request after I have registered with Give2LA?") |
597 | 589 | return True | 268 | reply = T("You can apply by clicking the %(signin)s link located on the top of the web page.") % dict(signin="<strong>%s</strong>" % T("‘Sign-In’")) |
598 | 590 | response.s3.prep = prep | 269 | list = [] |
599 | 591 | 270 | list.append(T("Enter your E-Mail and Password information.")) | |
600 | 592 | output = s3_rest_controller(prefix, resourcename) | 271 | list.append(T("Review the ‘List of Requests for Volunteers’.")) |
601 | 593 | return output | 272 | list.append(T("To select a Volunteer Task, click on %(apply)s.") % dict(apply="<strong>%s</strong>") % T("‘APPLY’")) |
602 | 594 | else: | 273 | list.append(T("Review the ‘Volunteer Assignment Details’. Enter your Emergency Contact information.")) |
603 | 595 | # Default: Simple Custom View | 274 | list.append(T("Download the Give2LA Volunteer Registration Forms, complete the forms, and take them with you to your Volunteer Assignment.")) |
604 | 596 | response.title = T("Contact us") | 275 | list.append(T("Then click %(commit)s.") % dict(commit="<strong>%s</strong>") % T("Commit")) |
605 | 597 | return dict() | 276 | list.append(T("Review the Volunteer Application details.")) |
606 | 598 | 277 | list.append(T("Then click %(form)s and take them with you to your Volunteer Assignment.") % dict(form="<strong>%s</strong>" % T("'Print Volunteer Assignment Form'"))) | |
607 | 278 | entry = (question, reply, list) | ||
608 | 279 | entries.append(entry) | ||
609 | 280 | question = T("Can I provide feedback or evaluation for an assignment after volunteering?") | ||
610 | 281 | reply = T("Yes. After you have signed-in, follow these steps:") | ||
611 | 282 | list = [] | ||
612 | 283 | list.append(T("On the top menu, click %(volunteer)s.") % dict(volunteer="<strong>%s</strong>") % T("VOLUNTEER")) | ||
613 | 284 | list.append(T("On the left menu, click %(assignments)s.") % dict(assignments="<strong>%s</strong>") % T("‘My Assignments’")) | ||
614 | 285 | list.append(T("Click on the ‘Details’ button of the Volunteer Task you have completed.")) | ||
615 | 286 | list.append(T("Scroll down to the bottom of the screen to get to ‘Evaluation of Event’.")) | ||
616 | 287 | list.append(T("Enter the evaluation details; and click %(save)s") % dict(save="<strong>%s</strong>") % T("Save")) | ||
617 | 288 | entry = (question, reply, list) | ||
618 | 289 | entries.append(entry) | ||
619 | 290 | question = T("I would like to register my corporation for donations, what is the process?") | ||
620 | 291 | reply = T("Follow these steps, to register") | ||
621 | 292 | list = [] | ||
622 | 293 | list.append(T("Locate the %(register)s for Corporations and Organizations on the Home Page and click on it.") % dict(register="<strong>%s</strong>" % T("‘CLICK HERE TO REGISTER’"))) | ||
623 | 294 | list.append(T("Enter the Mandatory details and click on the button %(accept)s at the bottom of the screen to register") % dict(accept="<strong>%s</strong" % T("‘I ACCEPT, CREATE MY ACCOUNT’"))) | ||
624 | 295 | entry = (question, reply, list) | ||
625 | 296 | entries.append(entry) | ||
626 | 297 | |||
627 | 298 | return dict(entries=entries) | ||
628 | 299 | |||
629 | 300 | # ----------------------------------------------------------------------------- | ||
630 | 301 | def faq(): | ||
631 | 302 | """ Custom View """ | ||
632 | 303 | donateLink = A(T("Donate Page"), _href=URL(c="don", f="index")) | ||
633 | 304 | |||
634 | 305 | response.title = T("Frequently Asked Questions") | ||
635 | 306 | entries = [] | ||
636 | 307 | question = T("Is there a minimum age limit to volunteer?") | ||
637 | 308 | reply = T("Yes, you have to be at least 18 years of age to Volunteer.") | ||
638 | 309 | entry = (question, reply) | ||
639 | 310 | entries.append(entry) | ||
640 | 311 | question = T("What is the Privacy policy of Give2LA?") | ||
641 | 312 | reply = T("Please refer to the %(privacy)s") % dict(privacy=A(T("Privacy Policy"), | ||
642 | 313 | _href=URL(c="default", f="disclaimer"))) | ||
643 | 314 | entry = (question, reply) | ||
644 | 315 | entries.append(entry) | ||
645 | 316 | question = T("Can I bring a friend to volunteer?") | ||
646 | 317 | reply = T("Yes, but your friend must also %(register)s and apply to the same Volunteer Assignment.") % dict(register=A(T("Register"), | ||
647 | 318 | _href=URL(c="vol", f="register"))) | ||
648 | 319 | entry = (question, reply) | ||
649 | 320 | entries.append(entry) | ||
650 | 321 | question = T("Will I get any food or reimbursements for expenses while volunteering?") | ||
651 | 322 | reply = T("No, unless it is otherwise stated on the Volunteer Assignment.") | ||
652 | 323 | entry = (question, reply) | ||
653 | 324 | entries.append(entry) | ||
654 | 325 | question = T("Can I donate cash to support the City of Los Angeles?") | ||
655 | 326 | reply = T("Yes, you can donate cash to the %(laepf)s who support the City of Los Angeles or other partner organizations listed on the %(donate)s. These links will take you directly to the organization’s website to complete the cash donation transaction.") % dict(laepf="<a href=http://laemergencypreparednessfoundation.org/>LAEPF</a>", donate=donateLink) | ||
656 | 327 | entry = (question, reply) | ||
657 | 328 | entries.append(entry) | ||
658 | 329 | question = T("What is the process for donating in-kind Items?") | ||
659 | 330 | reply = T("The City of Los Angeles prefers cash donations. In-kind items can be donated directly to the organization(s) listed under Donate Items or through any Upcoming Donation Drive on the %(donate)s") % dict(donate=donateLink) | ||
660 | 331 | entry = (question, reply) | ||
661 | 332 | entries.append(entry) | ||
662 | 333 | question = T("Do I have to be a U.S. citizen or legal U.S. resident to volunteer?") | ||
663 | 334 | reply = T("Yes. You must be a U.S. citizen, legal U.S. resident, or have gained legal entry into the United States.") | ||
664 | 335 | entry = (question, reply) | ||
665 | 336 | entries.append(entry) | ||
666 | 337 | question = T("Do I have to live in the City of Los Angeles to volunteer?") | ||
667 | 338 | reply = T("No, anyone may register to support the City of Los Angeles’ volunteer efforts.") | ||
668 | 339 | entry = (question, reply) | ||
669 | 340 | entries.append(entry) | ||
670 | 341 | question = T("Is my donation tax deductible?") | ||
671 | 342 | reply = T("Yes. All donations are tax deductible. The partner organization that receives your donation will provide a receipt for your donation. Please make sure you obtain your tax receipt from the organization and keep it in a safe place for tax purposes. The City of Los Angeles will not issue receipts for your donation.") | ||
672 | 343 | entry = (question, reply) | ||
673 | 344 | entries.append(entry) | ||
674 | 345 | |||
675 | 346 | return dict(entries=entries) | ||
676 | 347 | |||
677 | 348 | # ----------------------------------------------------------------------------- | ||
678 | 349 | def sitemap(): | ||
679 | 350 | """ Custom View """ | ||
680 | 351 | response.title = T("Site Map") | ||
681 | 352 | return dict() | ||
682 | 353 | |||
683 | 354 | # ----------------------------------------------------------------------------- | ||
684 | 355 | def disclaimer(): | ||
685 | 356 | """ Custom View """ | ||
686 | 357 | response.title = T("Disclaimer") | ||
687 | 358 | return dict() | ||
688 | 359 | |||
689 | 360 | # ----------------------------------------------------------------------------- | ||
690 | 361 | def register(): | ||
691 | 362 | """ | ||
692 | 363 | Registration for Organisations | ||
693 | 364 | - custom form | ||
694 | 365 | """ | ||
695 | 366 | |||
696 | 367 | # Which type of organisation are we registering? | ||
697 | 368 | don = False | ||
698 | 369 | vol = False | ||
699 | 370 | if "type" in request.vars: | ||
700 | 371 | if request.vars.type == "don": | ||
701 | 372 | don = True | ||
702 | 373 | elif request.vars.type == "vol": | ||
703 | 374 | vol = True | ||
704 | 375 | auth.settings.registration_requires_approval = True | ||
705 | 376 | |||
706 | 377 | auth.messages.submit_button = T("I accept. Create my account.") | ||
707 | 378 | request.args = ["register"] | ||
708 | 379 | _table_user.language.default = T.accepted_language | ||
709 | 380 | _table_user.language.readable = False | ||
710 | 381 | _table_user.language.writable = False | ||
711 | 382 | form = auth() | ||
712 | 383 | form.attributes["_id"] = "regform" | ||
713 | 384 | # Custom class for Submit Button | ||
714 | 385 | form[0][-1][0][0]["_class"] = "accept-button" | ||
715 | 386 | |||
716 | 387 | # Cancel button | ||
717 | 388 | form[0][-1][0].append(BR()) | ||
718 | 389 | #form[0][-1][1].append(INPUT(_type="reset", _value=T("Cancel"))) | ||
719 | 390 | form[0][-1][0].append(INPUT(_type="button", | ||
720 | 391 | _value=T("Cancel"), | ||
721 | 392 | _class="wide-grey-button", | ||
722 | 393 | _onClick="javascript: history.go(-1)")) | ||
723 | 394 | |||
724 | 395 | formstyle = s3.crud.formstyle | ||
725 | 396 | |||
726 | 397 | # Organisation | ||
727 | 398 | if form.errors.organisation: | ||
728 | 399 | organisation_error = DIV(form.errors.organisation, | ||
729 | 400 | _id="organisation__error", | ||
730 | 401 | _class="error", | ||
731 | 402 | _style="display: block;") | ||
732 | 403 | else: | ||
733 | 404 | organisation_error = "" | ||
734 | 405 | if don: | ||
735 | 406 | label = T("Corporation/Organization Name") | ||
736 | 407 | else: | ||
737 | 408 | label = T("Organization Name") | ||
738 | 409 | row = formstyle(id = "organisation", | ||
739 | 410 | label = LABEL("%s:" % label, | ||
740 | 411 | SPAN(" *", _class="req")), | ||
741 | 412 | widget = DIV(INPUT(_name="organisation", | ||
742 | 413 | _id="organisation", | ||
743 | 414 | _class="string"), | ||
744 | 415 | organisation_error), | ||
745 | 416 | comment = "") | ||
746 | 417 | form[0].insert(0, row) | ||
747 | 418 | |||
748 | 419 | # Industry Sector | ||
749 | 420 | if vol: | ||
750 | 421 | hidden = True | ||
751 | 422 | widget = INPUT(_name="sector_id", | ||
752 | 423 | _id="sector_id", | ||
753 | 424 | _class="string") | ||
754 | 425 | else: | ||
755 | 426 | from gluon.sqlhtml import OptionsWidget | ||
756 | 427 | hidden = False | ||
757 | 428 | widget = OptionsWidget.widget(db.org_organisation.sector_id, | ||
758 | 429 | value="") | ||
759 | 430 | # dropdown | ||
760 | 431 | row = formstyle(id = "sector_id", | ||
761 | 432 | label = LABEL("%s:" % T("Industry Sector")), | ||
762 | 433 | widget = widget, | ||
763 | 434 | comment = "", | ||
764 | 435 | hidden = hidden) | ||
765 | 436 | form[0].insert(1, row) | ||
766 | 437 | # freetext box for not listed | ||
767 | 438 | row = formstyle(id = "sector_other", | ||
768 | 439 | label = LABEL("%s:" % T("Other Sector not listed")), | ||
769 | 440 | widget = INPUT(_name="sector_other", | ||
770 | 441 | _id="sector_other", | ||
771 | 442 | _class="string"), | ||
772 | 443 | comment = "", | ||
773 | 444 | hidden = hidden) | ||
774 | 445 | form[0].insert(2, row) | ||
775 | 446 | |||
776 | 447 | |||
777 | 448 | # Primary Contact Person section | ||
778 | 449 | row = TR(TD(LABEL(T("Primary Contact")), | ||
779 | 450 | _colspan="3", | ||
780 | 451 | _class="subheading")) | ||
781 | 452 | form[0][2].append(row) | ||
782 | 453 | row = formstyle(id = "middle_name", | ||
783 | 454 | label = LABEL("%s:" % T("Middle Name")), | ||
784 | 455 | widget = INPUT(_name="middle_name", | ||
785 | 456 | _id="middle_name", | ||
786 | 457 | _class="string"), | ||
787 | 458 | comment = "") | ||
788 | 459 | form[0][4].append(row) | ||
789 | 460 | |||
790 | 461 | row = formstyle(id = "secondary_email", | ||
791 | 462 | label = LABEL("%s:" % T("Secondary Email")), | ||
792 | 463 | widget = INPUT(_name="secondary_email", | ||
793 | 464 | _id="secondary_email", | ||
794 | 465 | _class="string"), | ||
795 | 466 | comment = "") | ||
796 | 467 | form[0][12].append(row) | ||
797 | 468 | |||
798 | 469 | # What are you offering? | ||
799 | 470 | if don or vol: | ||
800 | 471 | hidden = True | ||
801 | 472 | else: | ||
802 | 473 | hidden = False | ||
803 | 474 | row = formstyle(id = "offer", | ||
804 | 475 | hidden = hidden, | ||
805 | 476 | label = LABEL("%s:" % T("We can offer"), | ||
806 | 477 | SPAN(" *", _class="req")), | ||
807 | 478 | widget = (T("Items"), | ||
808 | 479 | INPUT(_type="checkbox", | ||
809 | 480 | _value="on", | ||
810 | 481 | value="on" if don else "", | ||
811 | 482 | _name="has_items", | ||
812 | 483 | _id="has_items", | ||
813 | 484 | _class="boolean"), | ||
814 | 485 | T("Volunteers"), | ||
815 | 486 | INPUT(_type="checkbox", | ||
816 | 487 | _value="on", | ||
817 | 488 | value="on" if vol else "", | ||
818 | 489 | _name="vols", | ||
819 | 490 | _id="vols", | ||
820 | 491 | _class="boolean"), | ||
821 | 492 | ), | ||
822 | 493 | comment = "") | ||
823 | 494 | form[0][12].append(row) | ||
824 | 495 | |||
825 | 496 | # Phone | ||
826 | 497 | if form.errors.mobile_phone: | ||
827 | 498 | mobile_phone_error = DIV(form.errors.mobile_phone, | ||
828 | 499 | _id="mobile_phone__error", | ||
829 | 500 | _class="error", | ||
830 | 501 | _style="display: block;") | ||
831 | 502 | else: | ||
832 | 503 | mobile_phone_error = "" | ||
833 | 504 | if form.errors.work_phone: | ||
834 | 505 | work_phone_error = DIV(form.errors.work_phone, | ||
835 | 506 | _id="work_phone__error", | ||
836 | 507 | _class="error", | ||
837 | 508 | _style="display: block;") | ||
838 | 509 | else: | ||
839 | 510 | work_phone_error = "" | ||
840 | 511 | row = formstyle(id = "phone", | ||
841 | 512 | label = LABEL("%s:" % T("Work Phone")), | ||
842 | 513 | widget = DIV(INPUT(_name="work_phone", | ||
843 | 514 | _id="", | ||
844 | 515 | _class="string"), | ||
845 | 516 | work_phone_error), | ||
846 | 517 | comment = "") | ||
847 | 518 | form[0][12].append(row) | ||
848 | 519 | row = formstyle(id = "phone", | ||
849 | 520 | label = LABEL("%s:" % current.deployment_settings.get_ui_label_mobile_phone(), | ||
850 | 521 | SPAN(" *", _class="req")), | ||
851 | 522 | widget = DIV(INPUT(_name="mobile_phone", | ||
852 | 523 | _id="", | ||
853 | 524 | _class="string"), | ||
854 | 525 | mobile_phone_error), | ||
855 | 526 | comment = "") | ||
856 | 527 | form[0][12].append(row) | ||
857 | 528 | |||
858 | 529 | # Address | ||
859 | 530 | row = TR(TD(LABEL(T("Corporation/Organization Address")), | ||
860 | 531 | _colspan="3", | ||
861 | 532 | _class="subheading")) | ||
862 | 533 | form[0][12].append(row) | ||
863 | 534 | if form.errors.address1: | ||
864 | 535 | address1_error = DIV(form.errors.address1, | ||
865 | 536 | _id="address1__error", | ||
866 | 537 | _class="error", | ||
867 | 538 | _style="display: block;") | ||
868 | 539 | else: | ||
869 | 540 | address1_error = "" | ||
870 | 541 | row = formstyle(id = "address1", | ||
871 | 542 | label = LABEL("%s:" % T("Address 1"), | ||
872 | 543 | SPAN(" *", _class="req") | ||
873 | 544 | ), | ||
874 | 545 | widget = (INPUT(_name="address1", | ||
875 | 546 | _id="address1", | ||
876 | 547 | _class="string"), | ||
877 | 548 | address1_error), | ||
878 | 549 | comment = "") | ||
879 | 550 | form[0][12].append(row) | ||
880 | 551 | row = formstyle(id = "address2", | ||
881 | 552 | label = LABEL("%s:" % T("Address 2")), | ||
882 | 553 | widget = INPUT(_name="address2", | ||
883 | 554 | _id="address2", | ||
884 | 555 | _class="string"), | ||
885 | 556 | comment = "") | ||
886 | 557 | form[0][12].append(row) | ||
887 | 558 | row = formstyle(id = "city", | ||
888 | 559 | label = LABEL("%s:" % T("City"), | ||
889 | 560 | SPAN(" *", _class="req")), | ||
890 | 561 | widget = INPUT(_name="city", | ||
891 | 562 | _id = "city", | ||
892 | 563 | _class = "string"), | ||
893 | 564 | comment = "") | ||
894 | 565 | form[0][12].append(row) | ||
895 | 566 | states = S3LocationDropdownWidget(level="L1", | ||
896 | 567 | default="California", | ||
897 | 568 | empty=False) | ||
898 | 569 | widget = states(db.pr_address.location_id, None) | ||
899 | 570 | row = formstyle(id = "state", | ||
900 | 571 | label = LABEL("%s:" % T("State"), | ||
901 | 572 | SPAN(" *", _class="req")), | ||
902 | 573 | widget = widget, | ||
903 | 574 | comment = "") | ||
904 | 575 | form[0][12].append(row) | ||
905 | 576 | if form.errors.zip: | ||
906 | 577 | zip_error = DIV(form.errors.zip, | ||
907 | 578 | _id="zip__error", | ||
908 | 579 | _class="error", | ||
909 | 580 | _style="display: block;") | ||
910 | 581 | else: | ||
911 | 582 | zip_error = "" | ||
912 | 583 | row = formstyle(id = "zip", | ||
913 | 584 | label = LABEL("%s:" % T("Zip"), | ||
914 | 585 | SPAN(" *", _class="req") | ||
915 | 586 | ), | ||
916 | 587 | widget = ( INPUT(_name="zip", | ||
917 | 588 | _id="zip", | ||
918 | 589 | _class="string"), | ||
919 | 590 | zip_error | ||
920 | 591 | ), | ||
921 | 592 | comment = "") | ||
922 | 593 | form[0][12].append(row) | ||
923 | 594 | |||
924 | 595 | |||
925 | 596 | #form[0][-2].append(TR(TD(LABEL(T("Terms of Service:"), | ||
926 | 597 | # _id="terms_of_service__label"), | ||
927 | 598 | # _class="w2p_fl"), | ||
928 | 599 | # TD(LABEL(TEXTAREA(deployment_settings.get_terms_of_service(), | ||
929 | 600 | # _onfocus="this.rows=10", | ||
930 | 601 | # _readonly="readonly", | ||
931 | 602 | # _style="width:100%;text-align:", | ||
932 | 603 | # _cols="80", _rows="10"), | ||
933 | 604 | # _id="terms_of_service"), | ||
934 | 605 | # _class="w2p_fw", | ||
935 | 606 | # _colspan="2"), | ||
936 | 607 | # _id="terms_of_service__row")) | ||
937 | 608 | |||
938 | 609 | # Add client-side validation | ||
939 | 610 | # simplified copy of s3_register_validation() | ||
940 | 611 | script = "".join(( """ | ||
941 | 612 | $('#regform').validate({ | ||
942 | 613 | errorClass: 'req', | ||
943 | 614 | rules: { | ||
944 | 615 | first_name: { | ||
945 | 616 | required: true | ||
946 | 617 | }, | ||
947 | 618 | last_name: { | ||
948 | 619 | required: true | ||
949 | 620 | }, | ||
950 | 621 | email: { | ||
951 | 622 | required: true, | ||
952 | 623 | email: true | ||
953 | 624 | }, | ||
954 | 625 | organisation: { | ||
955 | 626 | required: true | ||
956 | 627 | }, | ||
957 | 628 | mobile_phone: { | ||
958 | 629 | required: true | ||
959 | 630 | }, | ||
960 | 631 | address1: { | ||
961 | 632 | required: true | ||
962 | 633 | }, | ||
963 | 634 | city: { | ||
964 | 635 | required: true | ||
965 | 636 | }, | ||
966 | 637 | zip: { | ||
967 | 638 | required: true | ||
968 | 639 | }, | ||
969 | 640 | password: { | ||
970 | 641 | required: true | ||
971 | 642 | }, | ||
972 | 643 | password_two: { | ||
973 | 644 | required: true, | ||
974 | 645 | equalTo: '.password:first' | ||
975 | 646 | } | ||
976 | 647 | }, | ||
977 | 648 | messages: { | ||
978 | 649 | firstname: '""", str(T("Enter your firstname")), """', | ||
979 | 650 | email: { | ||
980 | 651 | required: '""", str(T("Please enter a valid email address")), """', | ||
981 | 652 | minlength: '""", str(T("Please enter a valid email address")), """' | ||
982 | 653 | }, | ||
983 | 654 | password: { | ||
984 | 655 | required: '""", str(T("Provide a password")), """' | ||
985 | 656 | }, | ||
986 | 657 | password_two: { | ||
987 | 658 | required: '""", str(T("Repeat your password")), """', | ||
988 | 659 | equalTo: '""", str(T("Enter the same password as above")), """' | ||
989 | 660 | } | ||
990 | 661 | }, | ||
991 | 662 | errorPlacement: function(error, element) { | ||
992 | 663 | error.appendTo( element.parent().next() ); | ||
993 | 664 | }, | ||
994 | 665 | submitHandler: function(form) { | ||
995 | 666 | form.submit(); | ||
996 | 667 | } | ||
997 | 668 | });""" )) | ||
998 | 669 | response.s3.jquery_ready.append( script ) | ||
999 | 670 | |||
1000 | 671 | if session.s3.debug: | ||
1001 | 672 | response.s3.scripts.append( "%s/jquery.validate.js" % s3_script_dir ) | ||
1002 | 673 | response.s3.scripts.append( "%s/jquery.pstrength.1.3.js" % s3_script_dir ) | ||
1003 | 674 | else: | ||
1004 | 675 | response.s3.scripts.append( "%s/jquery.validate.min.js" % s3_script_dir ) | ||
1005 | 676 | response.s3.scripts.append( "%s/jquery.pstrength.1.3.min.js" % s3_script_dir ) | ||
1006 | 677 | |||
1007 | 678 | response.s3.jquery_ready.append("$('.password:first').pstrength();\n") | ||
1008 | 679 | |||
1009 | 680 | response.title = T("Register") | ||
1010 | 681 | response.s3.has_required = True | ||
1011 | 682 | |||
1012 | 683 | return dict(form=form) | ||
1013 | 684 | |||
1014 | 685 | # ----------------------------------------------------------------------------- | ||
1015 | 686 | def register_validation(form): | ||
1016 | 687 | """ Validate the custom fields in registration form """ | ||
1017 | 688 | # Name | ||
1018 | 689 | if "organisation" in request.post_vars and request.post_vars.organisation: | ||
1019 | 690 | # Check not in use | ||
1020 | 691 | table = db.org_organisation | ||
1021 | 692 | query = (table.name == request.post_vars.organisation) | ||
1022 | 693 | name = db(query).select(table.id, limitby=(0, 1)).first() | ||
1023 | 694 | if name: | ||
1024 | 695 | form.errors.organisation = T("Organisation Name is already in use") | ||
1025 | 696 | else: | ||
1026 | 697 | form.errors.organisation = T("Organisation Name is required") | ||
1027 | 698 | # Phone | ||
1028 | 699 | if "work_phone" in request.post_vars and request.post_vars.work_phone: | ||
1029 | 700 | regex = re.compile(single_phone_number_pattern) | ||
1030 | 701 | if not regex.match(request.post_vars.work_phone): | ||
1031 | 702 | form.errors.work_phone = T("Invalid phone number") | ||
1032 | 703 | if "mobile_phone" in request.post_vars and request.post_vars.mobile_phone: | ||
1033 | 704 | regex = re.compile(single_phone_number_pattern) | ||
1034 | 705 | if not regex.match(request.post_vars.mobile_phone): | ||
1035 | 706 | form.errors.mobile_phone = T("Invalid phone number") | ||
1036 | 707 | else: | ||
1037 | 708 | form.errors.mobile_phone = T("Phone number is required") | ||
1038 | 709 | # Address | ||
1039 | 710 | if not request.post_vars.address1: | ||
1040 | 711 | form.errors.address1 = T("Address is required") | ||
1041 | 712 | if not request.post_vars.city: | ||
1042 | 713 | form.errors.city = T("City is required") | ||
1043 | 714 | if not request.post_vars.zip: | ||
1044 | 715 | form.errors.zip = T("Zip is required") | ||
1045 | 716 | |||
1046 | 717 | return | ||
1047 | 718 | |||
1048 | 719 | # ----------------------------------------------------------------------------- | ||
1049 | 720 | def register_onaccept(form): | ||
1050 | 721 | # Usual Registration Tasks | ||
1051 | 722 | # (PR record, Authenticated Role, Contacts) | ||
1052 | 723 | person = auth.s3_register(form) | ||
1053 | 724 | |||
1054 | 725 | # LA-specific | ||
1055 | 726 | ptable = db.pr_person | ||
1056 | 727 | query = (ptable.id == person) | ||
1057 | 728 | |||
1058 | 729 | db(query).update(middle_name=request.post_vars.middle_name) | ||
1059 | 730 | |||
1060 | 731 | pe = db(query).select(ptable.pe_id, | ||
1061 | 732 | limitby=(0, 1)).first().pe_id | ||
1062 | 733 | |||
1063 | 734 | # Organisation | ||
1064 | 735 | organisation = request.post_vars.organisation | ||
1065 | 736 | if "vols" in request.post_vars and request.post_vars.vols == "on": | ||
1066 | 737 | has_vols = True | ||
1067 | 738 | else: | ||
1068 | 739 | has_vols = False | ||
1069 | 740 | if "has_items" in request.post_vars and request.post_vars.has_items == "on": | ||
1070 | 741 | has_items = True | ||
1071 | 742 | else: | ||
1072 | 743 | has_items = False | ||
1073 | 744 | |||
1074 | 745 | # Phone | ||
1075 | 746 | table = db.pr_contact | ||
1076 | 747 | work_phone = request.post_vars.work_phone | ||
1077 | 748 | mobile_phone = request.post_vars.mobile_phone | ||
1078 | 749 | if mobile_phone: | ||
1079 | 750 | # Don't auto-subscribe to SMS (priority 10) | ||
1080 | 751 | table.insert(pe_id = pe, | ||
1081 | 752 | contact_method = "SMS", | ||
1082 | 753 | value = mobile_phone, | ||
1083 | 754 | priority=10) | ||
1084 | 755 | if work_phone: | ||
1085 | 756 | # Don't auto-subscribe to SMS (priority 10) | ||
1086 | 757 | table.insert(pe_id = pe, | ||
1087 | 758 | contact_method = "WORK_PHONE", | ||
1088 | 759 | value = work_phone, | ||
1089 | 760 | priority=10) | ||
1090 | 761 | |||
1091 | 762 | # Address | ||
1092 | 763 | address1 = request.post_vars.address1 | ||
1093 | 764 | address2 = request.post_vars.address2 | ||
1094 | 765 | #if address2: | ||
1095 | 766 | # address = "%s\n%s" % (address1, | ||
1096 | 767 | # address2) | ||
1097 | 768 | #else: | ||
1098 | 769 | # address = address1 | ||
1099 | 770 | city = request.post_vars.city | ||
1100 | 771 | state = request.post_vars.location_id | ||
1101 | 772 | zip = request.post_vars.zip | ||
1102 | 773 | if request.post_vars.sector_other: | ||
1103 | 774 | sector_other = "Sector: %s" % request.post_vars.sector_other | ||
1104 | 775 | else: | ||
1105 | 776 | sector_other = "" | ||
1106 | 777 | otable = db.org_organisation | ||
1107 | 778 | org = otable.insert(name = organisation, | ||
1108 | 779 | has_vols = has_vols, | ||
1109 | 780 | has_items = has_items, | ||
1110 | 781 | #phone=phone, | ||
1111 | 782 | address=address1, | ||
1112 | 783 | address_2=address2, | ||
1113 | 784 | L3=city, | ||
1114 | 785 | L1=state, | ||
1115 | 786 | postcode=zip, | ||
1116 | 787 | sector_id=request.post_vars.sector_id, | ||
1117 | 788 | comments=sector_other) | ||
1118 | 789 | record = Storage(id=org) | ||
1119 | 790 | s3mgr.model.update_super(otable, record) | ||
1120 | 791 | auth.s3_set_record_owner(otable, org) | ||
1121 | 792 | # For OrgDons which don't require approval | ||
1122 | 793 | if auth.user: | ||
1123 | 794 | # Update the session | ||
1124 | 795 | auth.user.organisation_id = org | ||
1125 | 796 | user_id = auth.user.id | ||
1126 | 797 | else: | ||
1127 | 798 | user_id = form.vars.id | ||
1128 | 799 | |||
1129 | 800 | # Create HRM | ||
1130 | 801 | table = db.hrm_human_resource | ||
1131 | 802 | hrm = table.insert(person_id = person, | ||
1132 | 803 | organisation_id = org, | ||
1133 | 804 | focal_point = True, | ||
1134 | 805 | owned_by_user = user_id) | ||
1135 | 806 | record = Storage(id=hrm) | ||
1136 | 807 | s3mgr.model.update_super(table, record) | ||
1137 | 808 | auth.s3_set_record_owner(table, hrm) | ||
1138 | 809 | |||
1139 | 810 | # Set the Roles | ||
1140 | 811 | person = db(query).select(ptable.uuid, | ||
1141 | 812 | limitby=(0, 1)).first() | ||
1142 | 813 | if not person: | ||
1143 | 814 | # Error | ||
1144 | 815 | return | ||
1145 | 816 | utable = db[auth.settings.table_user] | ||
1146 | 817 | query = (utable.person_uuid == person.uuid) | ||
1147 | 818 | db(query).update(organisation_id = org) | ||
1148 | 819 | user = db(query).select(utable.id, | ||
1149 | 820 | limitby=(0, 1)).first() | ||
1150 | 821 | if not user: | ||
1151 | 822 | # Error | ||
1152 | 823 | return | ||
1153 | 824 | mtable = db[auth.settings.table_membership] | ||
1154 | 825 | gtable = db[auth.settings.table_group] | ||
1155 | 826 | _org = db(otable.id == org).select(otable.owned_by_organisation, | ||
1156 | 827 | limitby=(0, 1)).first() | ||
1157 | 828 | if _org: | ||
1158 | 829 | mtable.insert(user_id = user.id, | ||
1159 | 830 | group_id = _org.owned_by_organisation) | ||
1160 | 831 | |||
1161 | 832 | if has_vols: | ||
1162 | 833 | OrgVol = db(gtable.uuid == ORG_VOL).select(gtable.id, | ||
1163 | 834 | limitby=(0, 1)).first() | ||
1164 | 835 | if OrgVol: | ||
1165 | 836 | mtable.insert(user_id = user.id, | ||
1166 | 837 | group_id = OrgVol.id) | ||
1167 | 838 | # Go to the Contacts page so that a secondary contact can be added | ||
1168 | 839 | # Flag that we've come from registration for subsequent workflow | ||
1169 | 840 | #redirect(URL(c="vol", f="organisation", args=[org, "human_resource"], | ||
1170 | 841 | # vars={"register":1})) | ||
1171 | 842 | |||
1172 | 843 | if has_items: | ||
1173 | 844 | OrgDon = db(gtable.uuid == ORG_DON).select(gtable.id, | ||
1174 | 845 | limitby=(0, 1)).first() | ||
1175 | 846 | if OrgDon: | ||
1176 | 847 | mtable.insert(user_id = user.id, | ||
1177 | 848 | group_id = OrgDon.id) | ||
1178 | 849 | # Go to the Contacts page so that a secondary contact can be added | ||
1179 | 850 | # Flag that we've come from registration for subsequent workflow | ||
1180 | 851 | redirect(URL(c="don", f="organisation", args=[org, "human_resource"], | ||
1181 | 852 | vars={"register":1})) | ||
1182 | 853 | |||
1183 | 854 | # ----------------------------------------------------------------------------- | ||
1184 | 855 | #auth.settings.registration_requires_approval = True | ||
1185 | 856 | auth.settings.register_onvalidation = register_validation | ||
1186 | 857 | auth.settings.register_onaccept = register_onaccept | ||
1187 | 599 | 858 | ||
1188 | 600 | # END ========================================================================= | 859 | # END ========================================================================= |
1189 | 601 | 860 | ||
1190 | === added file 'controllers/don.py' | |||
1191 | --- controllers/don.py 1970-01-01 00:00:00 +0000 | |||
1192 | +++ controllers/don.py 2011-09-14 11:00:06 +0000 | |||
1193 | @@ -0,0 +1,693 @@ | |||
1194 | 1 | # -*- coding: utf-8 -*- | ||
1195 | 2 | |||
1196 | 3 | """ | ||
1197 | 4 | Donations (LA Specific) | ||
1198 | 5 | |||
1199 | 6 | @author: Michael Howden (michael@sahanafoundation.org) | ||
1200 | 7 | @date-created: 2011-08-02 | ||
1201 | 8 | """ | ||
1202 | 9 | |||
1203 | 10 | |||
1204 | 11 | module = request.controller | ||
1205 | 12 | resourcename = request.function | ||
1206 | 13 | |||
1207 | 14 | if not deployment_settings.has_module(module): | ||
1208 | 15 | raise HTTP(404, body="Module disabled: %s" % module) | ||
1209 | 16 | |||
1210 | 17 | # Options Menu (available in all Functions) | ||
1211 | 18 | shn_menu(module) | ||
1212 | 19 | |||
1213 | 20 | # Load Models | ||
1214 | 21 | s3mgr.load("don_collect") | ||
1215 | 22 | # ----------------------------------------------------------------------------- | ||
1216 | 23 | def index(): | ||
1217 | 24 | """ Custom View """ | ||
1218 | 25 | if s3_has_role(STAFF): | ||
1219 | 26 | redirect(URL(f="req")) | ||
1220 | 27 | else: | ||
1221 | 28 | response.menu_options = [] | ||
1222 | 29 | if session.s3.debug: | ||
1223 | 30 | response.s3.scripts.append( "%s/jquery.hoverIntent.js" % s3_script_dir ) | ||
1224 | 31 | else: | ||
1225 | 32 | response.s3.scripts.append( "%s/jquery.hoverIntent.minified.js" % s3_script_dir ) | ||
1226 | 33 | |||
1227 | 34 | response.title = T("Donate") | ||
1228 | 35 | response.s3.jquery_ready.append(""" | ||
1229 | 36 | $(".donate-popup").css("display", "none"); | ||
1230 | 37 | $(".organizations-list li a").hoverIntent(donateFadeIn, donateFadeOut); | ||
1231 | 38 | """) | ||
1232 | 39 | response.s3.js_global.append(""" | ||
1233 | 40 | function donateFadeIn(){$(this).next(".donate-popup").fadeIn();} | ||
1234 | 41 | function donateFadeOut(){$(this).next(".donate-popup").fadeOut();} | ||
1235 | 42 | """) | ||
1236 | 43 | |||
1237 | 44 | # Get Donation Drives List | ||
1238 | 45 | table = db.don_collect | ||
1239 | 46 | query = ( ( table.end_datetime > request.utcnow ) & | ||
1240 | 47 | ( table.deleted == False ) | ||
1241 | 48 | ) | ||
1242 | 49 | rows = db(query).select( table.start_datetime, | ||
1243 | 50 | table.end_datetime, | ||
1244 | 51 | table.site_id, | ||
1245 | 52 | orderby = table.start_datetime | ||
1246 | 53 | ) | ||
1247 | 54 | if rows: | ||
1248 | 55 | list = [] | ||
1249 | 56 | offset = IS_UTC_OFFSET.get_offset_value(session.s3.utc_offset) | ||
1250 | 57 | for row in rows: | ||
1251 | 58 | if offset: | ||
1252 | 59 | start_datetime = row.start_datetime + datetime.timedelta(seconds=offset) | ||
1253 | 60 | end_datetime = row.end_datetime + datetime.timedelta(seconds=offset) | ||
1254 | 61 | |||
1255 | 62 | start_date = start_datetime.strftime("%b %d") | ||
1256 | 63 | start_time = start_datetime.strftime("%I:%M %p") | ||
1257 | 64 | end_date = end_datetime.strftime("%b %d") | ||
1258 | 65 | end_time = end_datetime.strftime("%I:%M %p") | ||
1259 | 66 | |||
1260 | 67 | site = shn_site_represent(row.site_id, address = True) | ||
1261 | 68 | |||
1262 | 69 | if start_date == end_date: | ||
1263 | 70 | list.append( LI( SPAN( start_date, _class = "date"), | ||
1264 | 71 | " %s - %s" % (start_time, end_time), | ||
1265 | 72 | site, | ||
1266 | 73 | BR() | ||
1267 | 74 | ) | ||
1268 | 75 | ) | ||
1269 | 76 | else: | ||
1270 | 77 | list.append( LI( SPAN( start_date, _class = "date" ), | ||
1271 | 78 | " %s - " % start_time, | ||
1272 | 79 | SPAN( end_date, _class = "date" ), | ||
1273 | 80 | " %s" % end_time, | ||
1274 | 81 | site, | ||
1275 | 82 | BR() | ||
1276 | 83 | ) | ||
1277 | 84 | ) | ||
1278 | 85 | donation_drives = TAG[""](*list) | ||
1279 | 86 | else: | ||
1280 | 87 | donation_drives = P(T("No Donation Drives Scheduled. Please check back later")) | ||
1281 | 88 | |||
1282 | 89 | return dict(donation_drives = donation_drives) | ||
1283 | 90 | |||
1284 | 91 | # ----------------------------------------------------------------------------- | ||
1285 | 92 | def match(): | ||
1286 | 93 | # Get Req Resource Details | ||
1287 | 94 | tablename, req_id = request.vars.viewing.split(".") | ||
1288 | 95 | |||
1289 | 96 | # create fake resource for rheader | ||
1290 | 97 | req = db(db.req_req.id == req_id).select(limitby = (0, 1)).first() | ||
1291 | 98 | r = Storage() | ||
1292 | 99 | r.record = req | ||
1293 | 100 | r.representation = "html" | ||
1294 | 101 | r.name = "don" | ||
1295 | 102 | r.function = "match" | ||
1296 | 103 | r.vars = request.vars | ||
1297 | 104 | rheader = response.s3.don_rheader(r) | ||
1298 | 105 | |||
1299 | 106 | # Get Item Filter | ||
1300 | 107 | req_item = db(db.req_req_item.req_id == req_id).select(db.req_req_item.item_id, | ||
1301 | 108 | limitby = [0,1] | ||
1302 | 109 | ).first() | ||
1303 | 110 | if req_item: | ||
1304 | 111 | item_id = req_item.item_id | ||
1305 | 112 | else: | ||
1306 | 113 | item_id = None | ||
1307 | 114 | response.s3.filter = (db.inv_inv_item.item_id == item_id) | ||
1308 | 115 | |||
1309 | 116 | # Configure inv_item list | ||
1310 | 117 | s3mgr.configure("inv_inv_item", | ||
1311 | 118 | insertable = False, | ||
1312 | 119 | list_fields = ["id", | ||
1313 | 120 | "organisation_id", | ||
1314 | 121 | "item_id", | ||
1315 | 122 | "quantity", | ||
1316 | 123 | "comments"] | ||
1317 | 124 | ) | ||
1318 | 125 | response.s3.actions = [dict(url = URL(c="don", f="req", | ||
1319 | 126 | args = [req_id, "commit"], | ||
1320 | 127 | vars = dict(inv_item_id = "[id]") | ||
1321 | 128 | ), | ||
1322 | 129 | _class = "action-btn", | ||
1323 | 130 | label = str(T("Select")), | ||
1324 | 131 | ) | ||
1325 | 132 | ] | ||
1326 | 133 | s3mgr.load("inv_inv_item") | ||
1327 | 134 | output = response.s3.inv_item_controller() #s3_rest_controller("inv", "inv_item") | ||
1328 | 135 | |||
1329 | 136 | # Customize form | ||
1330 | 137 | output["rheader"] = rheader | ||
1331 | 138 | output["title"] = T("Request for Donations Details") | ||
1332 | 139 | output["subtitle"] = T("Matching Donation Items") | ||
1333 | 140 | |||
1334 | 141 | return output | ||
1335 | 142 | |||
1336 | 143 | # ----------------------------------------------------------------------------- | ||
1337 | 144 | def req(): | ||
1338 | 145 | """ | ||
1339 | 146 | /req/req/default_type=1 | ||
1340 | 147 | """ | ||
1341 | 148 | s3mgr.configure("req_req", | ||
1342 | 149 | list_fields = ["id", | ||
1343 | 150 | #"priority", | ||
1344 | 151 | "status", | ||
1345 | 152 | (T("BOC Status"), "req_commit_status"), | ||
1346 | 153 | "created_on", | ||
1347 | 154 | "date_required", | ||
1348 | 155 | (T("Item"), "item"), | ||
1349 | 156 | "site_id", | ||
1350 | 157 | ], | ||
1351 | 158 | orderby = ["created_on"]) | ||
1352 | 159 | |||
1353 | 160 | s3mgr.load("req_req") | ||
1354 | 161 | request.vars["default_type"] = 1 | ||
1355 | 162 | |||
1356 | 163 | #s3mgr.model.set_method("req", "req", method="match", action = match) | ||
1357 | 164 | |||
1358 | 165 | # Defined in the Model for use from Multiple Controllers for unified menus | ||
1359 | 166 | output = response.s3.req_controller() | ||
1360 | 167 | if "rheader" in output: | ||
1361 | 168 | if len(request.args) >0: | ||
1362 | 169 | args = request.args[0] | ||
1363 | 170 | else: | ||
1364 | 171 | args = None | ||
1365 | 172 | reportButtons = DIV( | ||
1366 | 173 | BUTTON(T("Print Donation Request Form"), | ||
1367 | 174 | _class="accept-button", | ||
1368 | 175 | _onClick="javascript: window.location='%s'" % \ | ||
1369 | 176 | URL(c=request.controller, | ||
1370 | 177 | f="req_print", | ||
1371 | 178 | args=args | ||
1372 | 179 | ) | ||
1373 | 180 | ), | ||
1374 | 181 | # Also in controllers/vol.py - DRY | ||
1375 | 182 | A(IMG(_src="/%s/static/img/get_adobe_reader.png" % request.application, | ||
1376 | 183 | _title="%s - %s" % (T("Get Adobe Reader"), | ||
1377 | 184 | T("This link will open a new browser window.")), | ||
1378 | 185 | _alt=T("Get Adobe Reader"), | ||
1379 | 186 | _width=158, | ||
1380 | 187 | _height=39, | ||
1381 | 188 | _style="float:right;"), | ||
1382 | 189 | _href="http://www.adobe.com/products/acrobat/readstep2.html", | ||
1383 | 190 | _target="_blank"), | ||
1384 | 191 | ) | ||
1385 | 192 | output["rheader"].append(reportButtons) | ||
1386 | 193 | |||
1387 | 194 | return output | ||
1388 | 195 | |||
1389 | 196 | def req_print(): | ||
1390 | 197 | """ Print Donation Request Form """ | ||
1391 | 198 | s3mgr.load("req_req_item") | ||
1392 | 199 | r = s3base.S3Request(s3mgr, | ||
1393 | 200 | prefix="req", | ||
1394 | 201 | name="req_item", | ||
1395 | 202 | extension="pdf") | ||
1396 | 203 | s3mgr.configure("req_req_item", | ||
1397 | 204 | callback = response.s3.donationRequest, | ||
1398 | 205 | formname = T("Request for Donations"), | ||
1399 | 206 | footer = lambda x, y: None, | ||
1400 | 207 | ) | ||
1401 | 208 | return r() | ||
1402 | 209 | |||
1403 | 210 | # ----------------------------------------------------------------------------- | ||
1404 | 211 | # @ToDo: move to inside a prep - only for inv_item components | ||
1405 | 212 | # Add inv_item directly to Org | ||
1406 | 213 | if deployment_settings.has_module("inv"): | ||
1407 | 214 | s3mgr.load("inv_inv_item") | ||
1408 | 215 | |||
1409 | 216 | s3mgr.configure("inv_inv_item", | ||
1410 | 217 | list_fields = ["id", | ||
1411 | 218 | "organisation_id", | ||
1412 | 219 | "item_category_id", | ||
1413 | 220 | "item_id", | ||
1414 | 221 | "pack_value", | ||
1415 | 222 | "quantity", | ||
1416 | 223 | ] | ||
1417 | 224 | ) | ||
1418 | 225 | |||
1419 | 226 | db.inv_inv_item.site_id.readable = db.inv_inv_item.site_id.writable = False | ||
1420 | 227 | db.inv_inv_item.expiry_date.readable = db.inv_inv_item.expiry_date.writable = False | ||
1421 | 228 | # inv_item CRUD strings | ||
1422 | 229 | # INV_ITEM = T(" Donation Item") | ||
1423 | 230 | |||
1424 | 231 | ADD_INV_ITEM = T("Add Donation Item") | ||
1425 | 232 | LIST_INV_ITEMS = T("List Donation Items") | ||
1426 | 233 | s3.crud_strings["inv_inv_item"] = Storage( | ||
1427 | 234 | title_create = ADD_INV_ITEM, | ||
1428 | 235 | title_display = T("Donation Item Details"), | ||
1429 | 236 | title_list = LIST_INV_ITEMS, | ||
1430 | 237 | title_update = T("Edit Donation Item"), | ||
1431 | 238 | title_search = T("Search Donation Items"), | ||
1432 | 239 | subtitle_create = ADD_INV_ITEM, | ||
1433 | 240 | subtitle_list = T("Donation Items"), | ||
1434 | 241 | label_list_button = LIST_INV_ITEMS, | ||
1435 | 242 | label_create_button = ADD_INV_ITEM, | ||
1436 | 243 | label_delete_button = T("Remove Donation Item"), | ||
1437 | 244 | msg_record_created = T("Donation Item Added"), | ||
1438 | 245 | msg_record_modified = T("Donation Item updated"), | ||
1439 | 246 | msg_record_deleted = T("Donation Item removed"), | ||
1440 | 247 | msg_list_empty = T("No Donation Items for this Corporation")) | ||
1441 | 248 | |||
1442 | 249 | ADD_GOODS = T("In the event of a declared disaster we MAY be able to donate the following Goods:") | ||
1443 | 250 | LIST_GOODS = T("List Donation Goods") | ||
1444 | 251 | s3.crud_strings["don_good"] = Storage( | ||
1445 | 252 | title_create = ADD_GOODS, | ||
1446 | 253 | title_display = T("Donation Good Details"), | ||
1447 | 254 | title_list = LIST_GOODS, | ||
1448 | 255 | title_update = T("Edit Donation Goods"), | ||
1449 | 256 | title_search = T("Search Donation Goods"), | ||
1450 | 257 | subtitle_create = ADD_GOODS, | ||
1451 | 258 | subtitle_list = T("Donate Goods"), | ||
1452 | 259 | label_list_button = LIST_GOODS, | ||
1453 | 260 | label_create_button = ADD_GOODS, | ||
1454 | 261 | label_delete_button = T("Remove Donation Goods"), | ||
1455 | 262 | msg_record_created = T("Donation Goods Added"), | ||
1456 | 263 | msg_record_modified = T("Donation Goods updated"), | ||
1457 | 264 | msg_record_deleted = T("Donation Goods removed"), | ||
1458 | 265 | msg_list_empty = T("No Donation Goods for this Corporation")) | ||
1459 | 266 | |||
1460 | 267 | ADD_SERVICE = T("In the event of a declared disaster we MAY be able to donate the following Services:") | ||
1461 | 268 | LIST_SERVICES = T("List Donation Services") | ||
1462 | 269 | s3.crud_strings["don_service"] = Storage( | ||
1463 | 270 | title_create = ADD_SERVICE, | ||
1464 | 271 | title_display = T("Donation Service Details"), | ||
1465 | 272 | title_list = LIST_SERVICES, | ||
1466 | 273 | title_update = T("Edit Donation Service"), | ||
1467 | 274 | title_search = T("Search Donation Services"), | ||
1468 | 275 | subtitle_create = ADD_SERVICE, | ||
1469 | 276 | subtitle_list = T("Donate Services"), | ||
1470 | 277 | label_list_button = LIST_SERVICES, | ||
1471 | 278 | label_create_button = ADD_SERVICE, | ||
1472 | 279 | label_delete_button = T("Remove Donation Service"), | ||
1473 | 280 | msg_record_created = T("Donation Service Added"), | ||
1474 | 281 | msg_record_modified = T("Donation Service updated"), | ||
1475 | 282 | msg_record_deleted = T("Donation Service removed"), | ||
1476 | 283 | msg_list_empty = T("No Donation Services for this Corporation")) | ||
1477 | 284 | |||
1478 | 285 | ADD_FACILITY = T("In the event of a declared disaster we MAY be able to donate the following Facilities:") | ||
1479 | 286 | LIST_FACILITYS = T("List Donation Facilities") | ||
1480 | 287 | s3.crud_strings["don_facility"] = Storage( | ||
1481 | 288 | title_create = ADD_FACILITY, | ||
1482 | 289 | title_display = T("Donation Facility Details"), | ||
1483 | 290 | title_list = LIST_FACILITYS, | ||
1484 | 291 | title_update = T("Edit Donation Facility"), | ||
1485 | 292 | title_search = T("Search Donation Facilities"), | ||
1486 | 293 | subtitle_create = ADD_FACILITY, | ||
1487 | 294 | subtitle_list = T("Donate Facilities"), | ||
1488 | 295 | label_list_button = LIST_FACILITYS, | ||
1489 | 296 | label_create_button = ADD_FACILITY, | ||
1490 | 297 | label_delete_button = T("Remove Donation Facility"), | ||
1491 | 298 | msg_record_created = T("Donation Facility Added"), | ||
1492 | 299 | msg_record_modified = T("Donation Facility updated"), | ||
1493 | 300 | msg_record_deleted = T("Donation Facility removed"), | ||
1494 | 301 | msg_list_empty = T("No Donation Facilities for this Corporation")) | ||
1495 | 302 | |||
1496 | 303 | # ----------------------------------------------------------------------------- | ||
1497 | 304 | def don_item_filter(inv_item_add_filter_func): | ||
1498 | 305 | """ | ||
1499 | 306 | Filter donated 'items' by category | ||
1500 | 307 | Services = category 'SERVICES' | ||
1501 | 308 | Facilities = category 'FACILITY' | ||
1502 | 309 | Goods = everything else | ||
1503 | 310 | """ | ||
1504 | 311 | itable = db.inv_inv_item | ||
1505 | 312 | ctable = db.supply_item_category | ||
1506 | 313 | |||
1507 | 314 | query = (ctable.code == "FACILITY") | ||
1508 | 315 | facility_cat_id = db(query).select(ctable.id, | ||
1509 | 316 | limitby = (0, 1), | ||
1510 | 317 | cache = gis.cache).first().id | ||
1511 | 318 | query = (ctable.code == "SERVICES") | ||
1512 | 319 | service_cat_id = db(query).select(ctable.id, | ||
1513 | 320 | limitby = (0, 1), | ||
1514 | 321 | cache = gis.cache).first().id | ||
1515 | 322 | |||
1516 | 323 | itable.organisation_id.widget = None # Implement SearchACWidget for Organisations | ||
1517 | 324 | itable.organisation_id.requires = IS_NULL_OR(IS_ONE_OF(db, "org_organisation.id", | ||
1518 | 325 | organisation_represent, | ||
1519 | 326 | orderby="org_organisation.name", | ||
1520 | 327 | sort=True, | ||
1521 | 328 | filterby = "has_items", | ||
1522 | 329 | filter_opts = [True]) | ||
1523 | 330 | ) | ||
1524 | 331 | itable.item_id.widget = None | ||
1525 | 332 | |||
1526 | 333 | if not s3_has_role(STAFF): | ||
1527 | 334 | # Only Staff can add Categories | ||
1528 | 335 | itable.item_category_id.comment = "" | ||
1529 | 336 | # Only Staff can add Item Types | ||
1530 | 337 | # @ToDo: Allow adding Items to 'OTHER' category | ||
1531 | 338 | itable.item_id.comment = "" | ||
1532 | 339 | # Only Staff can add Item Units | ||
1533 | 340 | # @ToDo: Should Units for Services/Facilities be hardcoded/hidden? | ||
1534 | 341 | # (always day/ea) | ||
1535 | 342 | comment = DIV(_class="tooltip", | ||
1536 | 343 | _title="%s|%s" % (T("Item Units"), | ||
1537 | 344 | T("The way in which an item is normally distributed"))) | ||
1538 | 345 | script = SCRIPT( | ||
1539 | 346 | """ | ||
1540 | 347 | S3FilterFieldChange({ | ||
1541 | 348 | 'FilterField': 'item_id', | ||
1542 | 349 | 'Field': 'item_pack_id', | ||
1543 | 350 | 'FieldResource':'item_pack', | ||
1544 | 351 | 'FieldPrefix': 'supply', | ||
1545 | 352 | 'msgNoRecords': S3.i18n.no_packs, | ||
1546 | 353 | 'fncPrep': fncPrepItem, | ||
1547 | 354 | 'fncRepresent': fncRepresentItem | ||
1548 | 355 | });""") | ||
1549 | 356 | itable.item_pack_id.comment = TAG[""](comment, script) | ||
1550 | 357 | |||
1551 | 358 | item_type = request.vars.item | ||
1552 | 359 | if item_type == "goods": | ||
1553 | 360 | s3.crud_strings["inv_inv_item"] = s3.crud_strings["don_good"] | ||
1554 | 361 | |||
1555 | 362 | itable.item_category_id.requires = IS_NULL_OR(IS_ONE_OF(db, | ||
1556 | 363 | "supply_item_category.id", | ||
1557 | 364 | "%(name)s", | ||
1558 | 365 | not_filterby = "id", | ||
1559 | 366 | not_filter_opts = [facility_cat_id, service_cat_id], | ||
1560 | 367 | sort=True)) | ||
1561 | 368 | response.s3.jquery_ready = [ | ||
1562 | 369 | """ | ||
1563 | 370 | $(document).ready(function() { | ||
1564 | 371 | S3FilterFieldChange({ | ||
1565 | 372 | 'FilterField': 'item_category_id', | ||
1566 | 373 | 'Field': 'item_id', | ||
1567 | 374 | 'FieldResource':'item', | ||
1568 | 375 | 'FieldPrefix': 'supply', | ||
1569 | 376 | //'url': S3.Ap.concat('/req/req_item_packs/'), | ||
1570 | 377 | //'msgNoRecords': S3.i18n.no_packs, | ||
1571 | 378 | //'fncPrep': fncPrepItem, | ||
1572 | 379 | //'fncRepresent': fncRepresentItem | ||
1573 | 380 | }); | ||
1574 | 381 | }); | ||
1575 | 382 | """ | ||
1576 | 383 | ] | ||
1577 | 384 | query = (itable.item_category_id != facility_cat_id) & \ | ||
1578 | 385 | (itable.item_category_id != service_cat_id) | ||
1579 | 386 | inv_item_add_filter_func( query ) | ||
1580 | 387 | elif item_type in ["services", "facilities"]: | ||
1581 | 388 | if item_type == "services": | ||
1582 | 389 | s3.crud_strings["inv_inv_item"] = s3.crud_strings["don_service"] | ||
1583 | 390 | item_category_filter = service_cat_id | ||
1584 | 391 | itable.item_id.label = T("Service Type") | ||
1585 | 392 | if s3_has_role(STAFF): | ||
1586 | 393 | itable.item_id.comment = DIV(A(T("Add Service Type"), | ||
1587 | 394 | _class="colorbox", | ||
1588 | 395 | _href=URL(c="supply", f="item", | ||
1589 | 396 | args="create", | ||
1590 | 397 | vars=dict(format="popup")), | ||
1591 | 398 | _target="top", | ||
1592 | 399 | _title=T("Add Service Type"))) | ||
1593 | 400 | itable.quantity.label = T("Duration of Donated Services") | ||
1594 | 401 | itable.item_pack_id.label = T("Unit of Time") | ||
1595 | 402 | itable.pack_value.label = T("Estimated Value ($) per Unit of Time") | ||
1596 | 403 | |||
1597 | 404 | elif item_type == "facilities": | ||
1598 | 405 | s3.crud_strings["inv_inv_item"] = s3.crud_strings["don_facility"] | ||
1599 | 406 | item_category_filter = facility_cat_id | ||
1600 | 407 | itable.item_id.label = T("Facility Type") | ||
1601 | 408 | if s3_has_role(STAFF): | ||
1602 | 409 | itable.item_id.comment = DIV(A(T("Add Facility Type"), | ||
1603 | 410 | _class="colorbox", | ||
1604 | 411 | _href=URL(c="supply", f="item", | ||
1605 | 412 | args="create", | ||
1606 | 413 | vars=dict(format="popup")), | ||
1607 | 414 | _target="top", | ||
1608 | 415 | _title=T("Add Facility Type"))) | ||
1609 | 416 | itable.comments.label = T("Comments (Sq. Ft, Bldg Type, Stories)") | ||
1610 | 417 | itable.comments.comment = DIV(_class="tooltip", | ||
1611 | 418 | _title="%s|%s|%s" % (T("Comments"), | ||
1612 | 419 | T("Square Feet, Building Type, Stories."), | ||
1613 | 420 | T("300 character limit."))) | ||
1614 | 421 | |||
1615 | 422 | itable.item_category_id.readable = itable.item_category_id.writable = False | ||
1616 | 423 | itable.item_category_id.default = item_category_filter | ||
1617 | 424 | |||
1618 | 425 | itable.item_id.requires = IS_ONE_OF(db, "supply_item.id", | ||
1619 | 426 | lambda id: response.s3.item_represent(id, | ||
1620 | 427 | show_um = False, | ||
1621 | 428 | show_link = False), | ||
1622 | 429 | filterby = "item_category_id", | ||
1623 | 430 | filter_opts = [item_category_filter], | ||
1624 | 431 | sort=True) | ||
1625 | 432 | |||
1626 | 433 | query = (itable.item_category_id == item_category_filter) | ||
1627 | 434 | inv_item_add_filter_func( query ) | ||
1628 | 435 | # ----------------------------------------------------------------------------- | ||
1629 | 436 | def organisation(): | ||
1630 | 437 | """ | ||
1631 | 438 | /org/organisation/ corporation | ||
1632 | 439 | """ | ||
1633 | 440 | |||
1634 | 441 | otable = db.org_organisation | ||
1635 | 442 | |||
1636 | 443 | otable.acronym.readable = False | ||
1637 | 444 | otable.acronym.writable = False | ||
1638 | 445 | otable.sector_id.readable = True | ||
1639 | 446 | otable.sector_id.writable = True | ||
1640 | 447 | org_has_items_field = otable.has_items | ||
1641 | 448 | org_has_items_field.default = True | ||
1642 | 449 | response.s3.filter = (org_has_items_field == True) | ||
1643 | 450 | |||
1644 | 451 | if not s3_has_role(STAFF): | ||
1645 | 452 | # Tweak the breadcrumb | ||
1646 | 453 | breadcrumbs[2] = (T("Organization Profile"), False, | ||
1647 | 454 | URL(c=request.controller, | ||
1648 | 455 | f=request.function, | ||
1649 | 456 | args=request.args)) | ||
1650 | 457 | |||
1651 | 458 | def corporation_rheader(r, tabs = []): | ||
1652 | 459 | """ Corporation rheader """ | ||
1653 | 460 | |||
1654 | 461 | if r.representation == "html": | ||
1655 | 462 | |||
1656 | 463 | if r.record is None: | ||
1657 | 464 | # List or Create form: rheader makes no sense here | ||
1658 | 465 | return None | ||
1659 | 466 | |||
1660 | 467 | tabs = [(T("Basic Details"), None), | ||
1661 | 468 | (T("Contacts"), "human_resource"), | ||
1662 | 469 | (T("Donate Goods"), "inv_item", dict(item="goods")), | ||
1663 | 470 | (T("Donate Services "), "inv_item", dict(item="services")), | ||
1664 | 471 | (T("Donate Facilities "), "inv_item", dict(item="facilities")), | ||
1665 | 472 | ] | ||
1666 | 473 | if "register" not in request.vars: | ||
1667 | 474 | tabs.append( (T("Donations"), "commit") ) | ||
1668 | 475 | rheader_tabs = s3_rheader_tabs(r, tabs) | ||
1669 | 476 | |||
1670 | 477 | organisation = r.record | ||
1671 | 478 | if organisation.sector_id: | ||
1672 | 479 | _sectors = org_sector_represent(organisation.sector_id) | ||
1673 | 480 | else: | ||
1674 | 481 | _sectors = None | ||
1675 | 482 | |||
1676 | 483 | if deployment_settings.get_ui_cluster(): | ||
1677 | 484 | sector_label = T("Cluster(s)") | ||
1678 | 485 | else: | ||
1679 | 486 | sector_label = T("Sector(s)") | ||
1680 | 487 | |||
1681 | 488 | rheader = DIV(TABLE( | ||
1682 | 489 | TR( | ||
1683 | 490 | TH("%s: " % T("Corporation")), | ||
1684 | 491 | organisation.name, | ||
1685 | 492 | TH("%s: " % sector_label), | ||
1686 | 493 | _sectors | ||
1687 | 494 | )), | ||
1688 | 495 | rheader_tabs | ||
1689 | 496 | ) | ||
1690 | 497 | return rheader | ||
1691 | 498 | return None | ||
1692 | 499 | |||
1693 | 500 | ADD_CORPORATION = T("Add Corporation / Organization") | ||
1694 | 501 | LIST_CORPORATIONS = T("List Corporations & Organizations") | ||
1695 | 502 | s3.crud_strings["org_organisation"] = Storage( | ||
1696 | 503 | title_create = ADD_CORPORATION, | ||
1697 | 504 | title_display = T("Corporation / Organization Details"), | ||
1698 | 505 | title_list = LIST_CORPORATIONS, | ||
1699 | 506 | title_update = T("Edit Corporation / Organization"), | ||
1700 | 507 | title_search = T("Search Corporations & Organizations"), | ||
1701 | 508 | subtitle_create = T("Add New Corporation / Organization"), | ||
1702 | 509 | subtitle_list = T("Corporations & Organizations"), | ||
1703 | 510 | label_list_button = LIST_CORPORATIONS, | ||
1704 | 511 | label_create_button = ADD_CORPORATION, | ||
1705 | 512 | label_delete_button = T("Delete Corporation / Organization"), | ||
1706 | 513 | msg_record_created = T("Corporation / Organization added"), | ||
1707 | 514 | msg_record_modified = T("Corporation / Organization updated"), | ||
1708 | 515 | msg_record_deleted = T("Corporation / Organization deleted"), | ||
1709 | 516 | msg_list_empty = T("No Corporations & Organizations currently registered")) | ||
1710 | 517 | |||
1711 | 518 | s3mgr.load("inv_inv_item") | ||
1712 | 519 | |||
1713 | 520 | def prep(r): | ||
1714 | 521 | don_item_filter(lambda query: | ||
1715 | 522 | r.resource.add_component_filter("inv_item", query)) | ||
1716 | 523 | if r.component and r.component.name == "human_resource": | ||
1717 | 524 | hrtable = db.hrm_human_resource | ||
1718 | 525 | hrtable.type.writable = hrtable.type.readable = False | ||
1719 | 526 | hrtable.status.writable = hrtable.status.readable = False | ||
1720 | 527 | hrtable.focal_point.writable = hrtable.focal_point.readable = False | ||
1721 | 528 | response.s3.jquery_ready.append("$('#hrm_human_resource_person_id__row1').hide();") | ||
1722 | 529 | |||
1723 | 530 | s3.crud_strings["hrm_human_resource"] = Storage( | ||
1724 | 531 | title_create = T("Add Contact"), | ||
1725 | 532 | title_display = T("Contact Details"), | ||
1726 | 533 | title_list = T("Contacts"), | ||
1727 | 534 | title_update = T("Edit Contact"), | ||
1728 | 535 | title_search = T("Search Contacts"), | ||
1729 | 536 | subtitle_create = T("Additional Contacts (optional)"), | ||
1730 | 537 | subtitle_list = T("Contacts"), | ||
1731 | 538 | label_list_button = T("List Contacts"), | ||
1732 | 539 | label_create_button = T("Add Contacts"), | ||
1733 | 540 | label_delete_button = T("Delete Contact"), | ||
1734 | 541 | msg_record_created = T("Contact added"), | ||
1735 | 542 | msg_record_modified = T("Contact updated"), | ||
1736 | 543 | msg_record_deleted = T("Contact deleted"), | ||
1737 | 544 | msg_no_match = T("No Contacts Found"), | ||
1738 | 545 | msg_list_empty = T("Currently there are no Contact registered")) | ||
1739 | 546 | |||
1740 | 547 | # Donation Organization Regisration Workflow | ||
1741 | 548 | if "register" in request.vars: | ||
1742 | 549 | # Only force the open on 1st run | ||
1743 | 550 | response.s3.show_listadd = True | ||
1744 | 551 | s3mgr.configure("hrm_human_resource", | ||
1745 | 552 | create_next = URL(c="don", f="organisation", | ||
1746 | 553 | args = [r.record.id, "inv_item"], | ||
1747 | 554 | vars = dict(item="goods")) | ||
1748 | 555 | ) | ||
1749 | 556 | |||
1750 | 557 | # We don't want this enforced workflow as it doesn't allow adding multiple Goods, etc | ||
1751 | 558 | #if r.component and r.component.name == "inv_item": | ||
1752 | 559 | # next_item = dict(goods = "services", | ||
1753 | 560 | # services = "facilities") | ||
1754 | 561 | # if request.vars.item in next_item: | ||
1755 | 562 | # response.s3.show_listadd = True | ||
1756 | 563 | # url = URL(c="don", f="organisation", | ||
1757 | 564 | # args = [r.record.id, "inv_item"], | ||
1758 | 565 | # vars = dict(item=next_item[request.vars.item], | ||
1759 | 566 | # register=1)) | ||
1760 | 567 | # else: | ||
1761 | 568 | # url = URL(c="don", f="index", args = [], vars = {}) | ||
1762 | 569 | # s3mgr.configure("inv_inv_item", | ||
1763 | 570 | # create_next = url | ||
1764 | 571 | # ) | ||
1765 | 572 | |||
1766 | 573 | # Add req to Corporations as Donations | ||
1767 | 574 | s3mgr.configure("req_commit", | ||
1768 | 575 | insertable = False, | ||
1769 | 576 | editable = False, | ||
1770 | 577 | deletable = False, | ||
1771 | 578 | ) | ||
1772 | 579 | |||
1773 | 580 | s3mgr.configure( "org_organisation", | ||
1774 | 581 | list_fields = ["id", | ||
1775 | 582 | "name", | ||
1776 | 583 | #"type", | ||
1777 | 584 | "sector_id", | ||
1778 | 585 | #"country", | ||
1779 | 586 | #"website" | ||
1780 | 587 | ]) | ||
1781 | 588 | |||
1782 | 589 | # req CRUD strings | ||
1783 | 590 | REQ = T("Donation") | ||
1784 | 591 | #ADD_REQ = T("Add Donation") | ||
1785 | 592 | LIST_REQ = T("List Donations") | ||
1786 | 593 | s3.crud_strings["req_req"] = Storage( | ||
1787 | 594 | #title_create = ADD_REQ, | ||
1788 | 595 | title_display = T("Donation Details"), | ||
1789 | 596 | title_list = LIST_REQ, | ||
1790 | 597 | #title_update = T("Edit Donation"), | ||
1791 | 598 | title_search = T("Search Donations"), | ||
1792 | 599 | #subtitle_create = ADD_REQ, | ||
1793 | 600 | subtitle_list = T("Donations"), | ||
1794 | 601 | label_list_button = LIST_REQ, | ||
1795 | 602 | #label_create_button = ADD_REQ, | ||
1796 | 603 | #label_delete_button = T("Remove Donations"), | ||
1797 | 604 | #msg_record_created = T("Donation Added"), | ||
1798 | 605 | #msg_record_modified = T("Donation updated"), | ||
1799 | 606 | #msg_record_deleted = T("Donation removed"), | ||
1800 | 607 | msg_list_empty = T("No Donations from this Corporation")) | ||
1801 | 608 | |||
1802 | 609 | if not s3_has_role(STAFF): | ||
1803 | 610 | response.s3.donate_cash_link =True | ||
1804 | 611 | |||
1805 | 612 | return organisation_controller(organisation_rheader = corporation_rheader, | ||
1806 | 613 | org_prep = prep) | ||
1807 | 614 | |||
1808 | 615 | # ----------------------------------------------------------------------------- | ||
1809 | 616 | def item(): | ||
1810 | 617 | """ REST Controller """ | ||
1811 | 618 | |||
1812 | 619 | s3mgr.load("inv_inv_item") | ||
1813 | 620 | def inv_item_add_filter_func(query): | ||
1814 | 621 | response.s3.filter = query | ||
1815 | 622 | don_item_filter(inv_item_add_filter_func) | ||
1816 | 623 | |||
1817 | 624 | # Tweak the breadcrumb | ||
1818 | 625 | type = request.get_vars.item | ||
1819 | 626 | if type == "goods": | ||
1820 | 627 | label = T("Goods") | ||
1821 | 628 | elif type == "services": | ||
1822 | 629 | label = T("Services") | ||
1823 | 630 | elif type == "facilities": | ||
1824 | 631 | label = T("Facilities") | ||
1825 | 632 | else: | ||
1826 | 633 | # Error! | ||
1827 | 634 | label = "" | ||
1828 | 635 | breadcrumbs[2] = (label, False, | ||
1829 | 636 | URL(c=request.controller, | ||
1830 | 637 | f=request.function, | ||
1831 | 638 | vars=request.vars)) | ||
1832 | 639 | |||
1833 | 640 | return response.s3.inv_item_controller() | ||
1834 | 641 | |||
1835 | 642 | # ----------------------------------------------------------------------------- | ||
1836 | 643 | def collect(): | ||
1837 | 644 | """ REST Controller """ | ||
1838 | 645 | def prep(r): | ||
1839 | 646 | s3mgr.configure("don_collect", | ||
1840 | 647 | list_fields = ["id", | ||
1841 | 648 | "start_datetime", | ||
1842 | 649 | "end_datetime", | ||
1843 | 650 | "site_id", | ||
1844 | 651 | "organisation_id", | ||
1845 | 652 | ]) | ||
1846 | 653 | return True | ||
1847 | 654 | |||
1848 | 655 | response.s3.prep = prep | ||
1849 | 656 | output = s3_rest_controller(module, resourcename) | ||
1850 | 657 | return output | ||
1851 | 658 | |||
1852 | 659 | # ----------------------------------------------------------------------------- | ||
1853 | 660 | def distribute(): | ||
1854 | 661 | """ REST Controller """ | ||
1855 | 662 | output = s3_rest_controller(module, resourcename) | ||
1856 | 663 | return output | ||
1857 | 664 | |||
1858 | 665 | # ----------------------------------------------------------------------------- | ||
1859 | 666 | def profile(): | ||
1860 | 667 | """ Organisation Profile """ | ||
1861 | 668 | return organisation_profile() | ||
1862 | 669 | |||
1863 | 670 | # ----------------------------------------------------------------------------- | ||
1864 | 671 | ################################################################################ | ||
1865 | 672 | ### Hook to call get the donation certificate | ||
1866 | 673 | ################################################################################ | ||
1867 | 674 | #def certprint(): | ||
1868 | 675 | # """ Print Cert TEST """ | ||
1869 | 676 | # s3mgr.load("don_distribute") | ||
1870 | 677 | # r = s3base.S3Request(s3mgr, | ||
1871 | 678 | # prefix="don", | ||
1872 | 679 | # name="distribute", | ||
1873 | 680 | # extension="pdf") | ||
1874 | 681 | # s3mgr.configure("don_distribute", | ||
1875 | 682 | # callback = response.s3.donationCertificate, | ||
1876 | 683 | # formname = "Donation Certificate", | ||
1877 | 684 | # header = response.s3.donCertBorder, | ||
1878 | 685 | # footer = lambda x, y: None, | ||
1879 | 686 | # ) | ||
1880 | 687 | # return r() | ||
1881 | 688 | ################################################################################ | ||
1882 | 689 | ### | ||
1883 | 690 | ################################################################################ | ||
1884 | 691 | |||
1885 | 692 | |||
1886 | 693 | # END ========================================================================= | ||
1887 | 0 | \ No newline at end of file | 694 | \ No newline at end of file |
1888 | 1 | 695 | ||
1889 | === modified file 'controllers/event.py' | |||
1890 | --- controllers/event.py 2011-08-06 18:24:53 +0000 | |||
1891 | +++ controllers/event.py 2011-09-14 11:00:06 +0000 | |||
1892 | @@ -32,6 +32,16 @@ | |||
1893 | 32 | redirect(URL(f="event", args="create")) | 32 | redirect(URL(f="event", args="create")) |
1894 | 33 | 33 | ||
1895 | 34 | # ============================================================================= | 34 | # ============================================================================= |
1896 | 35 | # Incidents | ||
1897 | 36 | # ============================================================================= | ||
1898 | 37 | def incident(): | ||
1899 | 38 | """ RESTful CRUD controller """ | ||
1900 | 39 | |||
1901 | 40 | tablename = "event_incident" | ||
1902 | 41 | s3mgr.load(tablename) | ||
1903 | 42 | return s3_rest_controller(module, resourcename) | ||
1904 | 43 | |||
1905 | 44 | # ============================================================================= | ||
1906 | 35 | # Events | 45 | # Events |
1907 | 36 | # ============================================================================= | 46 | # ============================================================================= |
1908 | 37 | def event(): | 47 | def event(): |
1909 | @@ -184,7 +194,7 @@ | |||
1910 | 184 | tabs.append((T("Map Configuration"), "config")) | 194 | tabs.append((T("Map Configuration"), "config")) |
1911 | 185 | 195 | ||
1912 | 186 | rheader = lambda r, tabs=tabs: event_rheader(r, tabs) | 196 | rheader = lambda r, tabs=tabs: event_rheader(r, tabs) |
1914 | 187 | output = s3_rest_controller("event", resourcename, | 197 | output = s3_rest_controller(module, resourcename, |
1915 | 188 | rheader=rheader) | 198 | rheader=rheader) |
1916 | 189 | return output | 199 | return output |
1917 | 190 | 200 | ||
1918 | 191 | 201 | ||
1919 | === modified file 'controllers/gis.py' | |||
1920 | --- controllers/gis.py 2011-08-11 23:34:08 +0000 | |||
1921 | +++ controllers/gis.py 2011-09-14 11:00:06 +0000 | |||
1922 | @@ -63,7 +63,7 @@ | |||
1923 | 63 | catalogue_toolbar = False | 63 | catalogue_toolbar = False |
1924 | 64 | 64 | ||
1925 | 65 | # @ToDo: Make these configurable | 65 | # @ToDo: Make these configurable |
1927 | 66 | search = True | 66 | search = False |
1928 | 67 | googleEarth = True | 67 | googleEarth = True |
1929 | 68 | googleStreetview = True | 68 | googleStreetview = True |
1930 | 69 | catalogue_layers = True | 69 | catalogue_layers = True |
1931 | @@ -92,7 +92,8 @@ | |||
1932 | 92 | search=search, | 92 | search=search, |
1933 | 93 | catalogue_layers=catalogue_layers, | 93 | catalogue_layers=catalogue_layers, |
1934 | 94 | mouse_position = mouse_position, | 94 | mouse_position = mouse_position, |
1936 | 95 | print_tool = print_tool | 95 | print_tool = print_tool, |
1937 | 96 | collapsed = True | ||
1938 | 96 | ) | 97 | ) |
1939 | 97 | 98 | ||
1940 | 98 | return map | 99 | return map |
1941 | 99 | 100 | ||
1942 | === modified file 'controllers/hrm.py' | |||
1943 | --- controllers/hrm.py 2011-08-28 19:50:18 +0000 | |||
1944 | +++ controllers/hrm.py 2011-09-14 11:00:06 +0000 | |||
1945 | @@ -915,4 +915,197 @@ | |||
1946 | 915 | redirect_vars = {fieldname: id}, | 915 | redirect_vars = {fieldname: id}, |
1947 | 916 | title_name = title) | 916 | title_name = title) |
1948 | 917 | 917 | ||
1949 | 918 | # ============================================================================= | ||
1950 | 919 | # Adding a human resource inline | ||
1951 | 920 | # ============================================================================= | ||
1952 | 921 | |||
1953 | 922 | def create_inline(): | ||
1954 | 923 | add_object_inline = local_import("s3.add_object_inline").add_object_inline | ||
1955 | 924 | # Set up fields | ||
1956 | 925 | pr_person = db.pr_person | ||
1957 | 926 | hrm_human_resource = db.hrm_human_resource | ||
1958 | 927 | |||
1959 | 928 | field_dict = { | ||
1960 | 929 | "first_name": pr_person.first_name, | ||
1961 | 930 | "middle_name": pr_person.middle_name, | ||
1962 | 931 | "last_name": pr_person.last_name, | ||
1963 | 932 | |||
1964 | 933 | "job_title": hrm_human_resource.job_title, | ||
1965 | 934 | "organisation_id": hrm_human_resource.organisation_id, | ||
1966 | 935 | } | ||
1967 | 936 | |||
1968 | 937 | emailRequired = ( | ||
1969 | 938 | request.controller == "hrm" and | ||
1970 | 939 | deployment_settings.get_hrm_email_required() | ||
1971 | 940 | ) | ||
1972 | 941 | |||
1973 | 942 | if emailRequired: | ||
1974 | 943 | email_validator = IS_EMAIL() | ||
1975 | 944 | else: | ||
1976 | 945 | email_validator = IS_NULL_OR(IS_EMAIL()) | ||
1977 | 946 | |||
1978 | 947 | email_field_name = "email_address" | ||
1979 | 948 | mobile_phone_field_name = "mobile_phone" | ||
1980 | 949 | field_dict.update({ | ||
1981 | 950 | email_field_name: Field( | ||
1982 | 951 | email_field_name, | ||
1983 | 952 | notnull=emailRequired, | ||
1984 | 953 | requires=email_validator, | ||
1985 | 954 | label=T("Email Address") | ||
1986 | 955 | ), | ||
1987 | 956 | mobile_phone_field_name: Field( | ||
1988 | 957 | mobile_phone_field_name, | ||
1989 | 958 | label=T("Mobile Phone Number") | ||
1990 | 959 | ) | ||
1991 | 960 | }) | ||
1992 | 961 | |||
1993 | 962 | |||
1994 | 963 | def validate_and_set_up_result( | ||
1995 | 964 | update_result, | ||
1996 | 965 | errors, | ||
1997 | 966 | var, | ||
1998 | 967 | check_request_var_matches_value_if_given, | ||
1999 | 968 | existing | ||
2000 | 969 | ): | ||
2001 | 970 | pr_contact = db.pr_contact | ||
2002 | 971 | pr_person = db.pr_person | ||
2003 | 972 | |||
2004 | 973 | existing_email_contact = None | ||
2005 | 974 | existing_mobile_phone_contact = None | ||
2006 | 975 | existing_person = None | ||
2007 | 976 | existing_human_resource = None | ||
2008 | 977 | |||
2009 | 978 | def check_attributes_match(existing_object, attribute_names): | ||
2010 | 979 | for attribute_name in attribute_names: | ||
2011 | 980 | check_request_var_matches_value_if_given( | ||
2012 | 981 | attribute_name, | ||
2013 | 982 | field_dict[attribute_name].label, | ||
2014 | 983 | getattr(existing_object, attribute_name) | ||
2015 | 984 | ) | ||
2016 | 985 | |||
2017 | 986 | # look for a person with the same email address | ||
2018 | 987 | email_address = var(email_field_name) | ||
2019 | 988 | if email_address: | ||
2020 | 989 | existing_email_contact = existing( | ||
2021 | 990 | (pr_contact.contact_method == "EMAIL") & | ||
2022 | 991 | (pr_contact.value == email_address) | ||
2023 | 992 | ) | ||
2024 | 993 | if existing_email_contact is not None: | ||
2025 | 994 | # check every other contact detail matches, otherwise complain | ||
2026 | 995 | |||
2027 | 996 | # mobile phone | ||
2028 | 997 | existing_mobile_phone_contact = existing( | ||
2029 | 998 | (pr_contact.contact_method == "MOBILE PHONE") & | ||
2030 | 999 | (pr_contact.pe_id == existing_email_contact.pe_id) | ||
2031 | 1000 | ) | ||
2032 | 1001 | if existing_mobile_phone_contact is not None: | ||
2033 | 1002 | check_request_var_matches_value_if_given( | ||
2034 | 1003 | mobile_phone_field_name, | ||
2035 | 1004 | field_dict[mobile_phone_field_name].label, | ||
2036 | 1005 | existing_mobile_phone_contact.value | ||
2037 | 1006 | ) | ||
2038 | 1007 | |||
2039 | 1008 | # person details | ||
2040 | 1009 | existing_person = existing( | ||
2041 | 1010 | pr_person.pe_id == existing_email_contact.pe_id | ||
2042 | 1011 | ) | ||
2043 | 1012 | if existing_person is not None: | ||
2044 | 1013 | check_attributes_match( | ||
2045 | 1014 | existing_person, | ||
2046 | 1015 | ( | ||
2047 | 1016 | "first_name", | ||
2048 | 1017 | "middle_name", | ||
2049 | 1018 | "last_name" | ||
2050 | 1019 | ) | ||
2051 | 1020 | ) | ||
2052 | 1021 | |||
2053 | 1022 | # human resource | ||
2054 | 1023 | existing_human_resource = existing( | ||
2055 | 1024 | hrm_human_resource.person_id == existing_person.id | ||
2056 | 1025 | ) | ||
2057 | 1026 | if existing_human_resource is not None: | ||
2058 | 1027 | check_attributes_match( | ||
2059 | 1028 | existing_human_resource, | ||
2060 | 1029 | ( | ||
2061 | 1030 | "job_title", | ||
2062 | 1031 | "organisation_id", | ||
2063 | 1032 | ) | ||
2064 | 1033 | ) | ||
2065 | 1034 | |||
2066 | 1035 | # an email address is assumed to uniquely identify a person | ||
2067 | 1036 | # however, there is no guarantee that a person has an email address | ||
2068 | 1037 | if existing_email_contact is None: | ||
2069 | 1038 | # there is no pr_pentity | ||
2070 | 1039 | pe_id = db.pr_pentity.insert().pe_id | ||
2071 | 1040 | |||
2072 | 1041 | db.pr_contact.insert( | ||
2073 | 1042 | pe_id = pe_id, | ||
2074 | 1043 | contact_method = "EMAIL", | ||
2075 | 1044 | value = email_address, | ||
2076 | 1045 | ) | ||
2077 | 1046 | else: | ||
2078 | 1047 | contact_id = existing_email_contact.id | ||
2079 | 1048 | pe_id = existing_email_contact.pe_id | ||
2080 | 1049 | |||
2081 | 1050 | assert pe_id is not None | ||
2082 | 1051 | |||
2083 | 1052 | if existing_mobile_phone_contact is None: | ||
2084 | 1053 | if var(mobile_phone_field_name): | ||
2085 | 1054 | db.pr_contact.insert( | ||
2086 | 1055 | pe_id = pe_id, | ||
2087 | 1056 | contact_method = "MOBILE PHONE", | ||
2088 | 1057 | value = var(mobile_phone_field_name) | ||
2089 | 1058 | ) | ||
2090 | 1059 | |||
2091 | 1060 | if existing_person is None: | ||
2092 | 1061 | person_id = db.pr_person.insert( | ||
2093 | 1062 | pe_id = pe_id, | ||
2094 | 1063 | first_name = var("first_name"), | ||
2095 | 1064 | middle_name = var("middle_name"), | ||
2096 | 1065 | last_name = var("last_name") | ||
2097 | 1066 | ) | ||
2098 | 1067 | else: | ||
2099 | 1068 | person_id = existing_person.id | ||
2100 | 1069 | else: | ||
2101 | 1070 | errors[email_field_name] = T("Required") | ||
2102 | 1071 | |||
2103 | 1072 | if errors: | ||
2104 | 1073 | response.flash = T("form invalid") | ||
2105 | 1074 | else: | ||
2106 | 1075 | response.flash = T("form accepted") | ||
2107 | 1076 | if existing_human_resource: | ||
2108 | 1077 | result_human_resource = existing_human_resource | ||
2109 | 1078 | else: | ||
2110 | 1079 | result_human_resource = db.hrm_human_resource.insert( | ||
2111 | 1080 | person_id = person_id, | ||
2112 | 1081 | job_title = var("job_title"), | ||
2113 | 1082 | organisation_id = var("organisation_id") | ||
2114 | 1083 | ) | ||
2115 | 1084 | db.commit() | ||
2116 | 1085 | update_result( | ||
2117 | 1086 | created_object_id = result_human_resource.id, | ||
2118 | 1087 | created_object_representation = hrm_human_resource_represent( | ||
2119 | 1088 | result_human_resource | ||
2120 | 1089 | ) | ||
2121 | 1090 | ) | ||
2122 | 1091 | |||
2123 | 1092 | return add_object_inline( | ||
2124 | 1093 | db = db, | ||
2125 | 1094 | formstyle = s3_formstyle, | ||
2126 | 1095 | fields = field_dict.values(), | ||
2127 | 1096 | table = db.hrm_human_resource, | ||
2128 | 1097 | table_name = "hrm_human_resource", | ||
2129 | 1098 | template = "inner_form.html", | ||
2130 | 1099 | validate_and_set_up_result = validate_and_set_up_result, | ||
2131 | 1100 | s3_mark_required = s3_mark_required, | ||
2132 | 1101 | TAG = TAG, | ||
2133 | 1102 | SPAN = SPAN, | ||
2134 | 1103 | response = response, | ||
2135 | 1104 | SQLFORM = SQLFORM, | ||
2136 | 1105 | T = T, | ||
2137 | 1106 | INPUT = INPUT, | ||
2138 | 1107 | XML = XML, | ||
2139 | 1108 | request = request, | ||
2140 | 1109 | ) | ||
2141 | 1110 | |||
2142 | 918 | # END ========================================================================= | 1111 | # END ========================================================================= |
2143 | 919 | 1112 | ||
2144 | === added file 'controllers/master.py' | |||
2145 | --- controllers/master.py 1970-01-01 00:00:00 +0000 | |||
2146 | +++ controllers/master.py 2011-09-14 11:00:06 +0000 | |||
2147 | @@ -0,0 +1,22 @@ | |||
2148 | 1 | # -*- coding: utf-8 -*- | ||
2149 | 2 | |||
2150 | 3 | """ | ||
2151 | 4 | Master Data - Controllers | ||
2152 | 5 | |||
2153 | 6 | @author: Fran | ||
2154 | 7 | """ | ||
2155 | 8 | |||
2156 | 9 | module = request.controller | ||
2157 | 10 | |||
2158 | 11 | if module not in deployment_settings.modules: | ||
2159 | 12 | raise HTTP(404, body="Module disabled: %s" % module) | ||
2160 | 13 | |||
2161 | 14 | # Options Menu (available in all Functions' Views) | ||
2162 | 15 | shn_menu(module) | ||
2163 | 16 | |||
2164 | 17 | def index(): | ||
2165 | 18 | "Module's Home Page" | ||
2166 | 19 | |||
2167 | 20 | module_name = deployment_settings.modules[module].name_nice | ||
2168 | 21 | response.title = module_name | ||
2169 | 22 | return dict(module_name=module_name) | ||
2170 | 0 | 23 | ||
2171 | === modified file 'controllers/org.py' | |||
2172 | --- controllers/org.py 2011-08-06 18:24:53 +0000 | |||
2173 | +++ controllers/org.py 2011-09-14 11:00:06 +0000 | |||
2174 | @@ -159,4 +159,87 @@ | |||
2175 | 159 | 159 | ||
2176 | 160 | return output | 160 | return output |
2177 | 161 | 161 | ||
2178 | 162 | |||
2179 | 163 | def add_site_inline(): | ||
2180 | 164 | formstyle = s3_formstyle | ||
2181 | 165 | |||
2182 | 166 | org_office = db.org_office | ||
2183 | 167 | field_names = [ | ||
2184 | 168 | "type", | ||
2185 | 169 | "name", | ||
2186 | 170 | "address", | ||
2187 | 171 | "address_2", | ||
2188 | 172 | "L3", | ||
2189 | 173 | "L1", | ||
2190 | 174 | "postcode", | ||
2191 | 175 | "phone1", | ||
2192 | 176 | "email", | ||
2193 | 177 | ] | ||
2194 | 178 | field_dict = {} | ||
2195 | 179 | for field_name in field_names: | ||
2196 | 180 | field_dict[field_name] = getattr(org_office, field_name) | ||
2197 | 181 | |||
2198 | 182 | def validate_and_set_up_result( | ||
2199 | 183 | update_result, errors, var, | ||
2200 | 184 | check_request_var_matches_value_if_given, | ||
2201 | 185 | existing | ||
2202 | 186 | ): | ||
2203 | 187 | # look for an office with the same name | ||
2204 | 188 | name = var("name") | ||
2205 | 189 | if name: | ||
2206 | 190 | existing_office = existing( | ||
2207 | 191 | org_office.name == name | ||
2208 | 192 | ) | ||
2209 | 193 | if existing_office is not None: | ||
2210 | 194 | for field_name, field in field_dict.iteritems(): | ||
2211 | 195 | print field_name | ||
2212 | 196 | check_request_var_matches_value_if_given( | ||
2213 | 197 | field_name, | ||
2214 | 198 | field.label, | ||
2215 | 199 | getattr(existing_office, field_name) | ||
2216 | 200 | ) | ||
2217 | 201 | else: | ||
2218 | 202 | existing_office = None | ||
2219 | 203 | |||
2220 | 204 | if errors: | ||
2221 | 205 | response.flash = T("form is invalid") | ||
2222 | 206 | else: | ||
2223 | 207 | response.flash = T("form accepted") | ||
2224 | 208 | if existing_office: | ||
2225 | 209 | result_object = existing_office | ||
2226 | 210 | else: | ||
2227 | 211 | result_object = db.org_office.insert( | ||
2228 | 212 | **dict( | ||
2229 | 213 | (field_name, var(field_name)) for field_name in field_names | ||
2230 | 214 | ) | ||
2231 | 215 | ) | ||
2232 | 216 | db.commit() | ||
2233 | 217 | update_result( | ||
2234 | 218 | created_object_id = existing_office.id, | ||
2235 | 219 | created_object_representation = existing_office.name | ||
2236 | 220 | ) | ||
2237 | 221 | |||
2238 | 222 | |||
2239 | 223 | add_object_inline = local_import("s3.add_object_inline").add_object_inline | ||
2240 | 224 | |||
2241 | 225 | return add_object_inline( | ||
2242 | 226 | db = db, | ||
2243 | 227 | formstyle = s3_formstyle, | ||
2244 | 228 | fields = field_dict.values(), | ||
2245 | 229 | table = db.org_office, | ||
2246 | 230 | table_name = "org_office", | ||
2247 | 231 | template = "inner_form.html", | ||
2248 | 232 | validate_and_set_up_result = validate_and_set_up_result, | ||
2249 | 233 | s3_mark_required = s3_mark_required, | ||
2250 | 234 | TAG = TAG, | ||
2251 | 235 | SPAN = SPAN, | ||
2252 | 236 | response = response, | ||
2253 | 237 | SQLFORM = SQLFORM, | ||
2254 | 238 | T = T, | ||
2255 | 239 | INPUT = INPUT, | ||
2256 | 240 | XML = XML, | ||
2257 | 241 | request = request, | ||
2258 | 242 | ) | ||
2259 | 243 | |||
2260 | 244 | |||
2261 | 162 | # END ========================================================================= | 245 | # END ========================================================================= |
2262 | 163 | 246 | ||
2263 | === modified file 'controllers/project.py' | |||
2264 | --- controllers/project.py 2011-08-06 18:24:53 +0000 | |||
2265 | +++ controllers/project.py 2011-09-14 11:00:06 +0000 | |||
2266 | @@ -17,7 +17,6 @@ | |||
2267 | 17 | 17 | ||
2268 | 18 | # ============================================================================= | 18 | # ============================================================================= |
2269 | 19 | def index(): | 19 | def index(): |
2270 | 20 | |||
2271 | 21 | """ Module's Home Page """ | 20 | """ Module's Home Page """ |
2272 | 22 | 21 | ||
2273 | 23 | module_name = deployment_settings.modules[module].name_nice | 22 | module_name = deployment_settings.modules[module].name_nice |
2274 | @@ -31,21 +30,18 @@ | |||
2275 | 31 | 30 | ||
2276 | 32 | # ============================================================================= | 31 | # ============================================================================= |
2277 | 33 | def need(): | 32 | def need(): |
2278 | 34 | |||
2279 | 35 | """ RESTful CRUD controller """ | 33 | """ RESTful CRUD controller """ |
2280 | 36 | 34 | ||
2281 | 37 | return s3_rest_controller(module, resourcename) | 35 | return s3_rest_controller(module, resourcename) |
2282 | 38 | 36 | ||
2283 | 39 | # ----------------------------------------------------------------------------- | 37 | # ----------------------------------------------------------------------------- |
2284 | 40 | def need_type(): | 38 | def need_type(): |
2285 | 41 | |||
2286 | 42 | """ RESTful CRUD controller """ | 39 | """ RESTful CRUD controller """ |
2287 | 43 | 40 | ||
2288 | 44 | return s3_rest_controller(module, resourcename) | 41 | return s3_rest_controller(module, resourcename) |
2289 | 45 | 42 | ||
2290 | 46 | # ============================================================================= | 43 | # ============================================================================= |
2291 | 47 | def project(): | 44 | def project(): |
2292 | 48 | |||
2293 | 49 | """ RESTful CRUD controller """ | 45 | """ RESTful CRUD controller """ |
2294 | 50 | 46 | ||
2295 | 51 | tablename = "%s_%s" % (module, resourcename) | 47 | tablename = "%s_%s" % (module, resourcename) |
2296 | @@ -71,65 +67,13 @@ | |||
2297 | 71 | 67 | ||
2298 | 72 | # ============================================================================= | 68 | # ============================================================================= |
2299 | 73 | def activity(): | 69 | def activity(): |
2300 | 74 | |||
2301 | 75 | """ RESTful CRUD controller """ | 70 | """ RESTful CRUD controller """ |
2302 | 76 | 71 | ||
2355 | 77 | tablename = "%s_%s" % (module, resourcename) | 72 | # Defined in the Model for use from Multiple Controllers for unified menus |
2356 | 78 | table = db[tablename] | 73 | return response.s3.project_activity_controller() |
2305 | 79 | |||
2306 | 80 | tabs = [ | ||
2307 | 81 | (T("Details"), None), | ||
2308 | 82 | (T("Requests"), "req"), | ||
2309 | 83 | (T("Documents"), "document"), | ||
2310 | 84 | (T("Photos"), "image"), | ||
2311 | 85 | #(T("Shipments To"), "rms_req"), | ||
2312 | 86 | ] | ||
2313 | 87 | rheader = lambda r: activity_rheader(r, tabs) | ||
2314 | 88 | |||
2315 | 89 | if "create" in request.args: | ||
2316 | 90 | # Default values (from gap_report) set for fields | ||
2317 | 91 | default_fieldnames = ["location_id", "need_type_id"] | ||
2318 | 92 | for fieldname in default_fieldnames: | ||
2319 | 93 | if fieldname in request.vars: | ||
2320 | 94 | table[fieldname].default = request.vars[fieldname] | ||
2321 | 95 | table[fieldname].writable = False | ||
2322 | 96 | table[fieldname].comment = None | ||
2323 | 97 | |||
2324 | 98 | return s3_rest_controller(module, resourcename, | ||
2325 | 99 | rheader = rheader) | ||
2326 | 100 | |||
2327 | 101 | # ----------------------------------------------------------------------------- | ||
2328 | 102 | def activity_rheader(r, tabs=[]): | ||
2329 | 103 | """ Resource Header for Activities""" | ||
2330 | 104 | |||
2331 | 105 | if r.representation == "html": | ||
2332 | 106 | record = r.record | ||
2333 | 107 | if record: | ||
2334 | 108 | rheader_tabs = s3_rheader_tabs(r, tabs) | ||
2335 | 109 | rheader = DIV( TABLE( | ||
2336 | 110 | TR( TH( "%s: " % T("Short Description")), | ||
2337 | 111 | record.name, | ||
2338 | 112 | ), | ||
2339 | 113 | TR( TH( "%s: " % T("Location")), | ||
2340 | 114 | gis_location_represent(record.location_id), | ||
2341 | 115 | TH( "%s: " % T("Duration")), | ||
2342 | 116 | "%s to %s" % (record.start_date, | ||
2343 | 117 | record.end_date), | ||
2344 | 118 | ), | ||
2345 | 119 | TR( TH( "%s: " % T("Organization")), | ||
2346 | 120 | organisation_represent(record.organisation_id), | ||
2347 | 121 | TH( "%s: " % SECTOR), | ||
2348 | 122 | shn_org_sector_represent(record.sector_id), | ||
2349 | 123 | ), | ||
2350 | 124 | ), | ||
2351 | 125 | rheader_tabs | ||
2352 | 126 | ) | ||
2353 | 127 | return rheader | ||
2354 | 128 | return None | ||
2357 | 129 | 74 | ||
2358 | 130 | # ============================================================================= | 75 | # ============================================================================= |
2359 | 131 | def task(): | 76 | def task(): |
2360 | 132 | |||
2361 | 133 | """ RESTful CRUD controller """ | 77 | """ RESTful CRUD controller """ |
2362 | 134 | 78 | ||
2363 | 135 | # Pre-process | 79 | # Pre-process |
2364 | @@ -211,7 +155,6 @@ | |||
2365 | 211 | 155 | ||
2366 | 212 | # ============================================================================= | 156 | # ============================================================================= |
2367 | 213 | def gap_report(): | 157 | def gap_report(): |
2368 | 214 | |||
2369 | 215 | """ Provide a Report on Gaps between Activities & Needs Assessments """ | 158 | """ Provide a Report on Gaps between Activities & Needs Assessments """ |
2370 | 216 | 159 | ||
2371 | 217 | # Get all assess_summary | 160 | # Get all assess_summary |
2372 | 218 | 161 | ||
2373 | === modified file 'controllers/req.py' | |||
2374 | --- controllers/req.py 2011-08-07 08:48:01 +0000 | |||
2375 | +++ controllers/req.py 2011-09-14 11:00:06 +0000 | |||
2376 | @@ -37,9 +37,13 @@ | |||
2377 | 37 | - custom View | 37 | - custom View |
2378 | 38 | """ | 38 | """ |
2379 | 39 | 39 | ||
2383 | 40 | module_name = deployment_settings.modules[module].name_nice | 40 | if s3_has_role("ADMIN"): |
2384 | 41 | response.title = module_name | 41 | module_name = deployment_settings.modules[module].name_nice |
2385 | 42 | return dict(module_name=module_name) | 42 | response.title = module_name |
2386 | 43 | return dict(module_name=module_name) | ||
2387 | 44 | |||
2388 | 45 | else: | ||
2389 | 46 | redirect(URL(f="req_skill")) | ||
2390 | 43 | 47 | ||
2391 | 44 | # ----------------------------------------------------------------------------- | 48 | # ----------------------------------------------------------------------------- |
2392 | 45 | def is_affiliated(): | 49 | def is_affiliated(): |
2393 | @@ -65,7 +69,7 @@ | |||
2394 | 65 | def create(): | 69 | def create(): |
2395 | 66 | """ Redirect to req/create """ | 70 | """ Redirect to req/create """ |
2396 | 67 | redirect(URL(f="req", args="create")) | 71 | redirect(URL(f="req", args="create")) |
2398 | 68 | 72 | ||
2399 | 69 | # ----------------------------------------------------------------------------- | 73 | # ----------------------------------------------------------------------------- |
2400 | 70 | def req(): | 74 | def req(): |
2401 | 71 | """ REST Controller """ | 75 | """ REST Controller """ |
2402 | @@ -135,10 +139,10 @@ | |||
2403 | 135 | 139 | ||
2404 | 136 | output["title"] = T("Request Item from Available Inventory") | 140 | output["title"] = T("Request Item from Available Inventory") |
2405 | 137 | output["req_btn"] = A( T("Return to Request"), | 141 | output["req_btn"] = A( T("Return to Request"), |
2410 | 138 | _href = URL( c = "req", | 142 | _href = URL(c = "req", |
2411 | 139 | f = "req", | 143 | f = "req", |
2412 | 140 | args = [req_item.req_id, "req_item"] | 144 | args = [req_item.req_id, "req_item"] |
2413 | 141 | ), | 145 | ), |
2414 | 142 | _class = "action-btn" | 146 | _class = "action-btn" |
2415 | 143 | ) | 147 | ) |
2416 | 144 | 148 | ||
2417 | @@ -301,7 +305,7 @@ | |||
2418 | 301 | if r.representation == "html": | 305 | if r.representation == "html": |
2419 | 302 | record = r.record | 306 | record = r.record |
2420 | 303 | if record and r.name == "commit": | 307 | if record and r.name == "commit": |
2422 | 304 | tabs = [(T("Edit Details"), None)] | 308 | tabs = [(T("Details"), None)] |
2423 | 305 | 309 | ||
2424 | 306 | if record.type == 1: | 310 | if record.type == 1: |
2425 | 307 | tabs.append((T("Items"), "commit_item")) | 311 | tabs.append((T("Items"), "commit_item")) |
2426 | 308 | 312 | ||
2427 | === modified file 'controllers/supply.py' | |||
2428 | --- controllers/supply.py 2011-09-09 11:19:19 +0000 | |||
2429 | +++ controllers/supply.py 2011-09-14 11:00:06 +0000 | |||
2430 | @@ -30,6 +30,7 @@ | |||
2431 | 30 | module_name = deployment_settings.modules[module].name_nice | 30 | module_name = deployment_settings.modules[module].name_nice |
2432 | 31 | response.title = module_name | 31 | response.title = module_name |
2433 | 32 | return dict(module_name=module_name) | 32 | return dict(module_name=module_name) |
2434 | 33 | |||
2435 | 33 | # ----------------------------------------------------------------------------- | 34 | # ----------------------------------------------------------------------------- |
2436 | 34 | def catalog(): | 35 | def catalog(): |
2437 | 35 | """ RESTful CRUD controller """ | 36 | """ RESTful CRUD controller """ |
2438 | 36 | 37 | ||
2439 | === modified file 'controllers/vol.py' (properties changed: +x to -x) | |||
2440 | --- controllers/vol.py 2011-08-06 18:24:53 +0000 | |||
2441 | +++ controllers/vol.py 2011-09-14 11:00:06 +0000 | |||
2442 | @@ -2,8 +2,6 @@ | |||
2443 | 2 | 2 | ||
2444 | 3 | """ | 3 | """ |
2445 | 4 | Volunteer Module | 4 | Volunteer Module |
2446 | 5 | - A 'My Sahana' view of an individual Volunteer's Data, Tasks, etc | ||
2447 | 6 | (Ability for Anonymous users to sign-up as a Volunteer?) | ||
2448 | 7 | """ | 5 | """ |
2449 | 8 | 6 | ||
2450 | 9 | module = request.controller | 7 | module = request.controller |
2451 | @@ -19,8 +17,11 @@ | |||
2452 | 19 | def index(): | 17 | def index(): |
2453 | 20 | """ Module's Home Page """ | 18 | """ Module's Home Page """ |
2454 | 21 | 19 | ||
2457 | 22 | # Default to the Personal profile | 20 | if s3_has_role(STAFF): |
2458 | 23 | return person() | 21 | response.view = "vol/index.html" |
2459 | 22 | return dict() | ||
2460 | 23 | else: | ||
2461 | 24 | redirect(URL(c="vol", f="req_skill")) | ||
2462 | 24 | 25 | ||
2463 | 25 | # ----------------------------------------------------------------------------- | 26 | # ----------------------------------------------------------------------------- |
2464 | 26 | # People | 27 | # People |
2465 | @@ -28,150 +29,41 @@ | |||
2466 | 28 | def person(): | 29 | def person(): |
2467 | 29 | """ | 30 | """ |
2468 | 30 | Person Controller | 31 | Person Controller |
2470 | 31 | - allows a person to view/update the details held about them | 32 | - List of Volunteers |
2471 | 32 | """ | 33 | """ |
2472 | 33 | 34 | ||
2473 | 35 | module = "pr" | ||
2474 | 34 | resourcename = "person" | 36 | resourcename = "person" |
2475 | 37 | tablename = "pr_person" | ||
2476 | 38 | table = db[tablename] | ||
2477 | 35 | 39 | ||
2478 | 40 | response.s3.filter = (table.volunteer == True) | ||
2479 | 41 | |||
2480 | 36 | # Load Model | 42 | # Load Model |
2481 | 37 | s3mgr.load("pr_address") | 43 | s3mgr.load("pr_address") |
2615 | 38 | s3mgr.load("hrm_skill") | 44 | s3mgr.load("vol_skill") |
2616 | 39 | 45 | ||
2617 | 40 | s3.crud.submit_button = T("Next") | 46 | s3mgr.model.add_component("vol_skill", |
2618 | 41 | 47 | pr_person="person_id") | |
2619 | 42 | s3mgr.model.add_component("hrm_certification", | 48 | |
2620 | 43 | pr_person="person_id") | 49 | s3mgr.configure("vol_skill", |
2621 | 44 | 50 | deletable = False) | |
2622 | 45 | s3mgr.model.add_component("hrm_competency", | 51 | |
2623 | 46 | pr_person="person_id") | 52 | tabs = [ (T("Basic Details"), None), |
2624 | 47 | 53 | (T("Skills"), "skill"), | |
2625 | 48 | s3mgr.model.add_component("hrm_credential", | 54 | (T("Organizational Affiliations"), "organisation"), |
2626 | 49 | pr_person="person_id") | 55 | (T("Address"), "address"), |
2627 | 50 | 56 | (T("Contact Details"), "contact"), | |
2628 | 51 | s3mgr.model.add_component("hrm_training", | 57 | ] |
2629 | 52 | pr_person="person_id") | 58 | |
2630 | 53 | 59 | rheader = lambda r: vol_pr_rheader(r, tabs=tabs) | |
2631 | 54 | s3mgr.model.add_component("hrm_experience", | 60 | |
2632 | 55 | pr_person="person_id") | 61 | output = s3_rest_controller(module, resourcename, rheader=rheader) |
2633 | 56 | 62 | ||
2501 | 57 | # Q: Are volunteers assigned to a specific organisation outside of a specific Event? | ||
2502 | 58 | # Yes, some are: CERT | ||
2503 | 59 | s3mgr.model.add_component("hrm_human_resource", | ||
2504 | 60 | pr_person="person_id") | ||
2505 | 61 | |||
2506 | 62 | # Configure human resource table | ||
2507 | 63 | # - for Positions | ||
2508 | 64 | tablename = "hrm_human_resource" | ||
2509 | 65 | table = db[tablename] | ||
2510 | 66 | table.type.readable = True | ||
2511 | 67 | table.type.writable = False | ||
2512 | 68 | table.location_id.writable = False # Populated from pr_address | ||
2513 | 69 | table.location_id.readable = False | ||
2514 | 70 | s3mgr.configure(tablename, | ||
2515 | 71 | list_fields=["id", | ||
2516 | 72 | "organisation_id", | ||
2517 | 73 | "job_title", | ||
2518 | 74 | "status"]) | ||
2519 | 75 | |||
2520 | 76 | # Configure person table | ||
2521 | 77 | # - hide fields | ||
2522 | 78 | tablename = "pr_person" | ||
2523 | 79 | table = db[tablename] | ||
2524 | 80 | table.pe_label.readable = False | ||
2525 | 81 | table.pe_label.writable = False | ||
2526 | 82 | table.missing.readable = False | ||
2527 | 83 | table.missing.writable = False | ||
2528 | 84 | table.age_group.readable = False | ||
2529 | 85 | table.age_group.writable = False | ||
2530 | 86 | s3mgr.configure(tablename, | ||
2531 | 87 | # Wizard: Move to next Tab after Save | ||
2532 | 88 | update_next = URL(args=["[id]", "address"]), | ||
2533 | 89 | deletable=False) | ||
2534 | 90 | |||
2535 | 91 | # Configure for personal mode | ||
2536 | 92 | s3.crud_strings[tablename].update( | ||
2537 | 93 | title_display = T("Personal Profile"), | ||
2538 | 94 | title_update = T("Personal Profile")) | ||
2539 | 95 | # People can view their own HR data, but not edit it | ||
2540 | 96 | db.hrm_human_resource.organisation_id.readable = True | ||
2541 | 97 | s3mgr.configure("hrm_human_resource", | ||
2542 | 98 | insertable = False, | ||
2543 | 99 | editable = False, | ||
2544 | 100 | deletable = False) | ||
2545 | 101 | s3mgr.configure("hrm_certification", | ||
2546 | 102 | insertable = True, | ||
2547 | 103 | editable = True, | ||
2548 | 104 | deletable = True) | ||
2549 | 105 | s3mgr.configure("hrm_credential", | ||
2550 | 106 | insertable = False, | ||
2551 | 107 | editable = False, | ||
2552 | 108 | deletable = False) | ||
2553 | 109 | s3mgr.configure("hrm_competency", | ||
2554 | 110 | insertable = True, # Can add unconfirmed | ||
2555 | 111 | editable = False, | ||
2556 | 112 | deletable = False) | ||
2557 | 113 | s3mgr.configure("hrm_training", # Can add but not provide grade | ||
2558 | 114 | insertable = True, | ||
2559 | 115 | editable = False, | ||
2560 | 116 | deletable = False) | ||
2561 | 117 | s3mgr.configure("hrm_experience", | ||
2562 | 118 | insertable = False, | ||
2563 | 119 | editable = False, | ||
2564 | 120 | deletable = False) | ||
2565 | 121 | s3mgr.configure("pr_group_membership", | ||
2566 | 122 | insertable = False, | ||
2567 | 123 | editable = False, | ||
2568 | 124 | deletable = False) | ||
2569 | 125 | tabs = [(T("Person Details"), None), | ||
2570 | 126 | (T("Addresses"), "address"), | ||
2571 | 127 | (T("Certificates"), "certification"), | ||
2572 | 128 | (T("Contact Information"), "contact"), | ||
2573 | 129 | #(T("Skills"), "competency"), | ||
2574 | 130 | #(T("Credentials"), "credential"), | ||
2575 | 131 | #(T("Trainings"), "training"), | ||
2576 | 132 | #(T("Mission Record"), "experience"), | ||
2577 | 133 | #(T("Positions"), "human_resource"), | ||
2578 | 134 | #(T("Teams"), "group_membership") | ||
2579 | 135 | ] | ||
2580 | 136 | |||
2581 | 137 | # Prepare CRUD | ||
2582 | 138 | def prep(r): | ||
2583 | 139 | if r.interactive: | ||
2584 | 140 | resource = r.resource | ||
2585 | 141 | r.resource.build_query(id=s3_logged_in_person()) | ||
2586 | 142 | if resource.count() == 1: | ||
2587 | 143 | resource.load() | ||
2588 | 144 | r.record = resource.records().first() | ||
2589 | 145 | if r.record: | ||
2590 | 146 | r.id = r.record.id | ||
2591 | 147 | if r.component: | ||
2592 | 148 | if r.component.name == "address": | ||
2593 | 149 | s3mgr.configure("pr_address", | ||
2594 | 150 | create_next = URL(args=[str(r.id), "certification"])) | ||
2595 | 151 | elif r.component.name == "certification": | ||
2596 | 152 | r.component.table.certificate_id.comment = None | ||
2597 | 153 | r.component.table.organisation_id.readable = False | ||
2598 | 154 | s3mgr.configure("hrm_certification", | ||
2599 | 155 | create_next = URL(args=[str(r.id), "contact"])) | ||
2600 | 156 | #elif r.component.name == "contact": | ||
2601 | 157 | # s3mgr.configure("pr_contact", | ||
2602 | 158 | # create_next = URL(# args=[str(r.id), ""])) | ||
2603 | 159 | |||
2604 | 160 | return True | ||
2605 | 161 | else: | ||
2606 | 162 | # This controller is only for interactive use | ||
2607 | 163 | redirect(URL(f='default', c="index")) | ||
2608 | 164 | response.s3.prep = prep | ||
2609 | 165 | |||
2610 | 166 | rheader = lambda r, tabs=tabs: vol_rheader(r, tabs) | ||
2611 | 167 | |||
2612 | 168 | output = s3_rest_controller("pr", resourcename, | ||
2613 | 169 | native=False, | ||
2614 | 170 | rheader=rheader) | ||
2634 | 171 | return output | 63 | return output |
2635 | 172 | 64 | ||
2636 | 173 | # ----------------------------------------------------------------------------- | 65 | # ----------------------------------------------------------------------------- |
2638 | 174 | def vol_rheader(r, tabs=[]): | 66 | def vol_pr_rheader(r, tabs=[]): |
2639 | 175 | """ Resource headers for component views """ | 67 | """ Resource headers for component views """ |
2640 | 176 | 68 | ||
2641 | 177 | rheader = None | 69 | rheader = None |
2642 | @@ -190,46 +82,2328 @@ | |||
2643 | 190 | TH(""), | 82 | TH(""), |
2644 | 191 | ""), | 83 | ""), |
2645 | 192 | 84 | ||
2646 | 193 | TR(TH("%s: " % T("Date of Birth")), | ||
2647 | 194 | "%s" % (s3_date_represent(person.date_of_birth) or T("unknown")), | ||
2648 | 195 | TH(""), | ||
2649 | 196 | ""), | ||
2650 | 197 | |||
2651 | 198 | ), rheader_tabs) | 85 | ), rheader_tabs) |
2652 | 199 | 86 | ||
2653 | 200 | return rheader | 87 | return rheader |
2654 | 201 | 88 | ||
2686 | 202 | # ----------------------------------------------------------------------------- | 89 | # ============================================================================= |
2687 | 203 | # Tasks | 90 | def organisation(): |
2688 | 204 | # ----------------------------------------------------------------------------- | 91 | """ |
2689 | 205 | def task(): | 92 | Org Controller for OrgAdmins |
2690 | 206 | 93 | """ | |
2691 | 207 | """ Allow a volunteer to View the details of their own tasks """ | 94 | |
2692 | 208 | 95 | table = db.org_organisation | |
2693 | 209 | tablename = "project_task" | 96 | |
2694 | 210 | s3mgr.load(tablename) | 97 | table.acronym.readable = False |
2695 | 211 | table = db[tablename] | 98 | table.acronym.writable = False |
2696 | 212 | 99 | org_has_vols_field = table.has_vols | |
2697 | 213 | my_person_id = s3_logged_in_person() | 100 | org_has_vols_field.default = True |
2698 | 214 | 101 | response.s3.filter = (org_has_vols_field == True) | |
2699 | 215 | if not my_person_id: | 102 | |
2700 | 216 | session.error = T("No person record found for current user.") | 103 | if "register" in request.vars: |
2701 | 217 | redirect(URL(f="index")) | 104 | response.s3.show_listadd = True |
2702 | 218 | 105 | ||
2703 | 219 | table.person_id.default = my_person_id | 106 | return organisation_controller(organisation_rheader = organisation_rheader) |
2704 | 220 | 107 | ||
2705 | 221 | response.s3.filter = (table.person_id == my_person_id) | 108 | # ----------------------------------------------------------------------------- |
2706 | 222 | 109 | def organisation_rheader(r, tabs = []): | |
2707 | 223 | s3.crud_strings[tablename].title_list = T("My Tasks") | 110 | """ Organisation rheader """ |
2708 | 224 | s3.crud_strings[tablename].subtitle_list = T("Task List") | 111 | |
2709 | 225 | s3.crud_strings[tablename].msg_list_empty = T("No tasks currently assigned") | 112 | if r.representation == "html": |
2710 | 226 | 113 | ||
2711 | 227 | s3mgr.configure(tablename, | 114 | if r.record is None: |
2712 | 228 | insertable = False, | 115 | # List or Create form: rheader makes no sense here |
2713 | 229 | editable = False, | 116 | return None |
2714 | 230 | deletable = False) | 117 | |
2715 | 231 | 118 | tabs = [(T("Basic Details"), None), | |
2716 | 232 | return s3_rest_controller("project", "task") | 119 | (T("Contacts"), "human_resource"), |
2717 | 120 | (T("Activities"), "activity") | ||
2718 | 121 | ] | ||
2719 | 122 | rheader_tabs = s3_rheader_tabs(r, tabs) | ||
2720 | 123 | |||
2721 | 124 | organisation = r.record | ||
2722 | 125 | |||
2723 | 126 | rheader = DIV(TABLE( | ||
2724 | 127 | TR( | ||
2725 | 128 | TH("%s: " % T("Organization")), | ||
2726 | 129 | organisation.name, | ||
2727 | 130 | ), | ||
2728 | 131 | ), | ||
2729 | 132 | rheader_tabs | ||
2730 | 133 | ) | ||
2731 | 134 | return rheader | ||
2732 | 135 | return None | ||
2733 | 136 | |||
2734 | 137 | # ============================================================================= | ||
2735 | 138 | def vol_sidebar(): | ||
2736 | 139 | """ Sidebar for people who aren't logged-in """ | ||
2737 | 140 | |||
2738 | 141 | request.args = ["login"] | ||
2739 | 142 | loginform = auth() | ||
2740 | 143 | loginform.attributes["_id"] = "loginform" | ||
2741 | 144 | request.args = [] | ||
2742 | 145 | |||
2743 | 146 | if not response.menu_left: | ||
2744 | 147 | response.menu_left = DIV() | ||
2745 | 148 | |||
2746 | 149 | if not auth.is_logged_in(): | ||
2747 | 150 | response.menu_left.append( | ||
2748 | 151 | DIV( | ||
2749 | 152 | P("%s:" % T("Already registered? Sign in here")), | ||
2750 | 153 | #loginform, | ||
2751 | 154 | FORM( | ||
2752 | 155 | LABEL(T("Email"), _for="email"), | ||
2753 | 156 | INPUT(_type="text", _name="email", _title=T("Email")), | ||
2754 | 157 | LABEL(T("Password"), _for="password"), | ||
2755 | 158 | INPUT(_type="password", _name="password", _title=T("Password")), | ||
2756 | 159 | INPUT(_type="submit", _value=T("Sign In"), _title=T("Sign In"), | ||
2757 | 160 | _class="sign-in-button"), | ||
2758 | 161 | loginform.custom.end, | ||
2759 | 162 | _action="", _enctype="multipart/form-data", _method="post"), | ||
2760 | 163 | _id="sign-in-menu", | ||
2761 | 164 | _class="sub-menu")) | ||
2762 | 165 | response.menu_left.append( | ||
2763 | 166 | DIV( | ||
2764 | 167 | P("%s:" % T("Other Volunteering Opportunities"), _class="osm-title"), | ||
2765 | 168 | UL( | ||
2766 | 169 | LI( | ||
2767 | 170 | A( | ||
2768 | 171 | DIV("American Red Cross", _class="link-name"), | ||
2769 | 172 | DIV( | ||
2770 | 173 | H3("redcrossla.org"), | ||
2771 | 174 | IMG(_src="/%s/static/img/la/logo_arc.png" % request.application, _width="87", _height="29", _alt="American Red Cross Logo"), | ||
2772 | 175 | P("Rooted in over a century's tradition of service to the community, the American Red Cross is one of the world's most renowned humanitarian organizations. American Red Cross volunteers assist with community emergency preparedness, services to the armed forces, emergency and disaster response, blood services, health and safety education, international services and other support volunteer services."), | ||
2773 | 176 | _class="other-popup"), | ||
2774 | 177 | _href="http://redcrossla.org", _target="_blank", | ||
2775 | 178 | _title="American Red Cross - Link will open to new Window") | ||
2776 | 179 | ), | ||
2777 | 180 | LI( | ||
2778 | 181 | A( | ||
2779 | 182 | DIV("CERT", _class="link-name"), | ||
2780 | 183 | DIV( | ||
2781 | 184 | H3("www.cert-la.com"), | ||
2782 | 185 | IMG(_src="/%s/static/img/la/certlogo.png" % request.application, _width="51", _height="30", _alt="CERT Logo"), | ||
2783 | 186 | P("The Los Angeles Fire Department Community Emergency Response Training Program (CERT), has been educating the citizens of Los Angeles in Disaster Preparedness since 1987. "), | ||
2784 | 187 | _class="other-popup"), | ||
2785 | 188 | _href="http://www.cert-la.com", _target="_blank", | ||
2786 | 189 | _title="CERT - %s" % T("Link will open to new Window")) | ||
2787 | 190 | ), | ||
2788 | 191 | LI( | ||
2789 | 192 | A( | ||
2790 | 193 | DIV("LA County Disaster Healthcare Volunteers", _class="link-name"), | ||
2791 | 194 | DIV( | ||
2792 | 195 | H3("www.lacountydhv.org"), | ||
2793 | 196 | IMG(_src="/%s/static/img/la/logo_dhv.png" % request.application, _width="88", _height="30", _alt="Disaster Healthcare Volunteers"), | ||
2794 | 197 | P("LA County Disaster Healthcare Volunteers, comprised of 4 volunteer units, is led by the County of LA Departments of Health Services, Emergency Medical Services Agency and Public Health Emergency Preparedness and Response Program. It is specifically for licensed medical, health, mental health, and other volunteers who want to volunteer their professional skills for public health emergencies or other large scale disasters. Actively licensed health professionals are encouraged to register with one of the four units (MRC LA, LA County Surge Unit, Long Beach MRC, Beach Cities Health District MRC) on the State of California Disaster Healthcare Volunteers (DHV) site in advance of the next disaster."), | ||
2795 | 198 | _class="other-popup"), | ||
2796 | 199 | _href="http://www.lacountydhv.org", _target="_blank", | ||
2797 | 200 | _title="Disaster Healthcare Volunteers - %s" % T("Link will open to new Window")) | ||
2798 | 201 | ), | ||
2799 | 202 | LI( | ||
2800 | 203 | A( | ||
2801 | 204 | DIV("LA Works", _class="link-name"), | ||
2802 | 205 | DIV( | ||
2803 | 206 | H3("www.laworks.com"), | ||
2804 | 207 | IMG(_src="/%s/static/img/la/laworks.png" % request.application, _width="47", _height="40", _alt="LA Works Logo"), | ||
2805 | 208 | P("L.A. Works is a 501(c)3 nonprofit, volunteer action center that creates and implements hands-on community service projects throughout the greater LA area."), | ||
2806 | 209 | _class="other-popup"), | ||
2807 | 210 | _href="http://www.laworks.com", _target="_blank", | ||
2808 | 211 | _title="LA Works - %s" % T("Link will open to new Window")) | ||
2809 | 212 | ), | ||
2810 | 213 | LI( | ||
2811 | 214 | A( | ||
2812 | 215 | DIV("Public Health Emergency Volunteer Network", _class="link-name"), | ||
2813 | 216 | DIV( | ||
2814 | 217 | H3("publichealth.lacounty.gov"), | ||
2815 | 218 | IMG(_src="/%s/static/img/la/logo_phev.png" % request.application, _width="121", _height="30", _alt="Public Health Emergency Volunteer (PHEV) Network"), | ||
2816 | 219 | P("The purpose of the Public Health Emergency Volunteer (PHEV) Network is to increase the coordination and collaboration with established community volunteer units that are willing to assist the Department of Public Health in responding to public health emergencies by creating a system to engage, train, and deploy these groups."), | ||
2817 | 220 | _class="other-popup"), | ||
2818 | 221 | _href="http://publichealth.lacounty.gov/eprp/volview.htm", _target="_blank", | ||
2819 | 222 | _title="Public Health Emergency Volunteer (PHEV) Network - %s" % T("Link will open to new Window")) | ||
2820 | 223 | ), | ||
2821 | 224 | LI( | ||
2822 | 225 | A( | ||
2823 | 226 | DIV("VCLA", _class="link-name"), | ||
2824 | 227 | DIV( | ||
2825 | 228 | H3("www.vcla.net"), | ||
2826 | 229 | IMG(_src="/%s/static/img/la/vcla.png" % request.application, _width="40", _height="40", _alt="VCLA Logo"), | ||
2827 | 230 | P("The Volunteer Center of Los Angeles (VCLA) is one of the largest civic action centers in the nation. We are the volunteer hub that connects people, communities, resources and businesses across Los Angeles. Our mission is to change lives and communities by connecting volunteers with community needs to make Los Angeles a safer, greener, healthier and more hopeful place to live and work."), | ||
2828 | 231 | _class="other-popup"), | ||
2829 | 232 | _href="http://www.vcla.net", _target="_blank", | ||
2830 | 233 | _title="VCLA - %s" % T("Link will open to new Window")) | ||
2831 | 234 | ) | ||
2832 | 235 | ), | ||
2833 | 236 | _class="other-sub-menu") | ||
2834 | 237 | ) | ||
2835 | 238 | if session.s3.debug: | ||
2836 | 239 | response.s3.scripts.append( "%s/jquery.hoverIntent.js" % s3_script_dir ) | ||
2837 | 240 | else: | ||
2838 | 241 | response.s3.scripts.append( "%s/jquery.hoverIntent.minified.js" % s3_script_dir ) | ||
2839 | 242 | |||
2840 | 243 | response.s3.jquery_ready.append(""" | ||
2841 | 244 | $('.other-popup').css('display', 'none'); | ||
2842 | 245 | $('.tooltip .message').css('display', 'none'); | ||
2843 | 246 | $('.other-sub-menu li a').hoverIntent(menuFadeIn, menuFadeOut); | ||
2844 | 247 | $('.tooltip a').hoverIntent(tooltipFadeIn, tooltipFadeOut);""") | ||
2845 | 248 | response.s3.js_global.append(""" | ||
2846 | 249 | // For Popup Panels for the Other Menu | ||
2847 | 250 | function menuFadeIn(){$(this).children('.other-popup').fadeIn();} | ||
2848 | 251 | function menuFadeOut(){$(this).children('.other-popup').fadeOut();} | ||
2849 | 252 | // For Tooltop Panels for the Other Menu | ||
2850 | 253 | function tooltipFadeIn(){$(this).next('.message').fadeIn();} | ||
2851 | 254 | function tooltipFadeOut(){$(this).next('.message').fadeOut();}""") | ||
2852 | 255 | |||
2853 | 256 | # ----------------------------------------------------------------------------- | ||
2854 | 257 | def register(): | ||
2855 | 258 | """ Custom Registration Form """ | ||
2856 | 259 | |||
2857 | 260 | auth.messages.submit_button = T("I accept. Create my account.") | ||
2858 | 261 | request.args = ["register"] | ||
2859 | 262 | db[auth.settings.table_user].language.default = T.accepted_language | ||
2860 | 263 | # @ToDo: Make use to the SQLFORM.createform function instead of inserting fields? | ||
2861 | 264 | form = auth() | ||
2862 | 265 | form.attributes["_id"] = "regform" | ||
2863 | 266 | # Custom class for Submit Button | ||
2864 | 267 | form[0][-1][0][0]["_class"] = "accept-button" | ||
2865 | 268 | |||
2866 | 269 | # Cancel button | ||
2867 | 270 | form[0][-1][0].append(BR()) | ||
2868 | 271 | #form[0][-1][0].append(INPUT(_type="reset", _value=T("Cancel"))) | ||
2869 | 272 | form[0][-1][0].append(INPUT(_type="button", | ||
2870 | 273 | _value=T("Cancel"), | ||
2871 | 274 | _class="wide-grey-button", | ||
2872 | 275 | _onClick="javascript: history.go(-1)")) | ||
2873 | 276 | |||
2874 | 277 | formstyle = s3.crud.formstyle | ||
2875 | 278 | |||
2876 | 279 | # Medical note | ||
2877 | 280 | row = formstyle(id = "", | ||
2878 | 281 | label = "", | ||
2879 | 282 | widget = DIV("%s:" % T("If you are a Medical or Health Professional and wish to volunteer in a professional capacity, please register at"), | ||
2880 | 283 | BR(), | ||
2881 | 284 | A("LA County Disaster Healthcare Volunteers", | ||
2882 | 285 | _href="http://www.lacountydhv.org", | ||
2883 | 286 | _target="_blank"), | ||
2884 | 287 | BR(), | ||
2885 | 288 | BR(), | ||
2886 | 289 | "%s:" % T("Individuals or Volunteer Units/Organizations interested in assisting during public health emergencies (i.e. Mass vaccine/medication dispensing sites or PODs) please register at"), | ||
2887 | 290 | BR(), | ||
2888 | 291 | A("LA County Department of Public Health Emergency Preparedness and Response Program", | ||
2889 | 292 | _href="http://publichealth.lacounty.gov/eprp/volview.htm", | ||
2890 | 293 | _target="_blank"), | ||
2891 | 294 | _style="width: 400px;", | ||
2892 | 295 | ), | ||
2893 | 296 | comment = "") | ||
2894 | 297 | form[0].insert(0, row) | ||
2895 | 298 | |||
2896 | 299 | # Middle Name | ||
2897 | 300 | row = formstyle(id = "middle_name", | ||
2898 | 301 | label = LABEL("%s:" % T("Middle Name"), | ||
2899 | 302 | _for="middle_name"), | ||
2900 | 303 | widget = INPUT(_name="middle_name", | ||
2901 | 304 | _id="middle_name", | ||
2902 | 305 | _class="string"), | ||
2903 | 306 | comment = "") | ||
2904 | 307 | form[0][2].append(row) | ||
2905 | 308 | |||
2906 | 309 | # Phone | ||
2907 | 310 | phone_opts = { | ||
2908 | 311 | "SMS": current.deployment_settings.get_ui_label_mobile_phone(), | ||
2909 | 312 | "HOME_PHONE": T("Home phone"), | ||
2910 | 313 | "WORK_PHONE": T("Work phone") | ||
2911 | 314 | } | ||
2912 | 315 | if form.errors.phone: | ||
2913 | 316 | phone_error = DIV(form.errors.phone, | ||
2914 | 317 | _id="phone__error", | ||
2915 | 318 | _class="error", | ||
2916 | 319 | _style="display: block;") | ||
2917 | 320 | else: | ||
2918 | 321 | phone_error = "" | ||
2919 | 322 | phone_widget = (INPUT(_name="phone", | ||
2920 | 323 | _id="", | ||
2921 | 324 | _class="string"), | ||
2922 | 325 | SELECT(OPTION(current.deployment_settings.get_ui_label_mobile_phone(), _value="SMS"), | ||
2923 | 326 | OPTION(T("Home phone"), _value="HOME_PHONE"), | ||
2924 | 327 | OPTION(T("Work phone"), _value="WORK_PHONE"), | ||
2925 | 328 | requires=IS_IN_SET(phone_opts), | ||
2926 | 329 | value="SMS", | ||
2927 | 330 | _name="phone_type", | ||
2928 | 331 | _id="phone_type"), | ||
2929 | 332 | phone_error | ||
2930 | 333 | ) | ||
2931 | 334 | phone_help = DIV(_class="tooltip", | ||
2932 | 335 | _title="%s|%s" % (T("Phone"), | ||
2933 | 336 | T("if you provide your Cell phone then you can choose to subscribe to SMS notifications by selecting 'My Profile' once you have completed registration."))) | ||
2934 | 337 | row = formstyle(id = "phone", | ||
2935 | 338 | label = LABEL("%s:" % T("Phone"), | ||
2936 | 339 | SPAN(" *", _class="req"), | ||
2937 | 340 | _for="phone"), | ||
2938 | 341 | widget = phone_widget, | ||
2939 | 342 | comment = phone_help) | ||
2940 | 343 | form[0][11].append(row) | ||
2941 | 344 | |||
2942 | 345 | # Address | ||
2943 | 346 | if form.errors.address1: | ||
2944 | 347 | address1_error = DIV(form.errors.address1, | ||
2945 | 348 | _id="address1__error", | ||
2946 | 349 | _class="error", | ||
2947 | 350 | _style="display: block;") | ||
2948 | 351 | else: | ||
2949 | 352 | address1_error = "" | ||
2950 | 353 | row = formstyle(id = "address1", | ||
2951 | 354 | label = LABEL("%s:" % T("Address 1"), | ||
2952 | 355 | SPAN(" *", _class="req"), | ||
2953 | 356 | _for="address1"), | ||
2954 | 357 | widget = (INPUT(_name="address1", | ||
2955 | 358 | _id="address1", | ||
2956 | 359 | _class="string"), | ||
2957 | 360 | address1_error), | ||
2958 | 361 | comment = "") | ||
2959 | 362 | form[0][11].append(row) | ||
2960 | 363 | row = formstyle(id = "address2", | ||
2961 | 364 | label = LABEL("%s:" % T("Address 2"), | ||
2962 | 365 | _for="address2"), | ||
2963 | 366 | widget = INPUT(_name="address2", | ||
2964 | 367 | _id="address2", | ||
2965 | 368 | _class="string"), | ||
2966 | 369 | comment = "") | ||
2967 | 370 | form[0][11].append(row) | ||
2968 | 371 | row = formstyle(id = "city", | ||
2969 | 372 | label = LABEL("%s:" % T("City"), | ||
2970 | 373 | SPAN(" *", _class="req"), | ||
2971 | 374 | _for="city"), | ||
2972 | 375 | widget = INPUT(_name="city", | ||
2973 | 376 | _id = "city", | ||
2974 | 377 | _class = "string"), | ||
2975 | 378 | comment = "") | ||
2976 | 379 | form[0][11].append(row) | ||
2977 | 380 | states = S3LocationDropdownWidget(level="L1", | ||
2978 | 381 | default="California", | ||
2979 | 382 | empty=False) | ||
2980 | 383 | widget = states(db.pr_address.location_id, None) | ||
2981 | 384 | row = formstyle(id = "state", | ||
2982 | 385 | label = LABEL("%s:" % T("State"), | ||
2983 | 386 | SPAN(" *", _class="req"), | ||
2984 | 387 | _for="location_id"), | ||
2985 | 388 | widget = widget, | ||
2986 | 389 | comment = "") | ||
2987 | 390 | form[0][11].append(row) | ||
2988 | 391 | if form.errors.zip: | ||
2989 | 392 | zip_error = DIV(form.errors.zip, | ||
2990 | 393 | _id="zip__error", | ||
2991 | 394 | _class="error", | ||
2992 | 395 | _style="display: block;") | ||
2993 | 396 | else: | ||
2994 | 397 | zip_error = "" | ||
2995 | 398 | row = formstyle(id = "zip", | ||
2996 | 399 | label = LABEL("%s:" % T("Zip"), | ||
2997 | 400 | SPAN(" *", _class="req"), | ||
2998 | 401 | _for="zip" | ||
2999 | 402 | ), | ||
3000 | 403 | widget = ( INPUT(_name="zip", | ||
3001 | 404 | _id="zip", | ||
3002 | 405 | _class="string"), | ||
3003 | 406 | zip_error | ||
3004 | 407 | ), | ||
3005 | 408 | comment = "") | ||
3006 | 409 | form[0][11].append(row) | ||
3007 | 410 | |||
3008 | 411 | |||
3009 | 412 | #form[0][-2].append(TR(TD(LABEL(T("Terms of Service:"), | ||
3010 | 413 | # _id="terms_of_service__label"), | ||
3011 | 414 | # _class="w2p_fl"), | ||
3012 | 415 | # TD(LABEL(TEXTAREA(deployment_settings.get_terms_of_service(), | ||
3013 | 416 | # _onfocus="this.rows=10", | ||
3014 | 417 | # _readonly="readonly", | ||
3015 | 418 | # _style="width:100%;text-align:", | ||
3016 | 419 | # _cols="80", _rows="10"), | ||
3017 | 420 | # _id="terms_of_service"), | ||
3018 | 421 | # _class="w2p_fw", | ||
3019 | 422 | # _colspan="2"), | ||
3020 | 423 | # _id="terms_of_service__row")) | ||
3021 | 424 | |||
3022 | 425 | # Eighteen | ||
3023 | 426 | if form.errors.eighteen: | ||
3024 | 427 | eighteen_error = DIV(form.errors.eighteen, | ||
3025 | 428 | _id="eighteen__error", | ||
3026 | 429 | _class="error", | ||
3027 | 430 | _style="display: block;") | ||
3028 | 431 | else: | ||
3029 | 432 | eighteen_error = "" | ||
3030 | 433 | label = LABEL(#"%s:" % T("I am 18 or over"), | ||
3031 | 434 | T("I am 18 or over"), | ||
3032 | 435 | SPAN(" *", _class="req"), | ||
3033 | 436 | _for="eighteen", | ||
3034 | 437 | _style="display: inline;", | ||
3035 | 438 | _id="eighteen__label") | ||
3036 | 439 | widget = INPUT(_type="checkbox", | ||
3037 | 440 | _value="on", | ||
3038 | 441 | _name="eighteen", | ||
3039 | 442 | _id="eighteen", | ||
3040 | 443 | _class="boolean") | ||
3041 | 444 | #row = formstyle(id = "eighteen", | ||
3042 | 445 | # label = label, | ||
3043 | 446 | # widget = (widget, | ||
3044 | 447 | # eighteen_error), | ||
3045 | 448 | # comment = "") | ||
3046 | 449 | row = TR(TD(widget, label, eighteen_error), | ||
3047 | 450 | TD(), | ||
3048 | 451 | _id="eighteen") | ||
3049 | 452 | form[0][-2].append(row) | ||
3050 | 453 | |||
3051 | 454 | # US Citizen | ||
3052 | 455 | if form.errors.citizen: | ||
3053 | 456 | citizen_error = DIV(form.errors.citizen, | ||
3054 | 457 | _id="citizen__error", | ||
3055 | 458 | _class="error", | ||
3056 | 459 | _style="display: block;") | ||
3057 | 460 | else: | ||
3058 | 461 | citizen_error = "" | ||
3059 | 462 | label = LABEL(#"%s:" % T("I am a U.S. Citizen"), | ||
3060 | 463 | T("I am a U.S. Citizen"), | ||
3061 | 464 | SPAN(" *", _class="req"), | ||
3062 | 465 | _for="citizen", | ||
3063 | 466 | _style="display: inline;", | ||
3064 | 467 | _id="citizen__label") | ||
3065 | 468 | widget = INPUT(_type="checkbox", | ||
3066 | 469 | _value="on", | ||
3067 | 470 | _name="citizen", | ||
3068 | 471 | _id="citizen", | ||
3069 | 472 | _class="boolean") | ||
3070 | 473 | #row = formstyle(id = "citizen", | ||
3071 | 474 | # label = label, | ||
3072 | 475 | # widget = (widget, | ||
3073 | 476 | # citizen_error), | ||
3074 | 477 | # comment = "") | ||
3075 | 478 | row = TR(TD(widget, label, citizen_error), | ||
3076 | 479 | TD(), | ||
3077 | 480 | _id="citizen") | ||
3078 | 481 | form[0][-2].append(row) | ||
3079 | 482 | |||
3080 | 483 | # Privacy Policy | ||
3081 | 484 | row = formstyle(id = "", | ||
3082 | 485 | label = "", | ||
3083 | 486 | widget = DIV(XML(T("By clicking on 'I accept' below you are agreeing to the %(privacy_policy)s.") % \ | ||
3084 | 487 | dict(privacy_policy = A(T("Privacy Policy"), | ||
3085 | 488 | _href = URL(c="default", | ||
3086 | 489 | f="disclaimer#privacy"), | ||
3087 | 490 | _target = "_blank" | ||
3088 | 491 | ) | ||
3089 | 492 | ) | ||
3090 | 493 | ), | ||
3091 | 494 | _style="width: 300px;", | ||
3092 | 495 | ), | ||
3093 | 496 | comment = "") | ||
3094 | 497 | form[0][-2].append(row) | ||
3095 | 498 | |||
3096 | 499 | # Add client-side validation | ||
3097 | 500 | # simplified copy of s3_register_validation() | ||
3098 | 501 | script = "".join(( """ | ||
3099 | 502 | $('#regform').validate({ | ||
3100 | 503 | errorClass: 'req', | ||
3101 | 504 | rules: { | ||
3102 | 505 | first_name: { | ||
3103 | 506 | required: true | ||
3104 | 507 | }, | ||
3105 | 508 | last_name: { | ||
3106 | 509 | required: true | ||
3107 | 510 | }, | ||
3108 | 511 | phone: { | ||
3109 | 512 | required: true | ||
3110 | 513 | }, | ||
3111 | 514 | email: { | ||
3112 | 515 | required: true, | ||
3113 | 516 | email: true | ||
3114 | 517 | }, | ||
3115 | 518 | address1: { | ||
3116 | 519 | required: true | ||
3117 | 520 | }, | ||
3118 | 521 | city: { | ||
3119 | 522 | required: true | ||
3120 | 523 | }, | ||
3121 | 524 | zip: { | ||
3122 | 525 | required: true | ||
3123 | 526 | }, | ||
3124 | 527 | password: { | ||
3125 | 528 | required: true | ||
3126 | 529 | }, | ||
3127 | 530 | password_two: { | ||
3128 | 531 | required: true, | ||
3129 | 532 | equalTo: '.password:first' | ||
3130 | 533 | }, | ||
3131 | 534 | eighteen: { | ||
3132 | 535 | required: true | ||
3133 | 536 | }, | ||
3134 | 537 | citizen: { | ||
3135 | 538 | required: true | ||
3136 | 539 | } | ||
3137 | 540 | }, | ||
3138 | 541 | messages: { | ||
3139 | 542 | firstname: '""", str(T("Enter your firstname")), """', | ||
3140 | 543 | email: { | ||
3141 | 544 | required: '""", str(T("Please enter a valid email address")), """', | ||
3142 | 545 | minlength: '""", str(T("Please enter a valid email address")), """' | ||
3143 | 546 | }, | ||
3144 | 547 | password: { | ||
3145 | 548 | required: '""", str(T("Provide a password")), """' | ||
3146 | 549 | }, | ||
3147 | 550 | password_two: { | ||
3148 | 551 | required: '""", str(T("Repeat your password")), """', | ||
3149 | 552 | equalTo: '""", str(T("Enter the same password as above")), """' | ||
3150 | 553 | }, | ||
3151 | 554 | eighteen: '""", str(T("If you are under the age 18, you may not register to apply to be a volunteer. Thank you for your interest in our volunteer opportunities.")), """', | ||
3152 | 555 | citizen: '""", str(T("If you are not a US citizen, you may not register to apply to be a volunteer. Thank you for your interest in our volunteer opportunities.")), """', | ||
3153 | 556 | }, | ||
3154 | 557 | errorPlacement: function(error, element) { | ||
3155 | 558 | error.appendTo( element.parent().next() ); | ||
3156 | 559 | }, | ||
3157 | 560 | submitHandler: function(form) { | ||
3158 | 561 | form.submit(); | ||
3159 | 562 | } | ||
3160 | 563 | });""" )) | ||
3161 | 564 | response.s3.jquery_ready.append( script ) | ||
3162 | 565 | |||
3163 | 566 | if session.s3.debug: | ||
3164 | 567 | response.s3.scripts.append( "%s/jquery.validate.js" % s3_script_dir ) | ||
3165 | 568 | response.s3.scripts.append( "%s/jquery.pstrength.1.3.js" % s3_script_dir ) | ||
3166 | 569 | else: | ||
3167 | 570 | response.s3.scripts.append( "%s/jquery.validate.min.js" % s3_script_dir ) | ||
3168 | 571 | response.s3.scripts.append( "%s/jquery.pstrength.1.3.min.js" % s3_script_dir ) | ||
3169 | 572 | |||
3170 | 573 | response.s3.jquery_ready.append("$('.password:first').pstrength();\n") | ||
3171 | 574 | |||
3172 | 575 | # Add sidebar for login box & other volunteering opportunities | ||
3173 | 576 | vol_sidebar() | ||
3174 | 577 | |||
3175 | 578 | response.s3.donate_cash_link = True | ||
3176 | 579 | |||
3177 | 580 | response.title = T("Register") | ||
3178 | 581 | response.s3.has_required = True | ||
3179 | 582 | |||
3180 | 583 | return dict(form=form) | ||
3181 | 584 | |||
3182 | 585 | # ----------------------------------------------------------------------------- | ||
3183 | 586 | def register_validation(form): | ||
3184 | 587 | """ Validate the custom fields in registration form """ | ||
3185 | 588 | # Terms of Service | ||
3186 | 589 | if "eighteen" not in request.post_vars or request.post_vars.eighteen != "on": | ||
3187 | 590 | form.errors.eighteen = T("If you are under the age 18, you may not register to apply to be a volunteer. Thank you for your interest in our volunteer opportunities.") | ||
3188 | 591 | if "citizen" not in request.post_vars or request.post_vars.citizen != "on": | ||
3189 | 592 | form.errors.citizen = T("If you are not a U.S. citizen, you may not register to apply to be a volunteer. Thank you for your interest in our volunteer opportunities.") | ||
3190 | 593 | # Phone | ||
3191 | 594 | if "phone" in request.post_vars and request.post_vars.phone: | ||
3192 | 595 | regex = re.compile(single_phone_number_pattern) | ||
3193 | 596 | if not regex.match(request.post_vars.phone): | ||
3194 | 597 | form.errors.phone = T("Invalid phone number") | ||
3195 | 598 | else: | ||
3196 | 599 | form.errors.phone = T("Phone number is required") | ||
3197 | 600 | # Address | ||
3198 | 601 | if not request.post_vars.address1: | ||
3199 | 602 | form.errors.address1 = T("Address is required") | ||
3200 | 603 | if not request.post_vars.city: | ||
3201 | 604 | form.errors.city = T("City is required") | ||
3202 | 605 | if not request.post_vars.zip: | ||
3203 | 606 | form.errors.zip = T("Zip is required") | ||
3204 | 607 | |||
3205 | 608 | return | ||
3206 | 609 | |||
3207 | 610 | # ----------------------------------------------------------------------------- | ||
3208 | 611 | def register_onaccept(form): | ||
3209 | 612 | # Usual Registration Tasks | ||
3210 | 613 | # (PR record, Authenticated Role, Contacts) | ||
3211 | 614 | person = auth.s3_register(form) | ||
3212 | 615 | |||
3213 | 616 | # LA-specific | ||
3214 | 617 | table = db.pr_person | ||
3215 | 618 | query = (table.id == person) | ||
3216 | 619 | |||
3217 | 620 | db(query).update(volunteer=True, | ||
3218 | 621 | middle_name=request.post_vars.middle_name) | ||
3219 | 622 | |||
3220 | 623 | pe = db(query).select(table.pe_id, | ||
3221 | 624 | limitby=(0, 1)).first().pe_id | ||
3222 | 625 | |||
3223 | 626 | # Phone | ||
3224 | 627 | table = db.pr_contact | ||
3225 | 628 | phone = request.post_vars.phone | ||
3226 | 629 | phone_type = request.post_vars.phone_type | ||
3227 | 630 | # Don't auto-subscribe to SMS (priority 10) | ||
3228 | 631 | table.insert(pe_id = pe, | ||
3229 | 632 | contact_method = phone_type, | ||
3230 | 633 | value = phone, | ||
3231 | 634 | priority=10) | ||
3232 | 635 | |||
3233 | 636 | # Address | ||
3234 | 637 | table = db.gis_location | ||
3235 | 638 | address1 = request.post_vars.address1 | ||
3236 | 639 | address2 = request.post_vars.address2 | ||
3237 | 640 | if address2: | ||
3238 | 641 | address = "%s\n%s" % (address1, | ||
3239 | 642 | address2) | ||
3240 | 643 | else: | ||
3241 | 644 | address = address1 | ||
3242 | 645 | city = request.post_vars.city | ||
3243 | 646 | location = request.post_vars.location_id | ||
3244 | 647 | state = db(table.id == location).select(table.id, | ||
3245 | 648 | table.name, | ||
3246 | 649 | cache=gis.cache, | ||
3247 | 650 | limitby=(0, 1)).first() | ||
3248 | 651 | if state: | ||
3249 | 652 | statename = state.name | ||
3250 | 653 | else: | ||
3251 | 654 | # Duff data - not USA | ||
3252 | 655 | statename = "unknown" | ||
3253 | 656 | zip = request.post_vars.zip | ||
3254 | 657 | county = "" | ||
3255 | 658 | if city: | ||
3256 | 659 | query = (table.name == city) & \ | ||
3257 | 660 | (table.level == "L3") & \ | ||
3258 | 661 | (table.path.like("%%/%s/%%" % state)) | ||
3259 | 662 | _city = db(query).select(table.id, | ||
3260 | 663 | table.parent, | ||
3261 | 664 | limitby=(0, 1)).first() | ||
3262 | 665 | if _city: | ||
3263 | 666 | if _city.parent != state: | ||
3264 | 667 | query = (table.id == _city.parent) | ||
3265 | 668 | county = db(query).select(table.name, | ||
3266 | 669 | limitby=(0, 1)).first().name | ||
3267 | 670 | elif state: | ||
3268 | 671 | _city = table.insert(name=city, level="L3", parent=state.id) | ||
3269 | 672 | gis.update_location_tree(_city, state.id) | ||
3270 | 673 | else: | ||
3271 | 674 | usa = db(table.code == "US").select(table.id, | ||
3272 | 675 | limitby=(0, 1)).first().id | ||
3273 | 676 | _city = table.insert(name=city, level="L3", parent=usa) | ||
3274 | 677 | gis.update_location_tree(_city, usa) | ||
3275 | 678 | else: | ||
3276 | 679 | _city = None | ||
3277 | 680 | location = table.insert(addr_street=address, addr_postcode=zip, parent=_city) | ||
3278 | 681 | gis.update_location_tree(location, _city) | ||
3279 | 682 | s3mgr.load("pr_address") | ||
3280 | 683 | table = db.pr_address | ||
3281 | 684 | table.insert(pe_id = pe, | ||
3282 | 685 | location_id = location, | ||
3283 | 686 | address=address, | ||
3284 | 687 | postcode=zip, | ||
3285 | 688 | L3=city, | ||
3286 | 689 | L2=county, | ||
3287 | 690 | L1=statename, | ||
3288 | 691 | L0="United States") | ||
3289 | 692 | |||
3290 | 693 | # ----------------------------------------------------------------------------- | ||
3291 | 694 | auth.settings.register_onvalidation = register_validation | ||
3292 | 695 | auth.settings.register_onaccept = register_onaccept | ||
3293 | 696 | auth.settings.register_next = URL(c="vol", f="skill", args=["create"]) | ||
3294 | 697 | |||
3295 | 698 | # Organisation widget for use in Registration Screen | ||
3296 | 699 | # NB User Profile is only editable by Admin - using User Management | ||
3297 | 700 | org_widget = IS_ONE_OF(db, "org_organisation.id", | ||
3298 | 701 | organisation_represent, | ||
3299 | 702 | orderby="org_organisation.name", | ||
3300 | 703 | sort=True) | ||
3301 | 704 | if deployment_settings.get_auth_registration_organisation_mandatory(): | ||
3302 | 705 | _table_user.organisation_id.requires = org_widget | ||
3303 | 706 | else: | ||
3304 | 707 | _table_user.organisation_id.requires = IS_NULL_OR(org_widget) | ||
3305 | 708 | |||
3306 | 709 | # ============================================================================= | ||
3307 | 710 | def profile(): | ||
3308 | 711 | """ Custom Profile Screen """ | ||
3309 | 712 | |||
3310 | 713 | if not auth.is_logged_in(): | ||
3311 | 714 | redirect(URL(f="user", args="login")) | ||
3312 | 715 | elif s3_has_role(ORG_VOL): | ||
3313 | 716 | #return organisation_profile() | ||
3314 | 717 | redirect(URL(f="organisation", args=[auth.user.organisation_id])) | ||
3315 | 718 | |||
3316 | 719 | # Only show admin-set fields if there is data | ||
3317 | 720 | table = db.auth_user | ||
3318 | 721 | if not auth.user.organisation_id: | ||
3319 | 722 | # Not relevant to Volunteers | ||
3320 | 723 | table.organisation_id.readable = False | ||
3321 | 724 | if not auth.user.site_id: | ||
3322 | 725 | # Only relevant to Field Staff | ||
3323 | 726 | table.site_id.readable = False | ||
3324 | 727 | |||
3325 | 728 | # Validate the custom fields | ||
3326 | 729 | auth.settings.profile_onvalidation = profile_validation | ||
3327 | 730 | |||
3328 | 731 | # Process the custom fields | ||
3329 | 732 | auth.settings.profile_onaccept = profile_onaccept | ||
3330 | 733 | |||
3331 | 734 | auth.messages.profile_save_button = "Save" | ||
3332 | 735 | |||
3333 | 736 | request.args = ["profile"] | ||
3334 | 737 | form = auth() | ||
3335 | 738 | |||
3336 | 739 | # Custom class for Submit Button | ||
3337 | 740 | form[0][-1][1][0]["_class"] = "submit-button" | ||
3338 | 741 | |||
3339 | 742 | # Lookup the Person | ||
3340 | 743 | id = auth.s3_logged_in_person() | ||
3341 | 744 | table = db.pr_person | ||
3342 | 745 | person = db(table.id == id).select(table.pe_id, | ||
3343 | 746 | table.middle_name, | ||
3344 | 747 | table.volunteer, | ||
3345 | 748 | limitby=(0, 1)).first() | ||
3346 | 749 | |||
3347 | 750 | row = TR(TD(LABEL("%s:" % table.middle_name.label, _for="middle_name")), | ||
3348 | 751 | TD(INPUT(_name="middle_name", | ||
3349 | 752 | _id="middle_name", | ||
3350 | 753 | _class="string", | ||
3351 | 754 | _value=person.middle_name))) | ||
3352 | 755 | form[0][0].append(row) | ||
3353 | 756 | |||
3354 | 757 | # Lookup the Contacts | ||
3355 | 758 | table = db.pr_contact | ||
3356 | 759 | query = (table.pe_id == person.pe_id) & \ | ||
3357 | 760 | (table.deleted == False) | ||
3358 | 761 | contacts = db(query).select(table.contact_method, | ||
3359 | 762 | table.value, | ||
3360 | 763 | table.priority) | ||
3361 | 764 | cell = "" | ||
3362 | 765 | home = "" | ||
3363 | 766 | work = "" | ||
3364 | 767 | sms_enabled = False | ||
3365 | 768 | email_enabled = True | ||
3366 | 769 | for contact in contacts: | ||
3367 | 770 | if contact.contact_method == "SMS": | ||
3368 | 771 | cell = contact.value | ||
3369 | 772 | if contact.priority == 10: | ||
3370 | 773 | sms_enabled = False | ||
3371 | 774 | else: | ||
3372 | 775 | sms_enabled = True | ||
3373 | 776 | elif contact.contact_method == "EMAIL": | ||
3374 | 777 | if contact.priority == 10: | ||
3375 | 778 | email_enabled = False | ||
3376 | 779 | else: | ||
3377 | 780 | email_enabled = True | ||
3378 | 781 | elif contact.contact_method == "HOME_PHONE": | ||
3379 | 782 | home = contact.value | ||
3380 | 783 | elif contact.contact_method == "WORK_PHONE": | ||
3381 | 784 | work = contact.value | ||
3382 | 785 | |||
3383 | 786 | # Cell phone | ||
3384 | 787 | if form.errors.mobile: | ||
3385 | 788 | cell_error = DIV(form.errors.mobile, | ||
3386 | 789 | _id="mobile__error", | ||
3387 | 790 | _class="error", | ||
3388 | 791 | _style="display: block;") | ||
3389 | 792 | else: | ||
3390 | 793 | cell_error = "" | ||
3391 | 794 | row = TR(TD(LABEL("%s:" % msg.CONTACT_OPTS["SMS"], _for="mobile")), | ||
3392 | 795 | TD(INPUT(_name="mobile", | ||
3393 | 796 | _id="mobile", | ||
3394 | 797 | _class="string", | ||
3395 | 798 | _value=cell), | ||
3396 | 799 | cell_error)) | ||
3397 | 800 | form[0][2].append(row) | ||
3398 | 801 | # @ToDo: JS validation | ||
3399 | 802 | |||
3400 | 803 | if person.volunteer: | ||
3401 | 804 | # Home phone | ||
3402 | 805 | if form.errors.home_phone: | ||
3403 | 806 | home_phone_error = DIV(form.errors.home_phone, | ||
3404 | 807 | _id="home_phone__error", | ||
3405 | 808 | _class="error", | ||
3406 | 809 | _style="display: block;") | ||
3407 | 810 | else: | ||
3408 | 811 | home_phone_error = "" | ||
3409 | 812 | row = TR(TD(LABEL("%s:" % msg.CONTACT_OPTS["HOME_PHONE"], _for="home_phone")), | ||
3410 | 813 | TD(INPUT(_name="home_phone", | ||
3411 | 814 | _id="home_phone", | ||
3412 | 815 | _class="string", | ||
3413 | 816 | _value=home), | ||
3414 | 817 | home_phone_error)) | ||
3415 | 818 | form[0][2].append(row) | ||
3416 | 819 | # @ToDo: JS validation | ||
3417 | 820 | |||
3418 | 821 | # Work phone | ||
3419 | 822 | if form.errors.work_phone: | ||
3420 | 823 | work_phone_error = DIV(form.errors.work_phone, | ||
3421 | 824 | _id="work_phone__error", | ||
3422 | 825 | _class="error", | ||
3423 | 826 | _style="display: block;") | ||
3424 | 827 | else: | ||
3425 | 828 | work_phone_error = "" | ||
3426 | 829 | row = TR(TD(LABEL("%s:" % msg.CONTACT_OPTS["WORK_PHONE"], _for="work_phone")), | ||
3427 | 830 | TD(INPUT(_name="work_phone", | ||
3428 | 831 | _id="work_phone", | ||
3429 | 832 | _class="string", | ||
3430 | 833 | _value=work), | ||
3431 | 834 | work_phone_error)) | ||
3432 | 835 | form[0][2].append(row) | ||
3433 | 836 | # @ToDo: JS validation | ||
3434 | 837 | |||
3435 | 838 | # Lookup the Address | ||
3436 | 839 | table = db.pr_address | ||
3437 | 840 | query = (table.pe_id == person.pe_id) & \ | ||
3438 | 841 | (table.deleted == False) | ||
3439 | 842 | address = db(query).select(table.location_id, | ||
3440 | 843 | limitby=(0, 1)).first() | ||
3441 | 844 | address1 = "" | ||
3442 | 845 | address2 = "" | ||
3443 | 846 | city = "" | ||
3444 | 847 | state = "" | ||
3445 | 848 | zip = "" | ||
3446 | 849 | if address: | ||
3447 | 850 | table = db.gis_location | ||
3448 | 851 | query = (table.id == address.location_id) | ||
3449 | 852 | location = db(query).select(table.id, | ||
3450 | 853 | table.path, | ||
3451 | 854 | table.parent, | ||
3452 | 855 | table.addr_street, | ||
3453 | 856 | table.addr_postcode, | ||
3454 | 857 | limitby=(0, 1)).first() | ||
3455 | 858 | if location: | ||
3456 | 859 | try: | ||
3457 | 860 | address1, address2 = location.addr_street.split("\n", 1) | ||
3458 | 861 | except ValueError: | ||
3459 | 862 | address1 = location.addr_street | ||
3460 | 863 | zip = location.addr_postcode | ||
3461 | 864 | results = gis.get_parent_per_level(None, location.id, location) | ||
3462 | 865 | try: | ||
3463 | 866 | city = results["L3"].name | ||
3464 | 867 | #except KeyError, AttributeError: | ||
3465 | 868 | except: | ||
3466 | 869 | pass | ||
3467 | 870 | try: | ||
3468 | 871 | state = results["L1"].name | ||
3469 | 872 | #except KeyError, AttributeError: | ||
3470 | 873 | except: | ||
3471 | 874 | pass | ||
3472 | 875 | |||
3473 | 876 | if form.errors.address1: | ||
3474 | 877 | address1_error = DIV(form.errors.address1, | ||
3475 | 878 | _id="address1__error", | ||
3476 | 879 | _class="error", | ||
3477 | 880 | _style="display: block;") | ||
3478 | 881 | else: | ||
3479 | 882 | address1_error = "" | ||
3480 | 883 | row = TR(TD(LABEL("%s: " % T("Address 1"), | ||
3481 | 884 | SPAN("*", _class="req"), | ||
3482 | 885 | _for="Address 1")), | ||
3483 | 886 | TD(INPUT(_name="address1", | ||
3484 | 887 | _id="address1", | ||
3485 | 888 | _class="string", | ||
3486 | 889 | _value=address1), | ||
3487 | 890 | address1_error)) | ||
3488 | 891 | form[0][2].append(row) | ||
3489 | 892 | row = TR(TD(LABEL("%s:" % T("Address 2"), _for="Address 2")), | ||
3490 | 893 | TD(INPUT(_name="address2", | ||
3491 | 894 | _id="address2", | ||
3492 | 895 | _class="string", | ||
3493 | 896 | _value=address2))) | ||
3494 | 897 | form[0][2].append(row) | ||
3495 | 898 | row = TR(TD(LABEL("%s: " % T("City"), | ||
3496 | 899 | SPAN("*", _class="req"), | ||
3497 | 900 | _for="city")), | ||
3498 | 901 | TD(INPUT(_name="city", | ||
3499 | 902 | _id="city", | ||
3500 | 903 | _class="string", | ||
3501 | 904 | _value=city))) | ||
3502 | 905 | form[0][2].append(row) | ||
3503 | 906 | states = S3LocationDropdownWidget(level="L1", | ||
3504 | 907 | default=state or "California", | ||
3505 | 908 | empty=False) | ||
3506 | 909 | widget = states(db.pr_address.location_id, None) | ||
3507 | 910 | row = TR(TD(LABEL("%s:" % T("State"), | ||
3508 | 911 | SPAN("*", _class="req"), | ||
3509 | 912 | _for="location_id")), | ||
3510 | 913 | TD(widget)) | ||
3511 | 914 | form[0][2].append(row) | ||
3512 | 915 | if form.errors.zip: | ||
3513 | 916 | zip_error = DIV(form.errors.zip, | ||
3514 | 917 | _id="zip__error", | ||
3515 | 918 | _class="error", | ||
3516 | 919 | _style="display: block;") | ||
3517 | 920 | else: | ||
3518 | 921 | zip_error = "" | ||
3519 | 922 | row = TR(TD(LABEL("%s:" % T("Zip"), | ||
3520 | 923 | SPAN("*", _class="req"), | ||
3521 | 924 | _for="zip")), | ||
3522 | 925 | TD(INPUT(_name="zip", | ||
3523 | 926 | _id="zip", | ||
3524 | 927 | _class="string", | ||
3525 | 928 | _value=zip), | ||
3526 | 929 | zip_error)) | ||
3527 | 930 | form[0][2].append(row) | ||
3528 | 931 | |||
3529 | 932 | # Notifications | ||
3530 | 933 | div = DIV(TR(TD(LABEL("%s:" % T("Notifications"))), | ||
3531 | 934 | TD() | ||
3532 | 935 | ), | ||
3533 | 936 | TR(TD(T("Receive Notifications via Email?")), | ||
3534 | 937 | TD(INPUT(_type="checkbox", | ||
3535 | 938 | _value="on", | ||
3536 | 939 | value="on" if email_enabled else "", | ||
3537 | 940 | _name="sub_email", | ||
3538 | 941 | _id="sub_email", | ||
3539 | 942 | _alt=T("Receive Notifications via Email?"), | ||
3540 | 943 | _class="boolean")) | ||
3541 | 944 | ), | ||
3542 | 945 | TR(TD(T("Receive Notifications via SMS?")), | ||
3543 | 946 | TD(INPUT(_type="checkbox", | ||
3544 | 947 | _value="on", | ||
3545 | 948 | value="on" if sms_enabled else "", | ||
3546 | 949 | _name="sub_sms", | ||
3547 | 950 | _id="sub_sms", | ||
3548 | 951 | _alt=T("Receive Notifications via SMS?"), | ||
3549 | 952 | _class="boolean")), | ||
3550 | 953 | TD(DIV(_class="tooltip", | ||
3551 | 954 | _title="%s|%s" % (T("Receive Notifications via SMS"), | ||
3552 | 955 | T("Note that this will may incur costs from your carrier.")))) | ||
3553 | 956 | ) | ||
3554 | 957 | ) | ||
3555 | 958 | form[0][-2].append(div) | ||
3556 | 959 | |||
3557 | 960 | # Affiliated Orgs | ||
3558 | 961 | s3mgr.load("vol_organisation") | ||
3559 | 962 | table = db.vol_organisation | ||
3560 | 963 | orgs = db(table.pe_id == person.pe_id).select(table.organisations_id, | ||
3561 | 964 | limitby=(0, 1)).first() | ||
3562 | 965 | if orgs: | ||
3563 | 966 | orgs = orgs.organisations_id | ||
3564 | 967 | table = db.org_organisation | ||
3565 | 968 | if orgs: | ||
3566 | 969 | _orgs = db(table.id.belongs(orgs)).select(table.name) | ||
3567 | 970 | else: | ||
3568 | 971 | _orgs = [] | ||
3569 | 972 | orgs = [] | ||
3570 | 973 | for org in _orgs: | ||
3571 | 974 | orgs.append(org.name) | ||
3572 | 975 | else: | ||
3573 | 976 | orgs = [] | ||
3574 | 977 | |||
3575 | 978 | div = DIV(TR(TD(), | ||
3576 | 979 | TD(B(T("Affiliation with other volunteer organizations")))), | ||
3577 | 980 | TR(TD(T("Are you affiliated with other volunteer organizations?"), | ||
3578 | 981 | " (", DIV(T("Check all that apply"), | ||
3579 | 982 | _style="display: inline;", | ||
3580 | 983 | _class="red"), | ||
3581 | 984 | ")", | ||
3582 | 985 | _colspan=2)), | ||
3583 | 986 | TR(TD("American Red Cross"), | ||
3584 | 987 | TD(INPUT(_type="checkbox", | ||
3585 | 988 | _value="on", | ||
3586 | 989 | value="on" if "American Red Cross of Greater Los Angeles" in orgs else "", | ||
3587 | 990 | _name="arc", | ||
3588 | 991 | _id="arc", | ||
3589 | 992 | _alt=T("American Red Cross"), | ||
3590 | 993 | _class="boolean"))), | ||
3591 | 994 | TR(TD("CERT"), | ||
3592 | 995 | TD(INPUT(_type="checkbox", | ||
3593 | 996 | _value="on", | ||
3594 | 997 | value="on" if "CERT Los Angeles" in orgs else "", | ||
3595 | 998 | _name="cert", | ||
3596 | 999 | _id="cert", | ||
3597 | 1000 | _alt=T("CERT"), | ||
3598 | 1001 | _class="boolean"))), | ||
3599 | 1002 | TR(TD("Disaster Healthcare Volunteers"), | ||
3600 | 1003 | TD(INPUT(_type="checkbox", | ||
3601 | 1004 | _value="on", | ||
3602 | 1005 | value="on" if "Disaster Healthcare Volunteers" in orgs else "", | ||
3603 | 1006 | _name="dhv", | ||
3604 | 1007 | _id="dhv", | ||
3605 | 1008 | _alt=T("Disaster Healthcare Volunteers"), | ||
3606 | 1009 | _class="boolean"))), | ||
3607 | 1010 | TR(TD("LA Works"), | ||
3608 | 1011 | TD(INPUT(_type="checkbox", | ||
3609 | 1012 | _value="on", | ||
3610 | 1013 | value="on" if "LA Works" in orgs else "", | ||
3611 | 1014 | _name="laworks", | ||
3612 | 1015 | _id="laworks", | ||
3613 | 1016 | _alt=T("LA Works"), | ||
3614 | 1017 | _class="boolean"))), | ||
3615 | 1018 | TR(TD("Volunteer Center of Los Angeles"), | ||
3616 | 1019 | TD(INPUT(_type="checkbox", | ||
3617 | 1020 | _value="on", | ||
3618 | 1021 | value="on" if "Volunteer Center of Los Angeles" in orgs else "", | ||
3619 | 1022 | _name="vcla", | ||
3620 | 1023 | _id="vcla", | ||
3621 | 1024 | _alt=T("Volunteer Center of Los Angeles"), | ||
3622 | 1025 | _class="boolean"))), | ||
3623 | 1026 | ) | ||
3624 | 1027 | form[0][-2].append(div) | ||
3625 | 1028 | |||
3626 | 1029 | # Skills | ||
3627 | 1030 | # - separate screen | ||
3628 | 1031 | |||
3629 | 1032 | response.title = T("Profile") | ||
3630 | 1033 | response.s3.has_required = True | ||
3631 | 1034 | |||
3632 | 1035 | return dict(form=form) | ||
3633 | 1036 | |||
3634 | 1037 | # ----------------------------------------------------------------------------- | ||
3635 | 1038 | def profile_validation(form): | ||
3636 | 1039 | """ Validate the custom fields in profile form """ | ||
3637 | 1040 | |||
3638 | 1041 | if s3_has_role(STAFF): | ||
3639 | 1042 | volunteer = False | ||
3640 | 1043 | else: | ||
3641 | 1044 | volunteer = True | ||
3642 | 1045 | |||
3643 | 1046 | # Mobile Phone | ||
3644 | 1047 | if "mobile" in request.post_vars and request.post_vars.mobile: | ||
3645 | 1048 | regex = re.compile(single_phone_number_pattern) | ||
3646 | 1049 | if not regex.match(request.post_vars.mobile): | ||
3647 | 1050 | form.errors.mobile = T("Invalid phone number") | ||
3648 | 1051 | elif "sub_sms" in request.post_vars and request.post_vars.sub_sms == "on": | ||
3649 | 1052 | form.errors.mobile = T("Cell phone number is required for SMS notifications") | ||
3650 | 1053 | # Home Phone | ||
3651 | 1054 | if "home_phone" in request.post_vars and request.post_vars.home_phone: | ||
3652 | 1055 | regex = re.compile(single_phone_number_pattern) | ||
3653 | 1056 | if not regex.match(request.post_vars.home_phone): | ||
3654 | 1057 | form.errors.home_phone = T("Invalid phone number") | ||
3655 | 1058 | # Work Phone | ||
3656 | 1059 | if "work_phone" in request.post_vars and request.post_vars.work_phone: | ||
3657 | 1060 | regex = re.compile(single_phone_number_pattern) | ||
3658 | 1061 | if not regex.match(request.post_vars.work_phone): | ||
3659 | 1062 | form.errors.work_phone = T("Invalid phone number") | ||
3660 | 1063 | # Address | ||
3661 | 1064 | if volunteer and not request.post_vars.address1: | ||
3662 | 1065 | form.errors.address1 = T("Address is required") | ||
3663 | 1066 | if volunteer and not request.post_vars.zip: | ||
3664 | 1067 | form.errors.zip = T("Zip is required") | ||
3665 | 1068 | |||
3666 | 1069 | return | ||
3667 | 1070 | |||
3668 | 1071 | # ----------------------------------------------------------------------------- | ||
3669 | 1072 | def profile_onaccept(form): | ||
3670 | 1073 | """ Process the custom fields """ | ||
3671 | 1074 | |||
3672 | 1075 | if s3_has_role(STAFF): | ||
3673 | 1076 | volunteer = False | ||
3674 | 1077 | else: | ||
3675 | 1078 | volunteer = True | ||
3676 | 1079 | |||
3677 | 1080 | table = db.pr_person | ||
3678 | 1081 | query = (table.id == auth.s3_logged_in_person()) | ||
3679 | 1082 | db(query).update(middle_name=request.post_vars.middle_name) | ||
3680 | 1083 | pe = db(query).select(table.pe_id, | ||
3681 | 1084 | limitby=(0, 1)).first().pe_id | ||
3682 | 1085 | |||
3683 | 1086 | if volunteer: | ||
3684 | 1087 | # Contacts / Notifications | ||
3685 | 1088 | if "sub_email" in request.post_vars and \ | ||
3686 | 1089 | request.post_vars.sub_email == "on": | ||
3687 | 1090 | email_enabled = True | ||
3688 | 1091 | else: | ||
3689 | 1092 | email_enabled = False | ||
3690 | 1093 | if "sub_sms" in request.post_vars and \ | ||
3691 | 1094 | request.post_vars.sub_sms == "on": | ||
3692 | 1095 | sms_enabled = True | ||
3693 | 1096 | else: | ||
3694 | 1097 | sms_enabled = False | ||
3695 | 1098 | home_phone = request.post_vars.home_phone | ||
3696 | 1099 | work_phone = request.post_vars.work_phone | ||
3697 | 1100 | email = request.post_vars.email | ||
3698 | 1101 | cell = request.post_vars.mobile | ||
3699 | 1102 | table = db.pr_contact | ||
3700 | 1103 | if email: | ||
3701 | 1104 | utable = db.auth_user | ||
3702 | 1105 | query = (utable.id == auth.user.id) | ||
3703 | 1106 | _email = db(query).select(utable.email, | ||
3704 | 1107 | limitby=(0, 1)).first().email | ||
3705 | 1108 | if not _email == email: | ||
3706 | 1109 | # Email has changed | ||
3707 | 1110 | # Check that the new email doesn't clash | ||
3708 | 1111 | query2 = (utable.email == email) | ||
3709 | 1112 | test = db(query2).select(utable.id, | ||
3710 | 1113 | limitby=(0, 1)).first() | ||
3711 | 1114 | if not test: | ||
3712 | 1115 | # update auth_user | ||
3713 | 1116 | db(query).update(email=email) | ||
3714 | 1117 | # update pr_contact | ||
3715 | 1118 | query = (table.value == _email) | ||
3716 | 1119 | if volunteer: | ||
3717 | 1120 | priority = 1 if email_enabled else 10 | ||
3718 | 1121 | db(query).update(value=email, priority=priority) | ||
3719 | 1122 | else: | ||
3720 | 1123 | db(query).update(value=email) | ||
3721 | 1124 | else: | ||
3722 | 1125 | # Existing .requires validation prevents the user from reusing | ||
3723 | 1126 | # an existing email | ||
3724 | 1127 | pass | ||
3725 | 1128 | elif volunteer: | ||
3726 | 1129 | # Just update the notifications | ||
3727 | 1130 | query = (table.value == email) | ||
3728 | 1131 | priority = 1 if email_enabled else 10 | ||
3729 | 1132 | db(query).update(priority=priority) | ||
3730 | 1133 | |||
3731 | 1134 | _cell = "" | ||
3732 | 1135 | _home_phone = "" | ||
3733 | 1136 | _work_phone = "" | ||
3734 | 1137 | query = (table.pe_id == pe) & \ | ||
3735 | 1138 | (table.deleted == False) | ||
3736 | 1139 | contacts = db(query).select(table.contact_method, | ||
3737 | 1140 | table.value) | ||
3738 | 1141 | for contact in contacts: | ||
3739 | 1142 | if contact.contact_method == "SMS": | ||
3740 | 1143 | _cell = contact.value | ||
3741 | 1144 | elif contact.contact_method == "HOME_PHONE": | ||
3742 | 1145 | _home_phone = contact.value | ||
3743 | 1146 | elif contact.contact_method == "WORK_PHONE": | ||
3744 | 1147 | _work_phone = contact.value | ||
3745 | 1148 | table = db.pr_contact | ||
3746 | 1149 | base_query = (table.pe_id == pe) | ||
3747 | 1150 | if volunteer: | ||
3748 | 1151 | priority = 1 if sms_enabled else 10 | ||
3749 | 1152 | if _cell: | ||
3750 | 1153 | # Update existing record | ||
3751 | 1154 | query = base_query & (table.value == _cell) | ||
3752 | 1155 | db(query).update(value=cell, priority=priority) | ||
3753 | 1156 | elif cell: | ||
3754 | 1157 | # Insert new record | ||
3755 | 1158 | table.insert(pe_id=pe, contact_method="SMS", value=cell, | ||
3756 | 1159 | priority=priority) | ||
3757 | 1160 | if _home_phone: | ||
3758 | 1161 | # Update existing record | ||
3759 | 1162 | query = base_query & (table.value == _home_phone) | ||
3760 | 1163 | db(query).update(value=home_phone) | ||
3761 | 1164 | elif home_phone: | ||
3762 | 1165 | # Insert new record | ||
3763 | 1166 | table.insert(pe_id=pe, contact_method="HOME_PHONE", | ||
3764 | 1167 | value=home_phone) | ||
3765 | 1168 | |||
3766 | 1169 | if _work_phone: | ||
3767 | 1170 | # Update existing record | ||
3768 | 1171 | query = base_query & (table.value == _work_phone) | ||
3769 | 1172 | db(query).update(value=work_phone) | ||
3770 | 1173 | elif work_phone: | ||
3771 | 1174 | # Insert new record | ||
3772 | 1175 | table.insert(pe_id=pe, contact_method="WORK_PHONE", | ||
3773 | 1176 | value=work_phone) | ||
3774 | 1177 | |||
3775 | 1178 | # Address | ||
3776 | 1179 | address1 = request.post_vars.address1 | ||
3777 | 1180 | address2 = request.post_vars.address2 | ||
3778 | 1181 | if address2: | ||
3779 | 1182 | address = "%s\n%s" % (address1, address2) | ||
3780 | 1183 | else: | ||
3781 | 1184 | address = address1 | ||
3782 | 1185 | zip = request.post_vars.zip | ||
3783 | 1186 | city = request.post_vars.city | ||
3784 | 1187 | state = request.post_vars.location_id | ||
3785 | 1188 | table = db.gis_location | ||
3786 | 1189 | statename = db(table.id == state).select(table.name, | ||
3787 | 1190 | cache=gis.cache, | ||
3788 | 1191 | limitby=(0, 1)).first().name | ||
3789 | 1192 | county = "" | ||
3790 | 1193 | if city: | ||
3791 | 1194 | query = (table.name == city) & \ | ||
3792 | 1195 | (table.level == "L3") & \ | ||
3793 | 1196 | (table.path.like("%%/%s/%%" % state)) | ||
3794 | 1197 | _city = db(query).select(table.id, | ||
3795 | 1198 | table.parent, | ||
3796 | 1199 | limitby=(0, 1)).first() | ||
3797 | 1200 | if _city: | ||
3798 | 1201 | if _city.parent != state: | ||
3799 | 1202 | query = (table.id == _city.parent) | ||
3800 | 1203 | county = db(query).select(table.name, | ||
3801 | 1204 | limitby=(0, 1)).first().name | ||
3802 | 1205 | else: | ||
3803 | 1206 | _city = table.insert(name=city, level="L3", parent=state) | ||
3804 | 1207 | gis.update_location_tree(_city, state) | ||
3805 | 1208 | else: | ||
3806 | 1209 | _city = None | ||
3807 | 1210 | table = db.pr_address | ||
3808 | 1211 | query = (table.pe_id == pe) & \ | ||
3809 | 1212 | (table.deleted == False) | ||
3810 | 1213 | test = db(query).select(table.location_id, | ||
3811 | 1214 | limitby=(0, 1)).first() | ||
3812 | 1215 | if test: | ||
3813 | 1216 | db(query).update(address=address, | ||
3814 | 1217 | postcode=zip, | ||
3815 | 1218 | L3=city, | ||
3816 | 1219 | L2=county, | ||
3817 | 1220 | L1=statename, | ||
3818 | 1221 | L0="United States") | ||
3819 | 1222 | table = db.gis_location | ||
3820 | 1223 | location = test.location_id | ||
3821 | 1224 | query = (table.id == location) | ||
3822 | 1225 | db(query).update(addr_street=address, | ||
3823 | 1226 | addr_postcode=zip, | ||
3824 | 1227 | parent=_city) | ||
3825 | 1228 | gis.update_location_tree(location, _city) | ||
3826 | 1229 | |||
3827 | 1230 | # Affiliated Organisations | ||
3828 | 1231 | # Also in models/vol.py | ||
3829 | 1232 | vol_orgs = ["American Red Cross of Greater Los Angeles", | ||
3830 | 1233 | "CERT Los Angeles", | ||
3831 | 1234 | "Disaster Healthcare Volunteers", | ||
3832 | 1235 | "LA Works", | ||
3833 | 1236 | "Volunteer Center of Los Angeles"] | ||
3834 | 1237 | table = db.org_organisation | ||
3835 | 1238 | query = (table.name.belongs(vol_orgs)) | ||
3836 | 1239 | orgs = db(query).select(table.id, | ||
3837 | 1240 | table.name, | ||
3838 | 1241 | cache=(cache.ram, 60)) | ||
3839 | 1242 | for org in orgs: | ||
3840 | 1243 | if org.name == "American Red Cross of Greater Los Angeles": | ||
3841 | 1244 | ARC = org.id | ||
3842 | 1245 | elif org.name == "CERT Los Angeles": | ||
3843 | 1246 | CERT = org.id | ||
3844 | 1247 | elif org.name == "Disaster Healthcare Volunteers": | ||
3845 | 1248 | DHV = org.id | ||
3846 | 1249 | elif org.name == "LA Works": | ||
3847 | 1250 | LAW = org.id | ||
3848 | 1251 | elif org.name == "Volunteer Center of Los Angeles": | ||
3849 | 1252 | VCLA = org.id | ||
3850 | 1253 | orgs = [] | ||
3851 | 1254 | if "arc" in request.post_vars and request.post_vars.arc == "on": | ||
3852 | 1255 | orgs.append(ARC) | ||
3853 | 1256 | if "cert" in request.post_vars and request.post_vars.cert == "on": | ||
3854 | 1257 | orgs.append(CERT) | ||
3855 | 1258 | if "dhv" in request.post_vars and request.post_vars.dhv == "on": | ||
3856 | 1259 | orgs.append(DHV) | ||
3857 | 1260 | if "laworks" in request.post_vars and \ | ||
3858 | 1261 | request.post_vars.laworks == "on": | ||
3859 | 1262 | orgs.append(LAW) | ||
3860 | 1263 | if "vcla" in request.post_vars and request.post_vars.vcla == "on": | ||
3861 | 1264 | orgs.append(VCLA) | ||
3862 | 1265 | s3mgr.load("vol_organisation") | ||
3863 | 1266 | table = db.vol_organisation | ||
3864 | 1267 | query = (table.pe_id == pe) | ||
3865 | 1268 | test = db(query).select(table.id, | ||
3866 | 1269 | limitby=(0, 1)).first() | ||
3867 | 1270 | if test: | ||
3868 | 1271 | db(query).update(organisations_id = orgs) | ||
3869 | 1272 | else: | ||
3870 | 1273 | table.insert(pe_id = pe, | ||
3871 | 1274 | organisations_id = orgs, | ||
3872 | 1275 | owned_by_user = auth.user.id) | ||
3873 | 1276 | |||
3874 | 1277 | else: | ||
3875 | 1278 | # Not a volunteer: EOC staff | ||
3876 | 1279 | if _cell: | ||
3877 | 1280 | # Update existing record | ||
3878 | 1281 | query = base_query & (table.value == _cell) | ||
3879 | 1282 | db(query).update(value=cell) | ||
3880 | 1283 | elif cell: | ||
3881 | 1284 | # Insert new record | ||
3882 | 1285 | table.insert(pe_id=pe, contact_method="SMS", value=cell) | ||
3883 | 1286 | |||
3884 | 1287 | # ----------------------------------------------------------------------------- | ||
3885 | 1288 | # Skills | ||
3886 | 1289 | # ----------------------------------------------------------------------------- | ||
3887 | 1290 | def skill(): | ||
3888 | 1291 | """ | ||
3889 | 1292 | Collect a Volunteer's Skills | ||
3890 | 1293 | """ | ||
3891 | 1294 | |||
3892 | 1295 | tablename = "vol_skill" | ||
3893 | 1296 | s3mgr.load(tablename) | ||
3894 | 1297 | table = db[tablename] | ||
3895 | 1298 | |||
3896 | 1299 | person = auth.s3_logged_in_person() | ||
3897 | 1300 | table.person_id.default = person | ||
3898 | 1301 | table.person_id.writable = table.person_id.readable = False | ||
3899 | 1302 | |||
3900 | 1303 | s3mgr.configure(tablename, | ||
3901 | 1304 | # Workflow: Prompt for creating Emergency Contacts after adding Skills | ||
3902 | 1305 | create_next = URL(f="contact", args=["my"]), | ||
3903 | 1306 | update_next = URL(f="skill", args=["my"]), | ||
3904 | 1307 | deletable = False, | ||
3905 | 1308 | listadd = False) | ||
3906 | 1309 | |||
3907 | 1310 | # Parse the request | ||
3908 | 1311 | if "my" in request.args: | ||
3909 | 1312 | query = (table.person_id == person) | ||
3910 | 1313 | record = db(query).select(table.id, | ||
3911 | 1314 | limitby=(0, 1), | ||
3912 | 1315 | cache = gis.cache).first() | ||
3913 | 1316 | if record: | ||
3914 | 1317 | r = s3mgr.parse_request(args=[str(record.id)]) | ||
3915 | 1318 | else: | ||
3916 | 1319 | r = s3mgr.parse_request(args=["create"]) | ||
3917 | 1320 | else: | ||
3918 | 1321 | r = s3mgr.parse_request() | ||
3919 | 1322 | |||
3920 | 1323 | # Execute the request | ||
3921 | 1324 | output = r() | ||
3922 | 1325 | |||
3923 | 1326 | response.title = T("My Skills") | ||
3924 | 1327 | return output | ||
3925 | 1328 | |||
3926 | 1329 | # ----------------------------------------------------------------------------- | ||
3927 | 1330 | # Contacts | ||
3928 | 1331 | # ----------------------------------------------------------------------------- | ||
3929 | 1332 | def contact(): | ||
3930 | 1333 | """ | ||
3931 | 1334 | Emergency Contacts for the volunteer | ||
3932 | 1335 | """ | ||
3933 | 1336 | |||
3934 | 1337 | tablename = "vol_contact" | ||
3935 | 1338 | s3mgr.load(tablename) | ||
3936 | 1339 | table = db[tablename] | ||
3937 | 1340 | |||
3938 | 1341 | person = auth.s3_logged_in_person() | ||
3939 | 1342 | table.person_id.default = person | ||
3940 | 1343 | table.person_id.writable = table.person_id.readable = False | ||
3941 | 1344 | |||
3942 | 1345 | s3mgr.configure(tablename, | ||
3943 | 1346 | create_next = URL(f="req_skill"), | ||
3944 | 1347 | update_next = URL(f="contact", args=["my"]), | ||
3945 | 1348 | deletable = False, | ||
3946 | 1349 | listadd = False) | ||
3947 | 1350 | |||
3948 | 1351 | # Parse the request | ||
3949 | 1352 | if "my" in request.args: | ||
3950 | 1353 | query = (table.person_id == person) | ||
3951 | 1354 | record = db(query).select(table.id, | ||
3952 | 1355 | limitby=(0, 1), | ||
3953 | 1356 | cache = gis.cache).first() | ||
3954 | 1357 | if record: | ||
3955 | 1358 | r = s3mgr.parse_request(args=[str(record.id)]) | ||
3956 | 1359 | else: | ||
3957 | 1360 | r = s3mgr.parse_request(args=["create"]) | ||
3958 | 1361 | else: | ||
3959 | 1362 | r = s3mgr.parse_request() | ||
3960 | 1363 | |||
3961 | 1364 | # Execute the request | ||
3962 | 1365 | output = r() | ||
3963 | 1366 | |||
3964 | 1367 | response.title = T("Emergency Contact") | ||
3965 | 1368 | return output | ||
3966 | 1369 | |||
3967 | 1370 | # ----------------------------------------------------------------------------- | ||
3968 | 1371 | # Assignments | ||
3969 | 1372 | # - My Assignments menu | ||
3970 | 1373 | # ----------------------------------------------------------------------------- | ||
3971 | 1374 | def assignment(): | ||
3972 | 1375 | |||
3973 | 1376 | """ Allow a Volunteer/Org to View the details of their own assignments """ | ||
3974 | 1377 | |||
3975 | 1378 | tablename = "vol_assignment" | ||
3976 | 1379 | s3mgr.load(tablename) | ||
3977 | 1380 | table = db[tablename] | ||
3978 | 1381 | |||
3979 | 1382 | if auth.user.organisation_id: | ||
3980 | 1383 | response.s3.filter = (table.organisation_id == auth.user.organisation_id) | ||
3981 | 1384 | # Control List View | ||
3982 | 1385 | table.person_id.readable = False | ||
3983 | 1386 | table.number.readable = True | ||
3984 | 1387 | table.number.label = T("Number of Volunteers Committed") | ||
3985 | 1388 | else: | ||
3986 | 1389 | my_person_id = s3_logged_in_person() | ||
3987 | 1390 | # Control List View | ||
3988 | 1391 | table.person_id.readable = False | ||
3989 | 1392 | |||
3990 | 1393 | if not my_person_id: | ||
3991 | 1394 | session.error = T("No person record found for current user.") | ||
3992 | 1395 | redirect(URL(f="index")) | ||
3993 | 1396 | |||
3994 | 1397 | response.s3.filter = (table.person_id == my_person_id) | ||
3995 | 1398 | |||
3996 | 1399 | # Filter for current/past assignments | ||
3997 | 1400 | sel = ((table.checkout == None) | | ||
3998 | 1401 | (table.checkout >= request.utcnow) | | ||
3999 | 1402 | (table.task_evaluation == None)) | ||
4000 | 1403 | s3.crud_strings[tablename].update( | ||
4001 | 1404 | subtitle_list = T("Current Assignments")) | ||
4002 | 1405 | if "show" in request.get_vars: | ||
4003 | 1406 | show = request.get_vars["show"] | ||
4004 | 1407 | if show == "past": | ||
4005 | 1408 | sel = ((table.checkout < request.utcnow) & | ||
4006 | 1409 | (table.task_evaluation != None)) | ||
4007 | 1410 | s3.crud_strings[tablename].update( | ||
4008 | 1411 | subtitle_list = T("Past Assignments"), | ||
4009 | 1412 | msg_no_match = T("No past assigments")) | ||
4010 | 1413 | response.s3.filter &= sel | ||
4011 | 1414 | |||
4012 | 1415 | # Post-process | ||
4013 | 1416 | def postp(r, output): | ||
4014 | 1417 | if r.interactive: | ||
4015 | 1418 | response.s3.actions = [dict( | ||
4016 | 1419 | url = URL(c = "vol", | ||
4017 | 1420 | f = "req", | ||
4018 | 1421 | args = ["assignment", "[id]"]), | ||
4019 | 1422 | _class = "action-btn", | ||
4020 | 1423 | label = str(T("Details")) | ||
4021 | 1424 | )] | ||
4022 | 1425 | if "show" in request.get_vars and request.get_vars["show"] == "past": | ||
4023 | 1426 | response.s3.actions += [dict( | ||
4024 | 1427 | url = URL(c=request.controller, | ||
4025 | 1428 | f="req", | ||
4026 | 1429 | args=["assignment", | ||
4027 | 1430 | "[id]", | ||
4028 | 1431 | "print"]), | ||
4029 | 1432 | _class = "action-btn", | ||
4030 | 1433 | label = str(T("Certificate")) | ||
4031 | 1434 | )] | ||
4032 | 1435 | |||
4033 | 1436 | return output | ||
4034 | 1437 | response.s3.postp = postp | ||
4035 | 1438 | |||
4036 | 1439 | output = s3_rest_controller("vol", "assignment") | ||
4037 | 1440 | return output | ||
4038 | 1441 | |||
4039 | 1442 | # ----------------------------------------------------------------------------- | ||
4040 | 1443 | # Requests | ||
4041 | 1444 | # ----------------------------------------------------------------------------- | ||
4042 | 1445 | def vol_req_rheader(r): | ||
4043 | 1446 | """ | ||
4044 | 1447 | Resource Header for Requests | ||
4045 | 1448 | - Volunteer view | ||
4046 | 1449 | - inc Volunteer Roster | ||
4047 | 1450 | """ | ||
4048 | 1451 | |||
4049 | 1452 | if r.representation == "html": | ||
4050 | 1453 | if r.name == "req": | ||
4051 | 1454 | record = r.record | ||
4052 | 1455 | if record: | ||
4053 | 1456 | if s3_has_role(STAFF): | ||
4054 | 1457 | # Show Tabs on Roster | ||
4055 | 1458 | tabs = [(T("Details"), None)] | ||
4056 | 1459 | if record.type == 3 and deployment_settings.has_module("hrm"): | ||
4057 | 1460 | tabs.append((T("Requested Volunteers"), "req_skill")) | ||
4058 | 1461 | if deployment_settings.has_module("doc"): | ||
4059 | 1462 | tabs.append((T("Documents"), "document")) | ||
4060 | 1463 | #if deployment_settings.get_req_use_commit(): | ||
4061 | 1464 | # tabs.append((T("Commitments"), "commit")) | ||
4062 | 1465 | tabs.append((T("Roster"), "assignment")) | ||
4063 | 1466 | try: | ||
4064 | 1467 | # Remove the default_type from URLs as set within respective controller | ||
4065 | 1468 | r.vars.pop("default_type") | ||
4066 | 1469 | except KeyError: | ||
4067 | 1470 | pass | ||
4068 | 1471 | rheader_tabs = s3_rheader_tabs(r, tabs) | ||
4069 | 1472 | elif not r.component: | ||
4070 | 1473 | # Volunteers should only ever access Requests via the Components | ||
4071 | 1474 | return | ||
4072 | 1475 | |||
4073 | 1476 | table = db.req_req_skill | ||
4074 | 1477 | query = (table.req_id == record.id) | ||
4075 | 1478 | srecord = db(query).select(table.skill_id, | ||
4076 | 1479 | table.quantity, | ||
4077 | 1480 | table.quantity_commit, | ||
4078 | 1481 | limitby=(0, 1)).first() | ||
4079 | 1482 | if srecord: | ||
4080 | 1483 | skills = response.s3.hrm_multi_skill_represent(srecord.skill_id) | ||
4081 | 1484 | requested = srecord.quantity | ||
4082 | 1485 | required = srecord.quantity - srecord.quantity_commit | ||
4083 | 1486 | else: | ||
4084 | 1487 | skills = requested = required = "" | ||
4085 | 1488 | |||
4086 | 1489 | address = shn_site_represent(record.site_id, address=True) | ||
4087 | 1490 | #table = db.org_office | ||
4088 | 1491 | #query = (table.id == record.site_id) | ||
4089 | 1492 | #srecord = db(query).select(table.name, | ||
4090 | 1493 | # table.address, | ||
4091 | 1494 | # table.postcode, | ||
4092 | 1495 | # table.L3, | ||
4093 | 1496 | # table.L1, | ||
4094 | 1497 | # limitby=(0, 1)).first() | ||
4095 | 1498 | #if srecord: | ||
4096 | 1499 | # location = T("%(site)s in %(location)s") % dict(site = srecord.name, | ||
4097 | 1500 | # location = record.location) | ||
4098 | 1501 | # ltable = db.gis_location | ||
4099 | 1502 | # query = (ltable.name == srecord.L1) | ||
4100 | 1503 | # state = db(query).select(ltable.code, | ||
4101 | 1504 | # limitby=(0, 1), | ||
4102 | 1505 | # cache=gis.cache).first() | ||
4103 | 1506 | # if state: | ||
4104 | 1507 | # statecode = state.code | ||
4105 | 1508 | # else: | ||
4106 | 1509 | # # Not valid US data (e.g. prepopulate) | ||
4107 | 1510 | # statecode = None | ||
4108 | 1511 | # address = "%s, %s %s %s" % (srecord.address, | ||
4109 | 1512 | # srecord.L3, | ||
4110 | 1513 | # statecode, | ||
4111 | 1514 | # srecord.postcode) | ||
4112 | 1515 | #else: | ||
4113 | 1516 | # location = address = "" | ||
4114 | 1517 | |||
4115 | 1518 | table = db.hrm_human_resource | ||
4116 | 1519 | query = (table.id == record.request_for_id) | ||
4117 | 1520 | person = db(query).select(table.person_id, | ||
4118 | 1521 | limitby=(0, 1)).first() | ||
4119 | 1522 | phone = email = report_to = "" | ||
4120 | 1523 | if person: | ||
4121 | 1524 | report_to = person_represent(person.person_id) | ||
4122 | 1525 | |||
4123 | 1526 | # @ToDo: Investigate if these db calls can be done together with a join? | ||
4124 | 1527 | table = db.pr_person | ||
4125 | 1528 | query = (table.id == person.person_id) | ||
4126 | 1529 | pe = db(query).select(table.pe_id, | ||
4127 | 1530 | limitby=(0, 1)).first() | ||
4128 | 1531 | if pe: | ||
4129 | 1532 | table = db.pr_contact | ||
4130 | 1533 | query = (table.pe_id == pe.pe_id) & \ | ||
4131 | 1534 | (table.contact_method.belongs(("SMS", "EMAIL"))) | ||
4132 | 1535 | contacts = db(query).select(table.contact_method, | ||
4133 | 1536 | table.value) | ||
4134 | 1537 | for contact in contacts: | ||
4135 | 1538 | if contact.contact_method == "SMS": | ||
4136 | 1539 | phone = contact.value | ||
4137 | 1540 | elif contact.contact_method == "EMAIL": | ||
4138 | 1541 | email = contact.value | ||
4139 | 1542 | |||
4140 | 1543 | if s3_has_role(STAFF): | ||
4141 | 1544 | subtitle = T("Request Details") | ||
4142 | 1545 | buttons = DIV( | ||
4143 | 1546 | BUTTON(T("PRINT ROSTER"), | ||
4144 | 1547 | _class="wide-grey-button", | ||
4145 | 1548 | _onClick="javascript: window.location='%s'" % \ | ||
4146 | 1549 | URL(c=request.controller, | ||
4147 | 1550 | f="req", | ||
4148 | 1551 | args=[record.id, | ||
4149 | 1552 | "assignment", | ||
4150 | 1553 | "print"])), | ||
4151 | 1554 | BUTTON(T("CANCEL REQUEST"), | ||
4152 | 1555 | _class="wide-grey-button", | ||
4153 | 1556 | _onClick="javascript: window.location='%s'" % \ | ||
4154 | 1557 | URL(c=request.controller, | ||
4155 | 1558 | f="req", | ||
4156 | 1559 | args=[record.id, | ||
4157 | 1560 | "cancel"])) | ||
4158 | 1561 | ) | ||
4159 | 1562 | textbox = "" | ||
4160 | 1563 | else: | ||
4161 | 1564 | subtitle = T("Volunteer Assignment Details") | ||
4162 | 1565 | buttons = "" | ||
4163 | 1566 | if r.component.name == "application": | ||
4164 | 1567 | textbox = P(T("When you volunteer with Give2LA, you are an extension of the good will of the City of Los Angeles. For many survivors, volunteers are their first point of contact. Your respect, courtesy and sensitivity during these difficult times are vital. In addition, following directions, procedures, and processes given to you by your supervisor are essential; failure to do so may exclude you from future volunteer assignments.")) | ||
4165 | 1568 | else: | ||
4166 | 1569 | give2la_forms = A( T("Give2LA Registration Forms"), | ||
4167 | 1570 | _href = URL(c="static", | ||
4168 | 1571 | f="Volunteer_Ethics_and_Conduct.pdf") | ||
4169 | 1572 | ) | ||
4170 | 1573 | textbox = DIV(P(T("Thank you for Volunteering. Please print out your Volunteer Assignment Form as it contains important information about who, when, and where to report to for your Volunteer Assignment.")), | ||
4171 | 1574 | P(XML(T("As a volunteer working to assist disaster survivors and in disaster recovery efforts, you will be required to fill out and sign the %(give2la_forms)s") % | ||
4172 | 1575 | dict(give2la_forms = give2la_forms) ), | ||
4173 | 1576 | "."), | ||
4174 | 1577 | P(T("Please let us know in advance if you cannot report for your Volunteer Assignment by calling the Point of Contact listed above.")), | ||
4175 | 1578 | ) | ||
4176 | 1579 | |||
4177 | 1580 | if record.date_required: | ||
4178 | 1581 | time_req = s3_time_represent(record.date_required, utc=True) | ||
4179 | 1582 | else: | ||
4180 | 1583 | time_req = "" | ||
4181 | 1584 | if record.date_required_until: | ||
4182 | 1585 | time_until = s3_time_represent(record.date_required_until, utc=True) | ||
4183 | 1586 | else: | ||
4184 | 1587 | time_until = "" | ||
4185 | 1588 | |||
4186 | 1589 | class DL(DIV): | ||
4187 | 1590 | tag = 'dl' | ||
4188 | 1591 | |||
4189 | 1592 | class DT(DIV): | ||
4190 | 1593 | tag = 'dt' | ||
4191 | 1594 | |||
4192 | 1595 | class DD(DIV): | ||
4193 | 1596 | tag = 'dd' | ||
4194 | 1597 | |||
4195 | 1598 | rheader = DIV( | ||
4196 | 1599 | textbox, | ||
4197 | 1600 | H2(subtitle, _class="paper-strip"), | ||
4198 | 1601 | buttons, | ||
4199 | 1602 | DIV( | ||
4200 | 1603 | TABLE( | ||
4201 | 1604 | TR( | ||
4202 | 1605 | TH(T("Request Number")), | ||
4203 | 1606 | TH(T("Task")), | ||
4204 | 1607 | TH(T("Date+Time")), | ||
4205 | 1608 | TH(T("Required Skills")), | ||
4206 | 1609 | TH(T("Request Priority")), | ||
4207 | 1610 | TH(T("Location")), | ||
4208 | 1611 | TH(T("Number of Volunteers"),BR(),DIV("(", T("Still Required"), "/", T("Total Requested"), ")")), # (assigned/required) | ||
4209 | 1612 | _class="odd" | ||
4210 | 1613 | ), | ||
4211 | 1614 | TR( | ||
4212 | 1615 | TD(record.request_number), | ||
4213 | 1616 | TD(record.purpose), | ||
4214 | 1617 | TD(B(s3_date_represent_utc(record.date_required)), | ||
4215 | 1618 | BR(), | ||
4216 | 1619 | "%s - %s" % (time_req, | ||
4217 | 1620 | time_until), | ||
4218 | 1621 | ), | ||
4219 | 1622 | TD(skills), | ||
4220 | 1623 | TD(response.s3.req_priority_represent(record.priority) ), | ||
4221 | 1624 | TD(record.location or ""), | ||
4222 | 1625 | TD(B(required), | ||
4223 | 1626 | " / %s" % requested, | ||
4224 | 1627 | _class="red"), | ||
4225 | 1628 | _class="even" | ||
4226 | 1629 | ), | ||
4227 | 1630 | _class="datatable display" | ||
4228 | 1631 | ), | ||
4229 | 1632 | _id="table-container" | ||
4230 | 1633 | ), | ||
4231 | 1634 | DL( | ||
4232 | 1635 | DT(T("Point of Contact")), | ||
4233 | 1636 | DD(report_to, | ||
4234 | 1637 | BR(), | ||
4235 | 1638 | "%s: %s" % (T("Phone"), | ||
4236 | 1639 | phone), | ||
4237 | 1640 | BR(), | ||
4238 | 1641 | "%s: %s" % (T("Email"), | ||
4239 | 1642 | email), | ||
4240 | 1643 | ), | ||
4241 | 1644 | DT(T("Volunteering Location")), | ||
4242 | 1645 | DD(#location, | ||
4243 | 1646 | #BR(), | ||
4244 | 1647 | address), | ||
4245 | 1648 | DT(T("Comments")), | ||
4246 | 1649 | DD(record.comments), | ||
4247 | 1650 | _class="assignment-details" | ||
4248 | 1651 | ), | ||
4249 | 1652 | ) | ||
4250 | 1653 | if r.component and r.component.name == "assignment": | ||
4251 | 1654 | if s3_has_role(STAFF): | ||
4252 | 1655 | # Volunteer Roster | ||
4253 | 1656 | response.s3.rfooter = DIV( | ||
4254 | 1657 | BUTTON(T("CHECK-IN ALL"), | ||
4255 | 1658 | _class="wide-grey-button", | ||
4256 | 1659 | _onClick="javascript: window.location='%s'" % \ | ||
4257 | 1660 | URL(c=request.controller, | ||
4258 | 1661 | f="req", | ||
4259 | 1662 | args=[record.id, | ||
4260 | 1663 | "assignment", | ||
4261 | 1664 | "checkin"])), | ||
4262 | 1665 | BUTTON(T("CHECK-OUT ALL"), | ||
4263 | 1666 | _class="wide-grey-button", | ||
4264 | 1667 | _onClick="javascript: window.location='%s'" % \ | ||
4265 | 1668 | URL(c=request.controller, | ||
4266 | 1669 | f="req", | ||
4267 | 1670 | args=[record.id, | ||
4268 | 1671 | "assignment", | ||
4269 | 1672 | "checkout"])) | ||
4270 | 1673 | ) | ||
4271 | 1674 | else: | ||
4272 | 1675 | # Volunteer Assignment | ||
4273 | 1676 | assignment = r.component_id | ||
4274 | 1677 | table = db.vol_assignment | ||
4275 | 1678 | query = table.id == r.component_id | ||
4276 | 1679 | record = db(query).select(limitby=(0, 1)).first() | ||
4277 | 1680 | if not record: | ||
4278 | 1681 | # Probably a Volunteer trying to use a URL for STAFF | ||
4279 | 1682 | session.error = auth.permission.INSUFFICIENT_PRIVILEGES | ||
4280 | 1683 | redirect(URL(c="vol", f="req_skill")) | ||
4281 | 1684 | req_id = record.req_id | ||
4282 | 1685 | if record.checkout != None and record.task_evaluation != None: | ||
4283 | 1686 | printBtn = T("PRINT CERTIFICATE") | ||
4284 | 1687 | else: | ||
4285 | 1688 | printBtn = T("PRINT VOLUNTEER ASSIGNMENT FORM") | ||
4286 | 1689 | rheader.append( | ||
4287 | 1690 | DIV( | ||
4288 | 1691 | BUTTON(printBtn, | ||
4289 | 1692 | _class="big-red-arrow", | ||
4290 | 1693 | _onClick="javascript: window.location='%s'" % \ | ||
4291 | 1694 | URL(c=request.controller, | ||
4292 | 1695 | f="req", | ||
4293 | 1696 | args=["assignment", | ||
4294 | 1697 | assignment, | ||
4295 | 1698 | "print"])), | ||
4296 | 1699 | # Also in controllers/don.py - DRY | ||
4297 | 1700 | A(IMG(_src="/%s/static/img/get_adobe_reader.png" % request.application, | ||
4298 | 1701 | _title="%s - %s" % (T("Get Adobe Reader"), | ||
4299 | 1702 | T("This link will open a new browser window.")), | ||
4300 | 1703 | _alt=T("Get Adobe Reader"), | ||
4301 | 1704 | _width=158, | ||
4302 | 1705 | _height=39, | ||
4303 | 1706 | _style="float:right;"), | ||
4304 | 1707 | _href="http://www.adobe.com/products/acrobat/readstep2.html", | ||
4305 | 1708 | _target="_blank"), | ||
4306 | 1709 | BR(), | ||
4307 | 1710 | BUTTON(T("CANCEL ASSIGNMENT"), | ||
4308 | 1711 | _class="wide-grey-button", | ||
4309 | 1712 | _onClick="javascript: window.location='%s'" % \ | ||
4310 | 1713 | URL(c=request.controller, | ||
4311 | 1714 | f="req", | ||
4312 | 1715 | args=[record.id, | ||
4313 | 1716 | "assignment", | ||
4314 | 1717 | assignment, | ||
4315 | 1718 | "delete"])) | ||
4316 | 1719 | ) | ||
4317 | 1720 | ) | ||
4318 | 1721 | if s3_has_role(STAFF): | ||
4319 | 1722 | rheader.append(rheader_tabs) | ||
4320 | 1723 | |||
4321 | 1724 | return rheader | ||
4322 | 1725 | return None | ||
4323 | 1726 | |||
4324 | 1727 | # ----------------------------------------------------------------------------- | ||
4325 | 1728 | def req(): | ||
4326 | 1729 | """ REST Controller """ | ||
4327 | 1730 | |||
4328 | 1731 | s3mgr.load("req_req") | ||
4329 | 1732 | default_type = 3 | ||
4330 | 1733 | request.vars["default_type"] = 3 | ||
4331 | 1734 | |||
4332 | 1735 | if "skill_id" in request.get_vars: | ||
4333 | 1736 | # Look up the Request from the Skill component | ||
4334 | 1737 | # (since that is what is available to us within the dataTables row) | ||
4335 | 1738 | table = db.req_req_skill | ||
4336 | 1739 | query = (table.id == request.vars.skill_id) | ||
4337 | 1740 | req = db(query).select(table.req_id, | ||
4338 | 1741 | limitby=(0, 1)).first() | ||
4339 | 1742 | if not req: | ||
4340 | 1743 | session.error = T("Invalid Request!") | ||
4341 | 1744 | redirect(URL(f="req_skill", args=[], vars={})) | ||
4342 | 1745 | # @ToDo: A nicer way to do this (without a 2nd request) | ||
4343 | 1746 | # simply amending request.args doesn't work | ||
4344 | 1747 | # Need to rewrite to not use prep/postp but rather process r() directly | ||
4345 | 1748 | redirect(URL(args = [req.req_id, "application", "create"], | ||
4346 | 1749 | vars={})) | ||
4347 | 1750 | |||
4348 | 1751 | if "document" in request.args: | ||
4349 | 1752 | s3mgr.load("doc_document") | ||
4350 | 1753 | |||
4351 | 1754 | req_table = db.req_req | ||
4352 | 1755 | s3mgr.configure(req_table, | ||
4353 | 1756 | deletable=False) | ||
4354 | 1757 | |||
4355 | 1758 | type_field = req_table.type | ||
4356 | 1759 | type_field.default = int(default_type) | ||
4357 | 1760 | type_field.writable = False | ||
4358 | 1761 | |||
4359 | 1762 | if s3_has_role(STAFF): | ||
4360 | 1763 | if "assignment" in request.args or \ | ||
4361 | 1764 | "checkin" in request.args or \ | ||
4362 | 1765 | "checkout" in request.args: | ||
4363 | 1766 | s3mgr.load("vol_assignment") | ||
4364 | 1767 | |||
4365 | 1768 | elif s3_has_role(ORG_VOL): | ||
4366 | 1769 | s3mgr.load("vol_application") | ||
4367 | 1770 | # Volunteer Orgs can see Public Requests & those published for them | ||
4368 | 1771 | org = auth.user.organisation_id | ||
4369 | 1772 | response.s3.filter = (req_table.public == True) | \ | ||
4370 | 1773 | (req_table.organisations_id.belongs((org,))) | ||
4371 | 1774 | s3mgr.configure(req_table, | ||
4372 | 1775 | editable=False), # We need the Controller/Table ACL to be editable to be able to add components | ||
4373 | 1776 | if "application" in request.args: | ||
4374 | 1777 | s3.crud.submit_button = T("COMMIT") | ||
4375 | 1778 | table = db.vol_application | ||
4376 | 1779 | table.organisation_id.default = org | ||
4377 | 1780 | table.organisation_id.readable = table.organisation_id.writable = False | ||
4378 | 1781 | table.number.readable = table.number.writable = True | ||
4379 | 1782 | table.person_id.readable = table.person_id.writable = False | ||
4380 | 1783 | field = table.team_leader_id | ||
4381 | 1784 | field.readable = field.writable = True | ||
4382 | 1785 | field.requires = IS_NOT_EMPTY() | ||
4383 | 1786 | #table.person_id.label = T("Team Leader") | ||
4384 | 1787 | #table.person_id.comment = None | ||
4385 | 1788 | #table.person_id.widget = S3AddPersonWidget( | ||
4386 | 1789 | # #select_existing=False | ||
4387 | 1790 | # ) | ||
4388 | 1791 | #table.person_id.requires = IS_ADD_PERSON_WIDGET() | ||
4389 | 1792 | #field = table.team_leader | ||
4390 | 1793 | #field.readable = field.writable = True | ||
4391 | 1794 | #field.requires = IS_NOT_EMPTY() | ||
4392 | 1795 | #field = table.team_leader_contact | ||
4393 | 1796 | #field.readable = field.writable = True | ||
4394 | 1797 | #field.requires = IS_NOT_EMPTY() | ||
4395 | 1798 | table.emergency_contact_name.readable = table.emergency_contact_name.writable = False | ||
4396 | 1799 | table.emergency_contact_name.requires = [] | ||
4397 | 1800 | table.emergency_contact_relationship.readable = table.emergency_contact_relationship.writable = False | ||
4398 | 1801 | table.emergency_contact_relationship.requires = [] | ||
4399 | 1802 | table.emergency_contact_phone.readable = table.emergency_contact_phone.writable = False | ||
4400 | 1803 | table.emergency_contact_phone.requires = [] | ||
4401 | 1804 | s3.crud_strings["vol_application"].subtitle_create = "" | ||
4402 | 1805 | |||
4403 | 1806 | elif "assignment" in request.args: | ||
4404 | 1807 | table = db.vol_assignment | ||
4405 | 1808 | table.organisation_id.default = org | ||
4406 | 1809 | table.organisation_id.readable = table.organisation_id.writable = False | ||
4407 | 1810 | table.person_id.readable = table.person_id.writable = False | ||
4408 | 1811 | # Make the component multiple=False | ||
4409 | 1812 | # @ToDo: Currently multiple=False will just return the .first() record even if inaccessible! | ||
4410 | 1813 | # That would be fixed by a filter, however then UI would break. | ||
4411 | 1814 | s3mgr.model.add_component("vol_assignment", | ||
4412 | 1815 | req_req=dict(joinby="req_id", | ||
4413 | 1816 | multiple=False)) | ||
4414 | 1817 | else: | ||
4415 | 1818 | s3mgr.load("vol_application") | ||
4416 | 1819 | # Volunteers can only see Public Requests | ||
4417 | 1820 | response.s3.filter = (req_table.public == True) | ||
4418 | 1821 | s3mgr.configure(req_table, | ||
4419 | 1822 | editable=False), # We need the Controller/Table ACL to be editable to be able to add components | ||
4420 | 1823 | person = s3_logged_in_person() | ||
4421 | 1824 | if "application" in request.args: | ||
4422 | 1825 | # Check for required Skills | ||
4423 | 1826 | table = db.req_req_skill | ||
4424 | 1827 | query = (table.req_id == request.args[0]) | ||
4425 | 1828 | req = db(query).select(table.skill_id, | ||
4426 | 1829 | limitby=(0, 1)).first() | ||
4427 | 1830 | if req: | ||
4428 | 1831 | # Read the applicant's skills | ||
4429 | 1832 | table = db.vol_skill | ||
4430 | 1833 | query = (table.person_id == auth.s3_logged_in_person()) | ||
4431 | 1834 | skillset = db(query).select(table.skill_id, | ||
4432 | 1835 | limitby=(0, 1)).first() | ||
4433 | 1836 | gap = False | ||
4434 | 1837 | if not skillset: | ||
4435 | 1838 | gap = True | ||
4436 | 1839 | else: | ||
4437 | 1840 | for skill in req.skill_id: | ||
4438 | 1841 | if not skill in skillset.skill_id: | ||
4439 | 1842 | gap = True | ||
4440 | 1843 | break | ||
4441 | 1844 | if gap: | ||
4442 | 1845 | response.warning = T("Please check that you have the required skills for this assignment as you've not specified that you have all the required skills.") | ||
4443 | 1846 | |||
4444 | 1847 | s3.crud.submit_button = T("COMMIT") | ||
4445 | 1848 | table = db.vol_application | ||
4446 | 1849 | table.person_id.default = person | ||
4447 | 1850 | table.person_id.readable = table.person_id.writable = False | ||
4448 | 1851 | s3.crud_strings["vol_application"].subtitle_create = "" | ||
4449 | 1852 | # Read in current Emergency Contacts | ||
4450 | 1853 | ctable = db.vol_contact | ||
4451 | 1854 | query = (ctable.person_id == person) | ||
4452 | 1855 | contacts = db(query).select(limitby=(0, 1)).first() | ||
4453 | 1856 | if contacts: | ||
4454 | 1857 | table.emergency_contact_name.default = contacts.emergency_contact_name | ||
4455 | 1858 | table.emergency_contact_relationship.default = contacts.emergency_contact_relationship | ||
4456 | 1859 | table.emergency_contact_phone.default = contacts.emergency_contact_phone | ||
4457 | 1860 | |||
4458 | 1861 | elif "assignment" in request.args: | ||
4459 | 1862 | table = db.vol_assignment | ||
4460 | 1863 | table.person_id.default = person | ||
4461 | 1864 | table.person_id.readable = table.person_id.writable = False | ||
4462 | 1865 | # Make the component multiple=False | ||
4463 | 1866 | # @ToDo: Currently multiple=False will just return the .first() record even if inaccessible! | ||
4464 | 1867 | # That would be fixed by a filter, however then UI would break. | ||
4465 | 1868 | #s3mgr.model.add_component("vol_assignment", | ||
4466 | 1869 | # req_req=dict(joinby="req_id", | ||
4467 | 1870 | # multiple=False)) | ||
4468 | 1871 | s3mgr.configure("vol_assignment", | ||
4469 | 1872 | enforce_single_record=True) | ||
4470 | 1873 | |||
4471 | 1874 | def prep(r): | ||
4472 | 1875 | db.req_req.status.readable = db.req_req.status.writable = False | ||
4473 | 1876 | |||
4474 | 1877 | # Remove type from list_fields | ||
4475 | 1878 | list_fields = s3mgr.model.get_config("req_req", | ||
4476 | 1879 | "list_fields") | ||
4477 | 1880 | try: | ||
4478 | 1881 | list_fields.remove("type") | ||
4479 | 1882 | except: | ||
4480 | 1883 | # It has already been removed. | ||
4481 | 1884 | # This can happen if the req controller is called | ||
4482 | 1885 | # for a second time, such as when printing reports | ||
4483 | 1886 | # see vol.print_assignment() | ||
4484 | 1887 | pass | ||
4485 | 1888 | s3mgr.configure(tablename, list_fields=list_fields) | ||
4486 | 1889 | |||
4487 | 1890 | type = ( r.record and r.record.type ) or \ | ||
4488 | 1891 | ( request.vars and request.vars.default_type ) | ||
4489 | 1892 | if type: | ||
4490 | 1893 | type = int(type) | ||
4491 | 1894 | req_table.type.default = int(type) | ||
4492 | 1895 | |||
4493 | 1896 | # Filter the query based on type | ||
4494 | 1897 | if response.s3.filter: | ||
4495 | 1898 | response.s3.filter = response.s3.filter & \ | ||
4496 | 1899 | (db.req_req.type == type) | ||
4497 | 1900 | else: | ||
4498 | 1901 | response.s3.filter = (db.req_req.type == type) | ||
4499 | 1902 | |||
4500 | 1903 | #if type == 3: | ||
4501 | 1904 | s3mgr.configure("req_req", | ||
4502 | 1905 | list_fields = ["id", | ||
4503 | 1906 | "priority", | ||
4504 | 1907 | "event_id", | ||
4505 | 1908 | "purpose", | ||
4506 | 1909 | "site_id", | ||
4507 | 1910 | "date_required", | ||
4508 | 1911 | ]) | ||
4509 | 1912 | |||
4510 | 1913 | if r.interactive: | ||
4511 | 1914 | # Set Fields and Labels depending on type | ||
4512 | 1915 | if type: | ||
4513 | 1916 | # This prevents the type from being edited AFTER it is set | ||
4514 | 1917 | req_table.type.readable = False | ||
4515 | 1918 | req_table.type.writable = False | ||
4516 | 1919 | |||
4517 | 1920 | crud_strings = deployment_settings.get_req_req_crud_strings(type) | ||
4518 | 1921 | if crud_strings: | ||
4519 | 1922 | s3.crud_strings["req_req"] = crud_strings | ||
4520 | 1923 | |||
4521 | 1924 | if "application" in request.args: | ||
4522 | 1925 | s3.crud_strings["req_req"].title_display = T("Volunteer Application") | ||
4523 | 1926 | elif "assignment" in request.args: | ||
4524 | 1927 | if s3_has_role(STAFF) and not r.component_id: | ||
4525 | 1928 | s3.crud_strings["req_req"].title_display = T("Volunteer Roster") | ||
4526 | 1929 | else: | ||
4527 | 1930 | s3.crud_strings["req_req"].title_display = T("Volunteer Assignment") | ||
4528 | 1931 | atable = db.vol_assignment | ||
4529 | 1932 | # @ToDo: Hide if vol hasn't yet checked-out or if time not > time_until | ||
4530 | 1933 | #atable.task_evaluation.readable = False | ||
4531 | 1934 | |||
4532 | 1935 | |||
4533 | 1936 | if r.method != "create": | ||
4534 | 1937 | # Disable Edit for fields where WebEOC is Master | ||
4535 | 1938 | req_table.event_id.writable = False | ||
4536 | 1939 | req_table.incident_id.writable = False | ||
4537 | 1940 | #req_table.incident_id.writable = True | ||
4538 | 1941 | req_table.request_number.writable = False | ||
4539 | 1942 | req_table.priority.writable = False | ||
4540 | 1943 | req_table.site_id.writable = False | ||
4541 | 1944 | req_table.request_for_id.writable = False | ||
4542 | 1945 | req_table.date_required.writable = False | ||
4543 | 1946 | req_table.date_required_until.writable = False | ||
4544 | 1947 | req_table.purpose.writable = False | ||
4545 | 1948 | req_table.date.writable = False | ||
4546 | 1949 | req_table.requester_id.writable = False | ||
4547 | 1950 | req_table.approved_by_id.writable = False | ||
4548 | 1951 | req_table.comments.writable = False | ||
4549 | 1952 | req_table.cancel.writable = False | ||
4550 | 1953 | |||
4551 | 1954 | if r.record and r.record.req_req_skill.count():#r.component and r.component.name == "req_skill": | ||
4552 | 1955 | # Is this component being updated (not created) | ||
4553 | 1956 | req_skill_table = db.req_req_skill | ||
4554 | 1957 | req_skill_table.skill_id.writable = False | ||
4555 | 1958 | req_skill_table.quantity.writable = False | ||
4556 | 1959 | |||
4557 | 1960 | # @ToDo: apply these changes via JS for the create form where type is editable | ||
4558 | 1961 | #if type == 3: # Person | ||
4559 | 1962 | req_table.date_required.requires = req_table.date_required.requires.other | ||
4560 | 1963 | req_table.date_required_until.requires = req_table.date_required_until.requires.other | ||
4561 | 1964 | req_table.location.readable = True | ||
4562 | 1965 | req_table.public.readable = True | ||
4563 | 1966 | req_table.organisations_id.readable = True | ||
4564 | 1967 | req_table.emailed.readable = True | ||
4565 | 1968 | |||
4566 | 1969 | if r.method == "create": | ||
4567 | 1970 | # Only enable Edit for fields where Sahana (not WebEOC) is Master | ||
4568 | 1971 | req_table.location.writable = True | ||
4569 | 1972 | req_table.public.writable = True | ||
4570 | 1973 | req_table.organisations_id.writable = True | ||
4571 | 1974 | |||
4572 | 1975 | req_table.purpose.label = T("Task Details") | ||
4573 | 1976 | req_table.site_id.label = T("Report To Facility") | ||
4574 | 1977 | req_table.request_for_id.label = T("Point of Contact") | ||
4575 | 1978 | |||
4576 | 1979 | if r.method != "update" and r.method != "read": | ||
4577 | 1980 | if not r.component: | ||
4578 | 1981 | # Hide fields which don't make sense in a Create form | ||
4579 | 1982 | # - includes one embedded in list_create | ||
4580 | 1983 | # - list_fields over-rides, so still visible within list itself | ||
4581 | 1984 | response.s3.req_create_form_mods() | ||
4582 | 1985 | |||
4583 | 1986 | # Get the default Facility for this user | ||
4584 | 1987 | # @ToDo: Use site_id in User Profile (like current organisation_id) | ||
4585 | 1988 | if deployment_settings.has_module("hrm"): | ||
4586 | 1989 | query = (db.hrm_human_resource.person_id == s3_logged_in_person()) | ||
4587 | 1990 | site = db(query).select(db.org_site.id, | ||
4588 | 1991 | limitby=(0, 1)).first() | ||
4589 | 1992 | if site: | ||
4590 | 1993 | r.table.site_id.default = site.id | ||
4591 | 1994 | |||
4592 | 1995 | elif r.component.name == "document": | ||
4593 | 1996 | s3.crud.submit_button = T("Add") | ||
4594 | 1997 | table = r.component.table | ||
4595 | 1998 | # @ToDo: Fix for Link Table | ||
4596 | 1999 | #table.date.default = r.record.date | ||
4597 | 2000 | #if r.record.site_id: | ||
4598 | 2001 | # stable = db.org_site | ||
4599 | 2002 | # query = (stable.id == r.record.site_id) | ||
4600 | 2003 | # site = db(query).select(stable.location_id, | ||
4601 | 2004 | # stable.organisation_id, | ||
4602 | 2005 | # limitby=(0, 1)).first() | ||
4603 | 2006 | # if site: | ||
4604 | 2007 | # table.location_id.default = site.location_id | ||
4605 | 2008 | # table.organisation_id.default = site.organisation_id | ||
4606 | 2009 | |||
4607 | 2010 | elif r.component.name == "req_skill": | ||
4608 | 2011 | #req_hide_quantities(r.component.table) | ||
4609 | 2012 | table = r.component.table | ||
4610 | 2013 | table.quantity_commit.writable = table.quantity_commit.readable = False | ||
4611 | 2014 | table.quantity_fulfil.writable = table.quantity_fulfil.readable = False | ||
4612 | 2015 | |||
4613 | 2016 | if r.component: | ||
4614 | 2017 | if r.component.name == "document" or \ | ||
4615 | 2018 | r.component.name == "req_skill": | ||
4616 | 2019 | # Limit site_id to facilities the user has permissions for | ||
4617 | 2020 | # @ToDo: Non-Item requests shouldn't be bound to a Facility? | ||
4618 | 2021 | auth.permission.permitted_facilities(table=r.table, | ||
4619 | 2022 | error_msg=T("You do not have permission for any facility to make a request.")) | ||
4620 | 2023 | |||
4621 | 2024 | elif r.component.name == "assignment": | ||
4622 | 2025 | # Tweak the breadcrumb | ||
4623 | 2026 | if r.component.count() > 1: | ||
4624 | 2027 | label = T("Roster") | ||
4625 | 2028 | else: | ||
4626 | 2029 | label = T("Assignment") | ||
4627 | 2030 | breadcrumbs[2] = (label, False, | ||
4628 | 2031 | URL(c=request.controller, | ||
4629 | 2032 | f=request.function, | ||
4630 | 2033 | args=request.args)) | ||
4631 | 2034 | table = db.vol_assignment | ||
4632 | 2035 | if s3_has_role(STAFF): | ||
4633 | 2036 | table.report_to_id.default = r.record.request_for_id | ||
4634 | 2037 | else: | ||
4635 | 2038 | # Volunteer can evaluate task if vol has checked-in and (checked-out or time > time_until) | ||
4636 | 2039 | query = (table.id == r.component_id) | ||
4637 | 2040 | assign = db(query).select(table.checkin, | ||
4638 | 2041 | table.checkout, | ||
4639 | 2042 | limitby=(0, 1)).first() | ||
4640 | 2043 | checkin = None | ||
4641 | 2044 | if assign: | ||
4642 | 2045 | checkin = assign.checkin | ||
4643 | 2046 | checkout = assign.checkout | ||
4644 | 2047 | query = (req_table.id == r.id) | ||
4645 | 2048 | req = db(query).select(req_table.date_required_until, | ||
4646 | 2049 | limitby=(0, 1)).first() | ||
4647 | 2050 | if req: | ||
4648 | 2051 | required_until = req.date_required_until | ||
4649 | 2052 | else: | ||
4650 | 2053 | required_until = datetime.datetime(3000, 1, 1) | ||
4651 | 2054 | |||
4652 | 2055 | if checkin and (checkout or \ | ||
4653 | 2056 | request.utcnow > required_until): | ||
4654 | 2057 | table.task_evaluation.writable = True | ||
4655 | 2058 | table.task_eval_comments.writable = True | ||
4656 | 2059 | else: | ||
4657 | 2060 | table.task_evaluation.readable = False | ||
4658 | 2061 | table.task_eval_comments.readable = False | ||
4659 | 2062 | if s3_has_role(ORG_VOL): | ||
4660 | 2063 | # Allow to edit Who/How Many until Evaluation time | ||
4661 | 2064 | s3.crud_strings.vol_assignment.title_update = T("Application Details") | ||
4662 | 2065 | table.team_leader_id.readable = table.team_leader_id.writable = True | ||
4663 | 2066 | table.number.readable = table.number.writable = True | ||
4664 | 2067 | table.number.label = T("Number of Volunteers Committed") | ||
4665 | 2068 | |||
4666 | 2069 | elif r.id and \ | ||
4667 | 2070 | r.component.name == "application" and \ | ||
4668 | 2071 | r.method == "create": | ||
4669 | 2072 | |||
4670 | 2073 | if not auth.user.organisation_id: | ||
4671 | 2074 | # Display an error message if the user has already got an | ||
4672 | 2075 | # assignment during this time period, this can | ||
4673 | 2076 | # alternatively be done onvalidation of the application, | ||
4674 | 2077 | # but doing it here is better UX and saves a query: | ||
4675 | 2078 | req_id = r.id | ||
4676 | 2079 | req = r.record | ||
4677 | 2080 | # @todo: make min_lag deployment setting: | ||
4678 | 2081 | min_lag = datetime.timedelta(hours=1) | ||
4679 | 2082 | # Earliest that another Request can start | ||
4680 | 2083 | earliest = req.date_required_until + min_lag | ||
4681 | 2084 | # Latest that another Request can end | ||
4682 | 2085 | latest = req.date_required - min_lag | ||
4683 | 2086 | person_id = s3_logged_in_person() | ||
4684 | 2087 | if person_id: | ||
4685 | 2088 | rtable = db.req_req | ||
4686 | 2089 | atable = db.vol_assignment | ||
4687 | 2090 | query = (atable.person_id == person_id) & \ | ||
4688 | 2091 | (rtable.id == atable.req_id) & \ | ||
4689 | 2092 | ((rtable.date_required >= earliest) | \ | ||
4690 | 2093 | (rtable.date_required_until >= latest)) | ||
4691 | 2094 | conflict = db(query).select(rtable.id, | ||
4692 | 2095 | limitby=(0, 1)).first() | ||
4693 | 2096 | if conflict: | ||
4694 | 2097 | session.error = T("You are assigned to another request during this time period") | ||
4695 | 2098 | redirect(URL(c="vol", f="req_skill")) | ||
4696 | 2099 | # Could be made less strong: | ||
4697 | 2100 | #response.error = T("You are assigned to another request during this time period") | ||
4698 | 2101 | else: | ||
4699 | 2102 | # Limit site_id to facilities the user has permissions for | ||
4700 | 2103 | # @ToDo: Non-Item requests shouldn't be bound to a Facility? | ||
4701 | 2104 | auth.permission.permitted_facilities(table=r.table, | ||
4702 | 2105 | error_msg=T("You do not have permission for any facility to make a request.")) | ||
4703 | 2106 | |||
4704 | 2107 | return True | ||
4705 | 2108 | response.s3.prep = prep | ||
4706 | 2109 | |||
4707 | 2110 | # Post-process | ||
4708 | 2111 | def postp(r, output): | ||
4709 | 2112 | |||
4710 | 2113 | if r.interactive: | ||
4711 | 2114 | if r.http == "POST": | ||
4712 | 2115 | form = output.get("form", None) | ||
4713 | 2116 | if not form.errors: | ||
4714 | 2117 | # Form submitted Succesfully | ||
4715 | 2118 | # interactive-only onaccept routines can go here | ||
4716 | 2119 | if r.component and \ | ||
4717 | 2120 | r.component.name == "application": | ||
4718 | 2121 | # Check whether Request Full: | ||
4719 | 2122 | # Create Assignment, Update Commit status | ||
4720 | 2123 | response.s3.application_onaccept_interactive(form) | ||
4721 | 2124 | |||
4722 | 2125 | # GET & POST | ||
4723 | 2126 | s3_action_buttons(r) | ||
4724 | 2127 | if not r.component: | ||
4725 | 2128 | # This is only appropriate for item requests | ||
4726 | 2129 | pass | ||
4727 | 2130 | elif r.component.name == "req_skill": | ||
4728 | 2131 | pass | ||
4729 | 2132 | elif r.component.name == "application": | ||
4730 | 2133 | try: | ||
4731 | 2134 | form = output["form"] | ||
4732 | 2135 | if form.errors.dsw: | ||
4733 | 2136 | dsw_error = DIV(form.errors.dsw, | ||
4734 | 2137 | _id="dsw__error", | ||
4735 | 2138 | _class="error", | ||
4736 | 2139 | _style="display: block;") | ||
4737 | 2140 | else: | ||
4738 | 2141 | dsw_error = "" | ||
4739 | 2142 | give2la_forms = A( T("Give2LA Registration Forms"), | ||
4740 | 2143 | _href = URL(c="static", | ||
4741 | 2144 | f="Volunteer_Ethics_and_Conduct.pdf") | ||
4742 | 2145 | ) | ||
4743 | 2146 | vol_appl_conditions = SPAN( XML(T("As a volunteer working to assist disaster survivors and in disaster recovery efforts, you will be required to fill out and sign the %(give2la_forms)s. Please print these forms and bring them to the Volunteering Location. The forms are in English only.") % \ | ||
4744 | 2147 | dict(give2la_forms = give2la_forms) | ||
4745 | 2148 | ), | ||
4746 | 2149 | #T("As a volunteer working to assist disaster survivors and in disaster recovery efforts, you will be required to sign the following forms: "), | ||
4747 | 2150 | #A( T("Personal Statement of Understanding"), | ||
4748 | 2151 | # _href = URL(c="static", | ||
4749 | 2152 | # f="Volunteer_Personal_Statement.pdf"), | ||
4750 | 2153 | # ), | ||
4751 | 2154 | #", ", | ||
4752 | 2155 | #A( T("City of Los Angeles Code of Volunteer Ethics and Conduct"), | ||
4753 | 2156 | # _href = URL(c="static", | ||
4754 | 2157 | # f="Volunteer_Ethics_and_Conduct.pdf"), | ||
4755 | 2158 | # ), | ||
4756 | 2159 | #T("and "), | ||
4757 | 2160 | #A( T("DSW Volunteer Registration Form "), | ||
4758 | 2161 | # _href = URL(c="static", | ||
4759 | 2162 | # f="DSW_Volunteer_Registration_Form.pdf"), | ||
4760 | 2163 | # ), | ||
4761 | 2164 | #T("or "), | ||
4762 | 2165 | #A( T("Waiver/Release of Liability"), | ||
4763 | 2166 | # _href = URL(c="static", | ||
4764 | 2167 | # f="Volunteer_Personal_Statement.pdf"), | ||
4765 | 2168 | # ), | ||
4766 | 2169 | #T(". All forms will be in English."), | ||
4767 | 2170 | BR(), | ||
4768 | 2171 | T("Check here to agree to these conditions:") | ||
4769 | 2172 | ) | ||
4770 | 2173 | form[0][-2].append(TR(TD(LABEL(vol_appl_conditions, | ||
4771 | 2174 | _for="dsw", | ||
4772 | 2175 | _style="display: inline;", | ||
4773 | 2176 | _id="dsw__label"), | ||
4774 | 2177 | SPAN("*", _class="req"), | ||
4775 | 2178 | INPUT(_type="checkbox", | ||
4776 | 2179 | _value="on", | ||
4777 | 2180 | _name="dsw", | ||
4778 | 2181 | _id="dsw", | ||
4779 | 2182 | _class="boolean"), | ||
4780 | 2183 | dsw_error, | ||
4781 | 2184 | _class="w2p_fl"), | ||
4782 | 2185 | _id="dsw__row")) | ||
4783 | 2186 | form[0][-1][0][0]["_class"] = "accept-button" | ||
4784 | 2187 | form[0][-1][0].append(BR()) | ||
4785 | 2188 | form[0][-1][0].append(INPUT(_type="button", | ||
4786 | 2189 | _value=T("DECLINE"), | ||
4787 | 2190 | _class="wide-grey-button", | ||
4788 | 2191 | _onClick="javascript: window.location='%s'" % \ | ||
4789 | 2192 | URL(c=request.controller, | ||
4790 | 2193 | f="req_skill"))) | ||
4791 | 2194 | except KeyError: | ||
4792 | 2195 | # update 'form' | ||
4793 | 2196 | pass | ||
4794 | 2197 | if "subtitle" in output and not output["subtitle"]: | ||
4795 | 2198 | # Remove null subtitle from Application form to avoid CSS markup | ||
4796 | 2199 | output.pop("subtitle") | ||
4797 | 2200 | |||
4798 | 2201 | elif r.component.name == "assignment": | ||
4799 | 2202 | ctable = r.component.table | ||
4800 | 2203 | # This is always appropriate | ||
4801 | 2204 | response.s3.actions = [ | ||
4802 | 2205 | dict(url = URL(f = "req", | ||
4803 | 2206 | args = [r.id, | ||
4804 | 2207 | r.component_name, | ||
4805 | 2208 | "[id]"]), | ||
4806 | 2209 | _class = "action-btn", | ||
4807 | 2210 | label = str(T("Details")) | ||
4808 | 2211 | )] | ||
4809 | 2212 | # This is only appropriate if vol not yet checked-in | ||
4810 | 2213 | query = (ctable.checkin == None) | ||
4811 | 2214 | rows = db(query).select(ctable.id) | ||
4812 | 2215 | restrict = [str(row.id) for row in rows] | ||
4813 | 2216 | response.s3.actions.append( | ||
4814 | 2217 | dict(url = URL(f = "req", | ||
4815 | 2218 | args = [r.id, | ||
4816 | 2219 | r.component_name, | ||
4817 | 2220 | "[id]", | ||
4818 | 2221 | "checkin"]), | ||
4819 | 2222 | _class = "action-btn", | ||
4820 | 2223 | label = str(T("Check-In NOW")), | ||
4821 | 2224 | restrict = restrict | ||
4822 | 2225 | ) | ||
4823 | 2226 | ) | ||
4824 | 2227 | # This is only appropriate if vol checked-in but not out | ||
4825 | 2228 | query = (ctable.checkin != None) & \ | ||
4826 | 2229 | (ctable.checkout == None) | ||
4827 | 2230 | rows = db(query).select(ctable.id) | ||
4828 | 2231 | restrict = [str(row.id) for row in rows] | ||
4829 | 2232 | response.s3.actions.append( | ||
4830 | 2233 | dict(url = URL(f = "req", | ||
4831 | 2234 | args = [r.id, | ||
4832 | 2235 | r.component_name, | ||
4833 | 2236 | "[id]", | ||
4834 | 2237 | "checkout"]), | ||
4835 | 2238 | _class = "action-btn", | ||
4836 | 2239 | label = str(T("Check-Out NOW")), | ||
4837 | 2240 | restrict = restrict | ||
4838 | 2241 | ) | ||
4839 | 2242 | ) | ||
4840 | 2243 | else: | ||
4841 | 2244 | # We don't yet have other components | ||
4842 | 2245 | pass | ||
4843 | 2246 | |||
4844 | 2247 | return output | ||
4845 | 2248 | response.s3.postp = postp | ||
4846 | 2249 | |||
4847 | 2250 | rheader = vol_req_rheader | ||
4848 | 2251 | |||
4849 | 2252 | output = s3_rest_controller("req", "req", rheader=rheader) | ||
4850 | 2253 | |||
4851 | 2254 | return output | ||
4852 | 2255 | |||
4853 | 2256 | # ----------------------------------------------------------------------------- | ||
4854 | 2257 | def req_skill(): | ||
4855 | 2258 | """ REST Controller """ | ||
4856 | 2259 | |||
4857 | 2260 | if s3_has_role(ORG_DON) and not s3_has_role(ORG_VOL): | ||
4858 | 2261 | session.warning = T("As a Corporation/Organization we suggest you donate staff as Services. If you wish to volunteer personally, then please sign out and then login with another account.") | ||
4859 | 2262 | redirect(URL(c="don", f="organisation", args=[auth.user.organisation_id, "inv_item"], vars={"item":"services"})) | ||
4860 | 2263 | |||
4861 | 2264 | if s3_has_role(STAFF): | ||
4862 | 2265 | # NB No link leads them here | ||
4863 | 2266 | # Tweak the breadcrumbs | ||
4864 | 2267 | breadcrumbs[2] = (T("Requests for Volunteers"), False, | ||
4865 | 2268 | URL(c=request.controller, | ||
4866 | 2269 | f=request.function)) | ||
4867 | 2270 | |||
4868 | 2271 | tablename = "req_req_skill" | ||
4869 | 2272 | s3mgr.load(tablename) | ||
4870 | 2273 | table = db[tablename] | ||
4871 | 2274 | |||
4872 | 2275 | s3mgr.configure(tablename, | ||
4873 | 2276 | insertable=False) | ||
4874 | 2277 | |||
4875 | 2278 | if not s3_has_role(STAFF): | ||
4876 | 2279 | req_table = db.req_req | ||
4877 | 2280 | s3mgr.load("vol_assignment") | ||
4878 | 2281 | vtable = db.vol_assignment | ||
4879 | 2282 | |||
4880 | 2283 | #if auth.is_logged_in(): | ||
4881 | 2284 | # person = auth.s3_logged_in_person() | ||
4882 | 2285 | #else: | ||
4883 | 2286 | vol_sidebar() | ||
4884 | 2287 | |||
4885 | 2288 | # Filter out: | ||
4886 | 2289 | # Reqs which haven't been published to the public site | ||
4887 | 2290 | # Reqs which are complete (status defined in models/req.py) | ||
4888 | 2291 | # @ToDo: if s3_has_role(ORG) then also allow reqs for that Org | ||
4889 | 2292 | response.s3.filter = \ | ||
4890 | 2293 | ((req_table.id == table.req_id) & (req_table.public == True)) & \ | ||
4891 | 2294 | ((req_table.id == table.req_id) & (req_table.commit_status != 2)) | ||
4892 | 2295 | |||
4893 | 2296 | #if auth.s3_is_logged_in(): | ||
4894 | 2297 | # # Filter Out: | ||
4895 | 2298 | # # Reqs which the Vol has already got an Assignment for | ||
4896 | 2299 | # response.s3.filter = response.s3.filter & \ | ||
4897 | 2300 | # ~((vtable.req_id == table.req_id) & (vtable.person_id == person)) | ||
4898 | 2301 | |||
4899 | 2302 | s3mgr.configure(tablename, | ||
4900 | 2303 | list_fields=["id", | ||
4901 | 2304 | (T("Task"), "task"), | ||
4902 | 2305 | (T("Date + Time"), "date"), | ||
4903 | 2306 | "skill_id", | ||
4904 | 2307 | # @ToDo: If-needed, VirtualField | ||
4905 | 2308 | #"priority", | ||
4906 | 2309 | (T("Location"), "location"), | ||
4907 | 2310 | #(T("Number of Volunteers Needed (Still Needed/Total Needed)"), "needed"), | ||
4908 | 2311 | (T("Number of Volunteers Still Needed"), "needed"), | ||
4909 | 2312 | #"quantity", | ||
4910 | 2313 | "comments" | ||
4911 | 2314 | ]) | ||
4912 | 2315 | actions = [ | ||
4913 | 2316 | dict(url = URL(c = "vol", | ||
4914 | 2317 | f = "req", | ||
4915 | 2318 | args = ["application", "create"], | ||
4916 | 2319 | vars = {"skill_id" : "[id]"}), | ||
4917 | 2320 | _class = "apply-button", | ||
4918 | 2321 | label = str(T("Apply")) | ||
4919 | 2322 | ) | ||
4920 | 2323 | ] | ||
4921 | 2324 | else: | ||
4922 | 2325 | actions = [ | ||
4923 | 2326 | dict(url = URL(c = "vol", | ||
4924 | 2327 | f = "req", | ||
4925 | 2328 | args = ["req_skill", "[id]"]), | ||
4926 | 2329 | _class = "action-btn", | ||
4927 | 2330 | label = str(READ) | ||
4928 | 2331 | ) | ||
4929 | 2332 | ] | ||
4930 | 2333 | |||
4931 | 2334 | def prep(r): | ||
4932 | 2335 | if r.interactive: | ||
4933 | 2336 | if r.method != "update" and r.method != "read": | ||
4934 | 2337 | # Hide fields which don't make sense in a Create form | ||
4935 | 2338 | # - includes one embedded in list_create | ||
4936 | 2339 | # - list_fields over-rides, so still visible within list itself | ||
4937 | 2340 | response.s3.req_hide_quantities(r.table) | ||
4938 | 2341 | |||
4939 | 2342 | return True | ||
4940 | 2343 | response.s3.prep = prep | ||
4941 | 2344 | |||
4942 | 2345 | # Post-process | ||
4943 | 2346 | def postp(r, output): | ||
4944 | 2347 | if r.interactive: | ||
4945 | 2348 | response.s3.actions = actions | ||
4946 | 2349 | if not s3_has_role(STAFF) and r.method == None: | ||
4947 | 2350 | if auth.is_logged_in(): | ||
4948 | 2351 | line = XML(T("If you have the required skills, click to %(apply_button)s") % | ||
4949 | 2352 | dict( apply_button = SPAN(T("Apply"), | ||
4950 | 2353 | _class="apply-button", | ||
4951 | 2354 | _style ="display:inline-block;text-align:center") | ||
4952 | 2355 | ) | ||
4953 | 2356 | ) | ||
4954 | 2357 | else: | ||
4955 | 2358 | line = TAG[""]( XML(T("Please %(register)s to volunteer with %(give2la)s and receive updates of new Requests for Volunteers.") % | ||
4956 | 2359 | dict( register = A( T("register"), | ||
4957 | 2360 | _href = URL(c = "vol", | ||
4958 | 2361 | f = "register") | ||
4959 | 2362 | ), | ||
4960 | 2363 | give2la = B("Give2", I("LA")) | ||
4961 | 2364 | ) | ||
4962 | 2365 | ), | ||
4963 | 2366 | #BR(), | ||
4964 | 2367 | #XML( T("If you have already registered please %(sign_in)s.") % | ||
4965 | 2368 | # dict( sign_in = A( T("Sign In"), | ||
4966 | 2369 | # _href = URL(c = "default", | ||
4967 | 2370 | # f = "user", | ||
4968 | 2371 | # args = ["login"], | ||
4969 | 2372 | # vars = dict(_next = "/la/vol/req_skill") | ||
4970 | 2373 | # ) | ||
4971 | 2374 | # ) | ||
4972 | 2375 | # ) | ||
4973 | 2376 | #) | ||
4974 | 2377 | ) | ||
4975 | 2378 | output["rheader"] = DIV( P( B(T("The City of Los Angeles has the following Requests for Volunteers.") ), | ||
4976 | 2379 | BR(), | ||
4977 | 2380 | line | ||
4978 | 2381 | ) | ||
4979 | 2382 | #T(" or "), | ||
4980 | 2383 | #A( T("Sign In"), _href = URL(c = "default", | ||
4981 | 2384 | # f = "user", | ||
4982 | 2385 | # args = ["login"], | ||
4983 | 2386 | # vars = dict(_next = "/la/vol/req_skill") | ||
4984 | 2387 | # ) | ||
4985 | 2388 | ) | ||
4986 | 2389 | #T("The City of Los Angeles requests your participation in the following volunteering opportunities. When you see a request that appeals to you click apply. If you have not registered to volunteer yet, please "), | ||
4987 | 2390 | #A(T("sign up"), | ||
4988 | 2391 | # _href="/%s/vol/register" % request.application, | ||
4989 | 2392 | # _class="signup"), | ||
4990 | 2393 | #T(" first. You can narrow down the list by for example searching for a specific task or your neighborhood.")) | ||
4991 | 2394 | return output | ||
4992 | 2395 | response.s3.postp = postp | ||
4993 | 2396 | |||
4994 | 2397 | output = s3_rest_controller("req", "req_skill") | ||
4995 | 2398 | |||
4996 | 2399 | return output | ||
4997 | 2400 | |||
4998 | 2401 | # ----------------------------------------------------------------------------- | ||
4999 | 2402 | def activity(): | ||
5000 | 2403 | """ REST Controller """ |