Merge lp:~sahana-eden-vms/sahana-eden/vms into lp:sahana-eden
- vms
- Merge into trunk
Proposed by
Pat Tressel
Status: | Merged |
---|---|
Merged at revision: | 993 |
Proposed branch: | lp:~sahana-eden-vms/sahana-eden/vms |
Merge into: | lp:sahana-eden |
Diff against target: |
816 lines (+329/-321) 9 files modified
controllers/msg.py (+2/-54) controllers/vol.py (+96/-10) models/msg.py (+66/-0) models/vol.py (+24/-132) views/msg/_compose.html (+133/-0) views/msg/compose.html (+2/-125) views/vol/compose_group.html (+2/-0) views/vol/compose_person.html (+2/-0) views/vol/view_team_map.html (+2/-0) |
To merge this branch: | bzr merge lp:~sahana-eden-vms/sahana-eden/vms |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Fran Boon | Pending | ||
Review via email: mp+32841@code.launchpad.net |
Commit message
Description of the change
This is Zubair's GSoC version. (It temporarily omits Dominic's vol changes -- we'll recover and merge those separately.) Changes in this version include maps of individual and team member locations, email to individual and team members. Multiselect widget for adding skills to a person has been removed as it's inappropriate for a table with multiple fields. This uses standard crud for skills, so they need to be added one at a time. Should not be a big issue. A skill can be deleted from a person by clicking edit on that skill, then delete skill on the edit page. We'll look into a fancier widget later.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'controllers/msg.py' |
2 | --- controllers/msg.py 2010-08-07 20:12:56 +0000 |
3 | +++ controllers/msg.py 2010-08-17 03:20:56 +0000 |
4 | @@ -353,60 +353,8 @@ |
5 | return shn_rest_controller(module, resource, deletable=False, listadd=False) |
6 | |
7 | def compose(): |
8 | - """ Form to Compose a Message """ |
9 | - resource1 = "log" |
10 | - tablename1 = module + "_" + resource1 |
11 | - table1 = db[tablename1] |
12 | - resource2 = "outbox" |
13 | - tablename2 = module + "_" + resource2 |
14 | - table2 = db[tablename2] |
15 | - |
16 | - if auth.is_logged_in() or auth.basic(): |
17 | - pass |
18 | - else: |
19 | - redirect(URL(r=request, c="default", f="user", args="login", |
20 | - vars={"_next":URL(r=request, c="msg", f="compose")})) |
21 | - |
22 | - # Model options |
23 | - table1.sender.writable = table1.sender.readable = False |
24 | - table1.fromaddress.writable = table1.fromaddress.readable = False |
25 | - table1.pe_id.writable = table1.pe_id.readable = False |
26 | - table1.verified.writable = table1.verified.readable = False |
27 | - table1.verified_comments.writable = table1.verified_comments.readable = False |
28 | - table1.actioned.writable = table1.actioned.readable = False |
29 | - table1.actionable.writable = table1.actionable.readable = False |
30 | - table1.actioned_comments.writable = table1.actioned_comments.readable = False |
31 | - |
32 | - table1.subject.label = T("Subject") |
33 | - table1.message.label = T("Message") |
34 | - table1.priority.label = T("Priority") |
35 | - |
36 | - table2.pe_id.writable = table2.pe_id.readable = True |
37 | - table2.pe_id.label = T("Recipients") |
38 | - |
39 | - def compose_onvalidation(form): |
40 | - """ Set the sender and use msg.send_by_pe_id to route the message """ |
41 | - if not request.vars.pe_id: |
42 | - session.error = T("Please enter the recipient") |
43 | - redirect(URL(r=request,c="msg", f="compose")) |
44 | - sender_pe_id = db(db.pr_person.uuid == auth.user.person_uuid).select(db.pr_person.pe_id, limitby=(0, 1)).first().pe_id |
45 | - if msg.send_by_pe_id(request.vars.pe_id, |
46 | - request.vars.subject, |
47 | - request.vars.message, |
48 | - sender_pe_id, |
49 | - request.vars.pr_message_method): |
50 | - session.flash = T("Message sent to outbox") |
51 | - redirect(URL(r=request, c="msg", f="compose")) |
52 | - else: |
53 | - session.error = T("Error in message") |
54 | - redirect(URL(r=request,c="msg", f="compose")) |
55 | - |
56 | - |
57 | - logform = crud.create(table1, |
58 | - onvalidation = compose_onvalidation) |
59 | - outboxform = crud.create(table2) |
60 | - |
61 | - return dict(logform = logform, outboxform = outboxform, title = T("Send Message")) |
62 | + |
63 | + return shn_msg_compose() |
64 | |
65 | def outbox(): |
66 | "View the contents of the Outbox" |
67 | |
68 | === modified file 'controllers/vol.py' |
69 | --- controllers/vol.py 2010-08-13 23:00:35 +0000 |
70 | +++ controllers/vol.py 2010-08-17 03:20:56 +0000 |
71 | @@ -4,6 +4,8 @@ |
72 | Volunteer Management System |
73 | """ |
74 | |
75 | +from gluon.sql import Rows |
76 | + |
77 | module = request.controller |
78 | |
79 | if module not in deployment_settings.modules: |
80 | @@ -33,7 +35,7 @@ |
81 | menu_teams = [ |
82 | [T("Teams"), False, URL(r=request, f="group"),[ |
83 | [T("List"), False, URL(r=request, f="group")], |
84 | - [T("Add"), False, URL(r=request, f="group", args="create", vars={"_next":URL(r=request, args=request.args, vars=request.vars)})], |
85 | + [T("Add"), False, URL(r=request, f="group", args="create")], |
86 | ]] |
87 | ] |
88 | menu.extend(menu_teams) |
89 | @@ -43,14 +45,17 @@ |
90 | if selection: |
91 | team_name = shn_pr_group_represent(group_id) |
92 | menu_teams = [ |
93 | - ["%s %s" % (T("Team:"), team_name), False, URL(r=request, f="group", args=[group_id, "read"])], |
94 | + ["%s %s" % (T("Team:"), team_name), False, URL(r=request, f="group", args=[group_id, "read"]),[ |
95 | + [T("View On Map"), False, URL(r=request, f="view_team_map", args=[group_id])], |
96 | + [T("Send Mail"), False, URL(r=request, f="compose_group", vars={"group_id":group_id})], |
97 | + ]], |
98 | ] |
99 | menu.extend(menu_teams) |
100 | |
101 | menu_persons = [ |
102 | - [T("Persons"), False, URL(r=request, f="person", args=["search_simple"], vars={"_next":URL(r=request, f="person", args=["[id]", "volunteer"], vars={"vol_tabs":"volunteer"})}),[ |
103 | - [T("List"), False, URL(r=request, f="person", vars={"_next":URL(r=request, f="person", args=["[id]", "volunteer"], vars={"vol_tabs":"volunteer"})})], |
104 | - [T("Add"), False, URL(r=request, f="person", args="create", vars={"_next":URL(r=request, f="person", args=["[id]", "volunteer"], vars={"vol_tabs":"volunteer"})})], |
105 | + [T("Persons"), False, URL(r=request, f="person", args=["search_simple"]),[ |
106 | + [T("List"), False, URL(r=request, f="person")], |
107 | + [T("Add"), False, URL(r=request, f="person", args="create")], |
108 | ]] |
109 | ] |
110 | menu.extend(menu_persons) |
111 | @@ -68,7 +73,8 @@ |
112 | [T("Volunteer Data"), False, URL(r=request, f="person", args=[person_id, "volunteer"], vars={"vol_tabs":"volunteer"})], |
113 | # The default tab is pr_person, which is fine here. |
114 | [T("Person Data"), False, URL(r=request, f="person", args=[person_id], vars={"vol_tabs":"person"})], |
115 | - [T("View Map"), False, URL(r=request, f="view_map", args=[person_id])], |
116 | + [T("View On Map"), False, URL(r=request, f="view_map", args=[person_id])], |
117 | + [T("Send Mail"), False, URL(r=request, f="compose_person", vars={"person_id":person_id})], |
118 | ]], |
119 | ] |
120 | menu.extend(menu_person) |
121 | @@ -78,7 +84,7 @@ |
122 | menu.extend(menu_skills) |
123 | if auth.user is not None: |
124 | menu_user = [ |
125 | - [T("My Tasks"), False, URL(r=request, f="task", args="")] |
126 | + [T("My Tasks"), False, URL(r=request, f="task", args="")], |
127 | ] |
128 | menu.extend(menu_user) |
129 | response.menu_options = menu |
130 | @@ -237,13 +243,13 @@ |
131 | |
132 | person_id = request.args(0) |
133 | |
134 | - presence_query = (db.pr_person.id == person_id) and (db.pr_presence.pe_id == db.pr_person.pe_id) and (db.gis_location.id == db.pr_presence.location_id) |
135 | + presence_query = (db.pr_person.id == person_id) & (db.pr_presence.pe_id == db.pr_person.pe_id) & (db.gis_location.id == db.pr_presence.location_id) |
136 | |
137 | # Need sql.Rows object for show_map, so don't extract individual row. |
138 | - location = db(presence_query).select(db.gis_location.ALL, orderby=~db.pr_presence.time, limitby=(0, 1)) |
139 | + location = db(presence_query).select(db.gis_location.ALL, orderby=~db.pr_presence.datetime, limitby=(0, 1)) |
140 | |
141 | if not location: |
142 | - address_query = (db.pr_person.id == person_id) and (db.pr_address.pe_id == db.pr_person.pe_id) and (db.gis_location.id == db.pr_address.location_id) |
143 | + address_query = (db.pr_person.id == person_id) & (db.pr_address.pe_id == db.pr_person.pe_id) & (db.gis_location.id == db.pr_address.location_id) |
144 | # TODO: If there are multiple addresses, which should we choose? |
145 | # For now, take whichever address is supplied first. |
146 | location = db(address_query).select(db.gis_location.ALL, limitby=(0, 1)) |
147 | @@ -371,6 +377,86 @@ |
148 | |
149 | |
150 | # ----------------------------------------------------------------------------- |
151 | +def view_team_map(): |
152 | + """ |
153 | + Map Location of Volunteer in a Team. |
154 | + Use most recent presence if available, else any address that's available. |
155 | + """ |
156 | + |
157 | + group_id = request.args(0) |
158 | + |
159 | + members_query = (db.pr_group_membership.group_id == group_id) |
160 | + members = db(members_query).select(db.pr_group_membership.person_id) #members of a team aka group |
161 | + member_person_ids = [ x.person_id for x in members ] #list of members |
162 | + |
163 | + #Presence Data of the members with Presence Logs |
164 | + presence_rows = db(db.pr_person.id.belongs(member_person_ids) & (db.pr_presence.pe_id == db.pr_person.pe_id) & (db.gis_location.id == db.pr_presence.location_id)).select(db.gis_location.ALL, db.pr_person.id, orderby=~db.pr_presence.datetime) |
165 | + #Get Latest Presence Data |
166 | + person_location_sort = presence_rows.sort(lambda row:row.pr_person.id) |
167 | + previous_person_id = None |
168 | + locations_list = [] |
169 | + for row in person_location_sort: |
170 | + if row.pr_person.id != previous_person_id: |
171 | + locations_list.append(row["gis_location"]) |
172 | + member_person_ids.remove(row.pr_person.id) |
173 | + previous_person_id = row.pr_person.id |
174 | + |
175 | + #Address of those members without Presence data |
176 | + address = db(db.pr_person.id.belongs(member_person_ids) & (db.pr_address.pe_id == db.pr_person.pe_id) & (db.gis_location.id == db.pr_address.location_id)).select(db.gis_location.ALL) |
177 | + |
178 | + locations_list.extend(address) |
179 | + |
180 | + if locations_list: |
181 | + |
182 | + bounds = gis.get_bounds(features=locations_list) |
183 | + |
184 | + volunteer = {"feature_group" : "People"} |
185 | + html = gis.show_map( |
186 | + feature_queries = [{"name" : "Volunteer", "query" : locations_list, "active" : True, "marker" : db(db.gis_marker.name == "volunteer").select().first().id}], |
187 | + feature_groups = [volunteer], |
188 | + wms_browser = {"name" : "Risk Maps", "url" : "http://preview.grid.unep.ch:8080/geoserver/ows?service=WMS&request=GetCapabilities"}, |
189 | + catalogue_overlays = True, |
190 | + catalogue_toolbar = True, |
191 | + toolbar = True, |
192 | + search = True, |
193 | + bbox = bounds, |
194 | + window = True, |
195 | + ) |
196 | + return dict(map=html) |
197 | + |
198 | + # TODO: What is an appropriate response if no location is available? |
199 | + return None |
200 | + |
201 | + |
202 | +# ----------------------------------------------------------------------------- |
203 | +def compose_person(): |
204 | + "Send message to volunteer" |
205 | + |
206 | + person_pe_id_query = (db.pr_person.id == request.vars.person_id) |
207 | + pe_id_row = db(person_pe_id_query).select(db.pr_person.pe_id).first() |
208 | + request.vars.pe_id = pe_id_row["pe_id"] |
209 | + |
210 | + return shn_msg_compose( redirect_module=module, |
211 | + redirect_function="compose_person", |
212 | + redirect_vars={"person_id":request.vars.person_id}, |
213 | + title_name="Send a message to a volunteer" ) |
214 | + |
215 | + |
216 | +# ----------------------------------------------------------------------------- |
217 | +def compose_group(): |
218 | + "Send message to members of a team" |
219 | + |
220 | + group_pe_id_query = (db.pr_group.id == request.vars.group_id) |
221 | + pe_id_row = db(group_pe_id_query).select(db.pr_group.pe_id).first() |
222 | + request.vars.pe_id = pe_id_row["pe_id"] |
223 | + |
224 | + return shn_msg_compose( redirect_module=module, |
225 | + redirect_function="compose_group", |
226 | + redirect_vars={"group_id":request.vars.group_id}, |
227 | + title_name="Send a message to a team of volunteers" ) |
228 | + |
229 | + |
230 | +# ----------------------------------------------------------------------------- |
231 | # TODO: Is resource a bad name, due to possible confusion with other usage? |
232 | def resource(): |
233 | "Select resources a volunteer has." |
234 | |
235 | === modified file 'models/msg.py' |
236 | --- models/msg.py 2010-08-11 22:48:49 +0000 |
237 | +++ models/msg.py 2010-08-17 03:20:56 +0000 |
238 | @@ -270,3 +270,69 @@ |
239 | Field("url", requires=IS_NULL_OR(IS_URL())), |
240 | migrate=migrate) |
241 | table.uuid.requires = IS_NOT_IN_DB(db, "%s.uuid" % tablename) |
242 | + |
243 | +def shn_msg_compose( redirect_module = "msg", |
244 | + redirect_function = "compose", |
245 | + redirect_vars = None, |
246 | + title_name = "Send Message" ): |
247 | + """ |
248 | + Form to Compose a Message |
249 | + |
250 | + @param redirect_module: Redirect to the specified module's url after login. |
251 | + @param redirect_function: Redirect to the specified function |
252 | + @param redirect_vars: Dict with vars to include in redirects |
253 | + @param title_name: Title of the page |
254 | + """ |
255 | + |
256 | + resource1 = "log" |
257 | + tablename1 = "msg" + "_" + resource1 |
258 | + table1 = db[tablename1] |
259 | + resource2 = "outbox" |
260 | + tablename2 = "msg" + "_" + resource2 |
261 | + table2 = db[tablename2] |
262 | + |
263 | + if auth.is_logged_in() or auth.basic(): |
264 | + pass |
265 | + else: |
266 | + redirect(URL(r=request, c="default", f="user", args="login", |
267 | + vars={"_next":URL(r=request, c=redirect_module, f=redirect_function, vars=redirect_vars)})) |
268 | + |
269 | + # Model options |
270 | + table1.sender.writable = table1.sender.readable = False |
271 | + table1.fromaddress.writable = table1.fromaddress.readable = False |
272 | + table1.pe_id.writable = table1.pe_id.readable = False |
273 | + table1.verified.writable = table1.verified.readable = False |
274 | + table1.verified_comments.writable = table1.verified_comments.readable = False |
275 | + table1.actioned.writable = table1.actioned.readable = False |
276 | + table1.actionable.writable = table1.actionable.readable = False |
277 | + table1.actioned_comments.writable = table1.actioned_comments.readable = False |
278 | + |
279 | + table1.subject.label = T("Subject") |
280 | + table1.message.label = T("Message") |
281 | + table1.priority.label = T("Priority") |
282 | + |
283 | + table2.pe_id.writable = table2.pe_id.readable = True |
284 | + table2.pe_id.label = T("Recipients") |
285 | + |
286 | + def compose_onvalidation(form): |
287 | + """ Set the sender and use msg.send_by_pe_id to route the message """ |
288 | + if not request.vars.pe_id: |
289 | + session.error = T("Please enter the recipient") |
290 | + redirect(URL(r=request,c=redirect_module, f=redirect_function, vars=redirect_vars)) |
291 | + sender_pe_id = db(db.pr_person.uuid == auth.user.person_uuid).select(db.pr_person.pe_id, limitby=(0, 1)).first().pe_id |
292 | + if msg.send_by_pe_id(request.vars.pe_id, |
293 | + request.vars.subject, |
294 | + request.vars.message, |
295 | + sender_pe_id, |
296 | + request.vars.pr_message_method): |
297 | + session.flash = T("Message sent to outbox") |
298 | + redirect(URL(r=request, c=redirect_module, f=redirect_function, vars=redirect_vars)) |
299 | + else: |
300 | + session.error = T("Error in message") |
301 | + redirect(URL(r=request,c=redirect_module, f=redirect_function, vars=redirect_vars)) |
302 | + |
303 | + logform = crud.create(table1, |
304 | + onvalidation = compose_onvalidation) |
305 | + outboxform = crud.create(table2) |
306 | + |
307 | + return dict(logform = logform, outboxform = outboxform, title = T(title_name)) |
308 | |
309 | === modified file 'models/vol.py' |
310 | --- models/vol.py 2010-08-16 21:08:38 +0000 |
311 | +++ models/vol.py 2010-08-17 03:20:56 +0000 |
312 | @@ -19,9 +19,6 @@ |
313 | migrate=migrate) |
314 | |
315 | # ------------------------------------------------------------------------- |
316 | - # Person components which are specifically volunteer data: |
317 | - shn_vol_volunteer_data = ("volunteer", "group_membership", "skill") |
318 | - # ------------------------------------------------------------------------- |
319 | # pr_volunteer (Component of pr_person) |
320 | # describes a person's availability as a volunteer |
321 | |
322 | @@ -399,11 +396,11 @@ |
323 | s3.crud_strings[tablename] = Storage( |
324 | title_create = T("Add Skill Type"), |
325 | title_display = T("Skill Type Details"), |
326 | - title_list = T("Skill Type"), |
327 | + title_list = T("Skill Types"), |
328 | title_update = T("Edit Skill Type"), |
329 | - title_search = T("Search Skill Type"), |
330 | + title_search = T("Search Skill Types"), |
331 | subtitle_create = T("Add New Skill Type"), |
332 | - subtitle_list = T("Skill Type"), |
333 | + subtitle_list = T("Skill Types"), |
334 | label_list_button = T("List Skill Types"), |
335 | label_create_button = T("Add Skill Types"), |
336 | label_delete_button = T("Delete Skill Type"), |
337 | @@ -412,22 +409,6 @@ |
338 | msg_record_deleted = T("Skill Type deleted"), |
339 | msg_list_empty = T("No Skill Types currently set")) |
340 | |
341 | - field_settings = S3CheckboxesWidget(db = db, |
342 | - lookup_table_name = "vol_skill_types", |
343 | - lookup_field_name = "name", |
344 | - multiple = True, |
345 | - num_column=3 |
346 | - ) |
347 | - |
348 | - # Reusable field |
349 | - skill_ids = db.Table(None, "skill_ids", |
350 | - FieldS3("skill_ids", |
351 | - requires = field_settings.requires, |
352 | - widget = field_settings.widget, |
353 | - represent = field_settings.represent, |
354 | - label = T("skills"), |
355 | - ondelete = "RESTRICT")) |
356 | - |
357 | # Representation function |
358 | def vol_skill_types_represent(id): |
359 | if id: |
360 | @@ -441,47 +422,31 @@ |
361 | else: |
362 | return None |
363 | |
364 | + skill_types_id = db.Table(None, "skill_types_id", |
365 | + FieldS3("skill_types_id", db.vol_skill_types, |
366 | + sortby = ["category", "name"], |
367 | + requires = IS_ONE_OF(db, "vol_skill_types.id", vol_skill_types_represent), |
368 | + represent = vol_skill_types_represent, |
369 | + label = T("Skill"), |
370 | + ondelete = "RESTRICT")) |
371 | + |
372 | |
373 | # ------------------------------------------------------------------------- |
374 | # vol_skill |
375 | # A volunteer's skills (component of pr) |
376 | # |
377 | |
378 | - def multiselect_widget(f, v): |
379 | - import uuid |
380 | - d_id = "multiselect-" + str(uuid.uuid4())[:8] |
381 | - wrapper = DIV(_id=d_id) |
382 | - inp = SQLFORM.widgets.options.widget(f, v) |
383 | - inp["_multiple"] = "multiple" |
384 | - inp["_style"] = "min-width: %spx;" % (len(f.name) * 20 + 50) |
385 | - if v: |
386 | - if not isinstance(v,list): v = str(v).split("|") |
387 | - opts = inp.elements("option") |
388 | - for op in opts: |
389 | - if op["_value"] in v: |
390 | - op["_selected"] = "selected" |
391 | - scr = SCRIPT('jQuery("#%s select").multiSelect({'\ |
392 | - 'noneSelected:"Select %ss"});' % (d_id, f.name)) |
393 | - wrapper.append(inp) |
394 | - wrapper.append(scr) |
395 | - if request.vars.get(inp["_id"] + "[]", None): |
396 | - var = request.vars[inp["_id"] + "[]"] |
397 | - if not isinstance(var,list): var = [var] |
398 | - request.vars[f.name] = "|".join(var) |
399 | - del request.vars[inp["_id"] + "[]"] |
400 | - return wrapper |
401 | - |
402 | resource = "skill" |
403 | tablename = module + "_" + resource |
404 | - table = db.define_table(tablename, timestamp, uuidstamp, deletion_status, |
405 | - person_id, |
406 | - Field("skill_types_id"), |
407 | - Field("status", requires=IS_IN_SET(["approved", "unapproved", "denied"]), label=T("status"), notnull=True, default="unapproved"), |
408 | - migrate=migrate) |
409 | - |
410 | - db.vol_skill.skill_types_id.widget = multiselect_widget |
411 | - db.vol_skill.skill_types_id.requires = IS_ONE_OF(db, "vol_skill_types.id", vol_skill_types_represent, multiple=True) |
412 | - #db.vol_skill.skill_types_id.represent = vol_skill_types_represent |
413 | + table = db.define_table( |
414 | + tablename, timestamp, uuidstamp, deletion_status, |
415 | + person_id, skill_types_id, |
416 | + Field("status", |
417 | + requires=IS_IN_SET(["approved","unapproved","denied"]), |
418 | + label=T("Status"), |
419 | + notnull=True, |
420 | + default="unapproved"), |
421 | + migrate=migrate) |
422 | |
423 | s3xrc.model.add_component(module, resource, |
424 | multiple=True, |
425 | @@ -502,17 +467,18 @@ |
426 | title_display = T("Skill Details"), |
427 | title_list = SKILL, |
428 | title_update = T("Edit Skill"), |
429 | - title_search = T("Search Skill"), |
430 | + title_search = T("Search Skills"), |
431 | subtitle_create = T("Add New Skill"), |
432 | subtitle_list = SKILL, |
433 | - label_list_button = T("List Skill"), |
434 | + label_list_button = T("List Skills"), |
435 | label_create_button = ADD_SKILL, |
436 | + label_delete_button = T("Delete Skill"), |
437 | msg_record_created = T("Skill added"), |
438 | msg_record_modified = T("Skill updated"), |
439 | msg_record_deleted = T("Skill deleted"), |
440 | msg_list_empty = T("No skills currently set")) |
441 | |
442 | - # shn_pr_group_represent ----------------------------------------------------- |
443 | + # shn_pr_group_represent ------------------------------------------------- |
444 | # |
445 | def teamname(record): |
446 | """ |
447 | @@ -536,77 +502,3 @@ |
448 | |
449 | name = cache.ram("pr_group_%s" % id, lambda: _represent(id)) |
450 | return name |
451 | - |
452 | - # ----------------------------------------------------------------------------- |
453 | - def shn_vol_view_map(jr, **attr): |
454 | - """ |
455 | - Map Location of Volunteer. |
456 | - Use most recent presence if available, else any address that's available. |
457 | - """ |
458 | - |
459 | - response.view = "vol/view_map.html" |
460 | - rheader = shn_vol_rheader(jr) |
461 | - |
462 | - output = dict(title=T("Volunteer location"), rheader=rheader) |
463 | - |
464 | - if jr.id: |
465 | - person_id = jr.id |
466 | - |
467 | - presence_query = (db.pr_person.id == person_id) & \ |
468 | - (db.pr_presence.pe_id == db.pr_person.pe_id) & \ |
469 | - (db.gis_location.id == db.pr_presence.location_id) |
470 | - |
471 | - # Need sql.Rows object for show_map, so don't extract individual row. |
472 | - location = db(presence_query).select(db.gis_location.ALL, |
473 | - orderby=~db.pr_presence.time, |
474 | - limitby=(0, 1)) |
475 | - |
476 | - if not location: |
477 | - address_query = (db.pr_person.id == person_id) & \ |
478 | - (db.pr_address.pe_id == db.pr_person.pe_id) & \ |
479 | - (db.gis_location.id == db.pr_address.location_id) |
480 | - |
481 | - # TODO: If there are multiple addresses, which should we choose? |
482 | - # For now, take whichever address is supplied first. |
483 | - location = db(address_query).select(db.gis_location.ALL, limitby=(0, 1)) |
484 | - |
485 | - if location: |
486 | - # Center and zoom the map. |
487 | - location_row = location.first() # location is a sql.Rows |
488 | - lat = location_row.lat |
489 | - lon = location_row.lon |
490 | - bounds = gis.get_bounds(features=location) |
491 | - |
492 | - marker = db(db.gis_marker.name == "volunteer").select().first() |
493 | - if marker: |
494 | - marker = marker.id |
495 | - else: |
496 | - marker = None |
497 | - |
498 | - volunteer = {"feature_group" : "People"} |
499 | - html = gis.show_map( |
500 | - feature_queries = [{"name" : "Volunteer", |
501 | - "query" : location, |
502 | - "active" : True, |
503 | - "marker" : marker}], |
504 | - feature_groups = [volunteer], |
505 | - catalogue_overlays = True, |
506 | - catalogue_toolbar = False, |
507 | - toolbar = True, |
508 | - search = True, |
509 | - lat = lat, |
510 | - lon = lon, |
511 | - bbox = bounds, |
512 | - window = True, |
513 | - ) |
514 | - output.update(map=html) |
515 | - |
516 | - else: |
517 | - # TODO: What is an appropriate response if no location is available? |
518 | - html = T("No location known of this person.") |
519 | - output.update(map=html) |
520 | - |
521 | - return output |
522 | - |
523 | - s3xrc.model.set_method("pr", "person", method="view_map", action=shn_vol_view_map) |
524 | - |
525 | |
526 | === added file 'views/msg/_compose.html' |
527 | --- views/msg/_compose.html 1970-01-01 00:00:00 +0000 |
528 | +++ views/msg/_compose.html 2010-08-17 03:20:56 +0000 |
529 | @@ -0,0 +1,133 @@ |
530 | +{{try:}} |
531 | + {{=H2(title)}} |
532 | +{{except:}} |
533 | +{{pass}} |
534 | +<script type="text/javascript">//<![CDATA[ |
535 | +$(function() { |
536 | + // Hide the real Input Field |
537 | + $('#msg_outbox_pe_id').hide(); |
538 | + // Autocomplete-enable the Dummy Input |
539 | + $('#dummy').autocomplete('{{=URL(r=request, c="msg", f="search")}}', { |
540 | + minChars: 2, |
541 | + //mustMatch: true, |
542 | + // TODO : Should get multiple working |
543 | + multiple: false, |
544 | + matchContains: true, |
545 | + autofill: true, |
546 | + dataType: 'json', |
547 | + parse: function(data) { |
548 | + var rows = new Array(); |
549 | + for(var i=0; i<data.length; i++){ |
550 | + rows[i] = { data:data[i], value:data[i].id, result:data[i].name }; |
551 | + } |
552 | + return rows; |
553 | + }, |
554 | + formatItem: function(row, i, n) { |
555 | + return row.name; |
556 | + } |
557 | + }); |
558 | + // Populate the real Input when the Dummy is selected |
559 | + $('#dummy').result(function(event, data, formatted) { |
560 | + var newvalue = data.id; |
561 | + $('#msg_outbox_pe_id').val(newvalue); |
562 | + }); |
563 | +// $('#dummy_submit').click(function(){ |
564 | +// return true; |
565 | +// }); |
566 | +$('#msg_outbox_pr_message_method').change(function() { |
567 | + if ($(this).val() == 1){//Dependent on pr_message_method |
568 | + $('#msg_log_subject__row').show(); |
569 | + } |
570 | + else{ |
571 | + $('#msg_log_subject__row').hide(); |
572 | + } |
573 | + }); |
574 | +}); |
575 | +//]]></script> |
576 | + |
577 | +<div class='form-container'> |
578 | +{{try:}} |
579 | + {{=logform.custom.begin}} |
580 | + <table> |
581 | + <tbody> |
582 | + <tr id='msg_outbox_pr_message_method__row'> |
583 | + <td> |
584 | + <label>{{=outboxform.custom.label.pr_message_method}}</label> |
585 | + </td> |
586 | + <td> |
587 | + {{=outboxform.custom.widget.pr_message_method}} |
588 | + </td> |
589 | + <td> |
590 | + {{=outboxform.custom.comment.pr_message_method}} |
591 | + </td> |
592 | + </tr> |
593 | + <tr id='msg_outbox_pe_id__row'> |
594 | + <td> |
595 | + <label>{{=outboxform.custom.label.pe_id}}</label> |
596 | + </td> |
597 | + {{if 'pe_id' in request.vars:}} |
598 | + <script type="text/javascript">//<![CDATA[ |
599 | + $('#msg_outbox_pe_id').val({{=request.vars.pe_id}}) |
600 | + //]]></script> |
601 | + <td> |
602 | + {{=shn_pentity_represent(request.vars.pe_id)}} |
603 | + </td> |
604 | + {{else:}} |
605 | + <td> |
606 | + {{=INPUT(_id="dummy", _class="ac_input", _size="50")}} |
607 | + {{=outboxform.custom.widget.pe_id}} |
608 | + </td> |
609 | + <td> |
610 | + {{=outboxform.custom.comment.pe_id}} |
611 | + </td> |
612 | + {{pass}} |
613 | + </tr> |
614 | + <tr id='msg_log_subject__row'> |
615 | + <td> |
616 | + <label>{{=logform.custom.label.subject}}</label> |
617 | + </td> |
618 | + <td> |
619 | + {{=logform.custom.widget.subject}} |
620 | + </td> |
621 | + <td> |
622 | + {{=logform.custom.comment.subject}} |
623 | + </td> |
624 | + </tr> |
625 | + <tr id='msg_log_message__row'> |
626 | + <td> |
627 | + <label>{{=logform.custom.label.message}}</label> |
628 | + </td> |
629 | + <td> |
630 | + {{=logform.custom.widget.message}} |
631 | + </td> |
632 | + <td> |
633 | + {{=logform.custom.comment.message}} |
634 | + </td> |
635 | + </tr> |
636 | + <tr id='msg_log_priority__row'> |
637 | + <td> |
638 | + <label>{{=logform.custom.label.priority}}</label> |
639 | + </td> |
640 | + <td> |
641 | + {{=logform.custom.widget.priority}} |
642 | + </td> |
643 | + <td> |
644 | + {{=logform.custom.comment.priority}} |
645 | + </td> |
646 | + </tr> |
647 | + <tr id='submit_record__row'> |
648 | + <td> |
649 | + </td> |
650 | + <td> |
651 | + {{=INPUT(_type="submit", _value=T("Send message"), _id="dummy_submit")}} |
652 | + </td> |
653 | + </tr> |
654 | + <td> |
655 | + </td> |
656 | + </tbody> |
657 | + </table> |
658 | + {{=logform.custom.end}} |
659 | +{{except:}} |
660 | +{{pass}} |
661 | +</div> |
662 | +<p> </p> |
663 | |
664 | === modified file 'views/msg/compose.html' |
665 | --- views/msg/compose.html 2010-07-24 16:05:47 +0000 |
666 | +++ views/msg/compose.html 2010-08-17 03:20:56 +0000 |
667 | @@ -1,125 +1,2 @@ |
668 | -{{extend "layout.html"}} |
669 | -{{try:}} |
670 | - {{=H2(title)}} |
671 | -{{except:}} |
672 | -{{pass}} |
673 | -<script type="text/javascript">//<![CDATA[ |
674 | -$(function() { |
675 | - // Hide the real Input Field |
676 | - $('#msg_outbox_pe_id').hide(); |
677 | - // Autocomplete-enable the Dummy Input |
678 | - $('#dummy').autocomplete('{{=URL(r=request, c="msg", f="search")}}', { |
679 | - minChars: 2, |
680 | - //mustMatch: true, |
681 | - // TODO : Should get multiple working |
682 | - multiple: false, |
683 | - matchContains: true, |
684 | - autofill: true, |
685 | - dataType: 'json', |
686 | - parse: function(data) { |
687 | - var rows = new Array(); |
688 | - for(var i=0; i<data.length; i++){ |
689 | - rows[i] = { data:data[i], value:data[i].id, result:data[i].name }; |
690 | - } |
691 | - return rows; |
692 | - }, |
693 | - formatItem: function(row, i, n) { |
694 | - return row.name; |
695 | - } |
696 | - }); |
697 | - // Populate the real Input when the Dummy is selected |
698 | - $('#dummy').result(function(event, data, formatted) { |
699 | - var newvalue = data.id; |
700 | - $('#msg_outbox_pe_id').val(newvalue); |
701 | - }); |
702 | -// $('#dummy_submit').click(function(){ |
703 | -// return true; |
704 | -// }); |
705 | -$('#msg_outbox_pr_message_method').change(function() { |
706 | - if ($(this).val() == 1){//Dependent on pr_message_method |
707 | - $('#msg_log_subject__row').show(); |
708 | - } |
709 | - else{ |
710 | - $('#msg_log_subject__row').hide(); |
711 | - } |
712 | - }); |
713 | -}); |
714 | -//]]></script> |
715 | - |
716 | -<div class='form-container'> |
717 | -{{try:}} |
718 | - {{=logform.custom.begin}} |
719 | - <table> |
720 | - <tbody> |
721 | - <tr id='msg_outbox_pr_message_method__row'> |
722 | - <td> |
723 | - <label>{{=outboxform.custom.label.pr_message_method}}</label> |
724 | - </td> |
725 | - <td> |
726 | - {{=outboxform.custom.widget.pr_message_method}} |
727 | - </td> |
728 | - <td> |
729 | - {{=outboxform.custom.comment.pr_message_method}} |
730 | - </td> |
731 | - </tr> |
732 | - <tr id='msg_outbox_pe_id__row'> |
733 | - <td> |
734 | - <label>{{=outboxform.custom.label.pe_id}}</label> |
735 | - </td> |
736 | - <td> |
737 | - {{=INPUT(_id="dummy", _class="ac_input", _size="50")}} |
738 | - {{=outboxform.custom.widget.pe_id}} |
739 | - </td> |
740 | - <td> |
741 | - {{=outboxform.custom.comment.pe_id}} |
742 | - </td> |
743 | -</tr> |
744 | - <tr id='msg_log_subject__row'> |
745 | - <td> |
746 | - <label>{{=logform.custom.label.subject}}</label> |
747 | - </td> |
748 | - <td> |
749 | - {{=logform.custom.widget.subject}} |
750 | - </td> |
751 | - <td> |
752 | - {{=logform.custom.comment.subject}} |
753 | - </td> |
754 | - </tr> |
755 | - <tr id='msg_log_message__row'> |
756 | - <td> |
757 | - <label>{{=logform.custom.label.message}}</label> |
758 | - </td> |
759 | - <td> |
760 | - {{=logform.custom.widget.message}} |
761 | - </td> |
762 | - <td> |
763 | - {{=logform.custom.comment.message}} |
764 | - </td> |
765 | - </tr> |
766 | - <tr id='msg_log_priority__row'> |
767 | - <td> |
768 | - <label>{{=logform.custom.label.priority}}</label> |
769 | - </td> |
770 | - <td> |
771 | - {{=logform.custom.widget.priority}} |
772 | - </td> |
773 | - <td> |
774 | - {{=logform.custom.comment.priority}} |
775 | - </td> |
776 | - </tr> |
777 | - <tr id='submit_record__row'> |
778 | - <td> |
779 | - </td> |
780 | - <td> |
781 | - {{=INPUT(_type="submit", _value=T("Send message"), _id="dummy_submit")}} |
782 | - </td> |
783 | - </tr> |
784 | - <td> |
785 | - </td> |
786 | - </tbody> |
787 | - </table> |
788 | - {{=logform.custom.end}} |
789 | -{{except:}} |
790 | -{{pass}} |
791 | -</div> |
792 | -<p> </p> |
793 | +{{extend 'layout.html'}} |
794 | +{{include 'msg/_compose.html'}} |
795 | |
796 | === added file 'views/vol/compose_group.html' |
797 | --- views/vol/compose_group.html 1970-01-01 00:00:00 +0000 |
798 | +++ views/vol/compose_group.html 2010-08-17 03:20:56 +0000 |
799 | @@ -0,0 +1,2 @@ |
800 | +{{extend 'layout.html'}} |
801 | +{{include 'msg/_compose.html'}} |
802 | |
803 | === added file 'views/vol/compose_person.html' |
804 | --- views/vol/compose_person.html 1970-01-01 00:00:00 +0000 |
805 | +++ views/vol/compose_person.html 2010-08-17 03:20:56 +0000 |
806 | @@ -0,0 +1,2 @@ |
807 | +{{extend 'layout.html'}} |
808 | +{{include 'msg/_compose.html'}} |
809 | |
810 | === added file 'views/vol/view_team_map.html' |
811 | --- views/vol/view_team_map.html 1970-01-01 00:00:00 +0000 |
812 | +++ views/vol/view_team_map.html 2010-08-17 03:20:56 +0000 |
813 | @@ -0,0 +1,2 @@ |
814 | +{{extend 'layout.html'}} |
815 | +{{=XML(map)}} |
816 | \ No newline at end of file |