Merge lp:~pratyush-nigam/sahana-eden/savesearch into lp:sahana-eden
- savesearch
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 2692 |
Proposed branch: | lp:~pratyush-nigam/sahana-eden/savesearch |
Merge into: | lp:sahana-eden |
Diff against target: |
1083 lines (+471/-232) 10 files modified
controllers/msg.py (+131/-2) controllers/pr.py (+69/-69) deployment-templates/cron/crontab (+7/-0) deployment-templates/models/000_config.py (+3/-0) models/04_pr.py (+79/-72) models/msg.py (+60/-24) models/zz_last.py (+1/-0) modules/s3/s3aaa.py (+1/-1) modules/s3/s3cfg.py (+7/-2) modules/s3/s3search.py (+113/-62) |
To merge this branch: | bzr merge lp:~pratyush-nigam/sahana-eden/savesearch |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Howden (community) | Needs Fixing | ||
Review via email: mp+69918@code.launchpad.net |
Commit message
Description of the change
- 2384. By Pratyush Nigam
-
removed the 80 characters in a single line
- 2385. By Pratyush Nigam
-
Merging
- 2386. By Pratyush Nigam
-
Merging
- 2387. By Pratyush Nigam
-
Removed some of the persisting errors
- 2388. By Pratyush Nigam
-
Started work on getting updates for the saved searches
- 2389. By Pratyush Nigam
-
Merging
- 2390. By Pratyush Nigam
-
Changes to find updates for the user who are subscribed to the saved searches
Work in Progress - 2391. By Pratyush Nigam
-
Merging
- 2392. By Pratyush Nigam
-
Got the subscription update part working to some extent.
- 2393. By Pratyush Nigam
-
Merging
- 2394. By Pratyush Nigam
-
Changes made to implement the subscription sending feature
- 2395. By Pratyush Nigam
-
Merging
- 2396. By Pratyush Nigam
-
Made some changes with respect to what gets displayed in the Search Criteria Column
- 2397. By Pratyush Nigam
-
Changes made to send subscription emails, email formatting and cronjob settings left
- 2398. By Pratyush Nigam
-
Email Formatting Improved and Cron jobs are set
- 2399. By Pratyush Nigam
-
Merging and Customized the saved searches tab
- 2400. By Pratyush Nigam
-
Merging
Michael Howden (michael-howden) : | # |
- 2401. By Pratyush Nigam
-
Code Documenting
- 2402. By Pratyush Nigam
-
Conflict removed and Merging
Michael Howden (michael-howden) : | # |
- 2403. By Pratyush Nigam
-
Implemented the suggested changes
- 2404. By Pratyush Nigam
-
Merging
- 2405. By Pratyush Nigam
-
Playing with crud string
- 2406. By Pratyush Nigam
-
Made changes to rectify the errors in search criteria
- 2407. By Pratyush Nigam
-
Merging
- 2408. By Pratyush Nigam
-
Made changes to format email
---------- This line and the following will be ignored --------------modified:
controllers/msg.py
controllers/pr.py - 2409. By Pratyush Nigam
-
Merging
Preview Diff
1 | === modified file 'controllers/msg.py' |
2 | --- controllers/msg.py 2011-08-06 18:24:53 +0000 |
3 | +++ controllers/msg.py 2011-08-20 19:52:33 +0000 |
4 | @@ -850,6 +850,136 @@ |
5 | return items |
6 | |
7 | |
8 | +# ----------------------------------------------------------------------------- |
9 | +def subscription(): |
10 | + resourcename = "subscription" |
11 | + #form for the subscrption preferences of the user |
12 | + return s3_rest_controller(module, resourcename) |
13 | + |
14 | + |
15 | +# ----------------------------------------------------------------------------- |
16 | +def load_search(id): |
17 | + var = {} |
18 | + var["load"] = id |
19 | + s3mgr.load("pr_save_search") |
20 | + rows = db(db.pr_save_search.id == id).select(db.pr_save_search.ALL) |
21 | + import cPickle |
22 | + for row in rows: |
23 | + search_vars = cPickle.loads(row.search_vars) |
24 | + prefix = str(search_vars["prefix"]) |
25 | + function = str(search_vars["function"]) |
26 | + date = str(row.modified_on) |
27 | + break |
28 | + field = "%s.modified_on__gt" %(function) |
29 | + date = date.replace(" ","T") |
30 | + date = date + "Z" |
31 | + var[field] = date |
32 | + #var["transform"] = "eden/static/formats/xml/import.xsl" |
33 | + r = current.manager.parse_request(prefix, |
34 | + function, |
35 | + args=["search"], |
36 | + #extension="xml", |
37 | + get_vars=Storage(var) |
38 | + ) |
39 | + #redirect(URL(r=request, c=prefix, f=function, args=["search"],vars=var)) |
40 | + response.s3.no_sspag=True |
41 | + output = r() |
42 | + #extract the updates |
43 | + return output |
44 | + |
45 | + |
46 | +# ----------------------------------------------------------------------------- |
47 | +def get_criteria(id): |
48 | + s = "" |
49 | + try: |
50 | + id = id.replace("'","'") |
51 | + search_vars = cPickle.loads(id) |
52 | + s = "<p>" |
53 | + pat = '_' |
54 | + for var in search_vars.iterkeys(): |
55 | + if var == "criteria" : |
56 | + c_dict = search_vars[var] |
57 | + #s = s + crud_string("pr_save_search", "Search Criteria") |
58 | + for j in c_dict.iterkeys(): |
59 | + if not re.match(pat,j): |
60 | + st = str(j) |
61 | + st = st.replace("_search_"," ") |
62 | + st = st.replace("_advanced","") |
63 | + st = st.replace("_simple","") |
64 | + st = st.replace("text","text matching") |
65 | + """st = st.replace(search_vars["function"],"") |
66 | + st = st.replace(search_vars["prefix"],"")""" |
67 | + st = st.replace("_"," ") |
68 | + s = "%s <b> %s </b>: %s <br />" %(s, st.capitalize(), str(c_dict[j])) |
69 | + elif var == "simple" or var == "advanced": |
70 | + continue |
71 | + else: |
72 | + if var == "function": |
73 | + v1 = "Resource Name" |
74 | + elif var == "prefix": |
75 | + v1 = "Module" |
76 | + s = "%s<b>%s</b>: %s<br />" %(s, v1, str(search_vars[var])) |
77 | + s = s + "</p>" |
78 | + return s |
79 | + except: |
80 | + return s |
81 | + |
82 | + |
83 | +# ----------------------------------------------------------------------------- |
84 | +def check_updates(user_id): |
85 | + #Check Updates for all the Saved Searches Subscribed by the User |
86 | + message = "<h2>Saved Searches' Update</h2>" |
87 | + flag = 0 |
88 | + s3mgr.load("pr_save_search") |
89 | + rows = db(db.pr_save_search.user_id == user_id).select(db.pr_save_search.ALL) |
90 | + for row in rows : |
91 | + if row.subscribed: |
92 | + records = load_search(row.id) |
93 | + #message = message + "<b>" + get_criteria(row.id) + "</b>" |
94 | + if str(records["items"]) != "No Matching Records": |
95 | + message = message + str(records["items"]) + "<br />" #Include the Saved Search details |
96 | + flag = 1 |
97 | + db.pr_save_search[row.id] = dict(modified_on = request.utcnow) |
98 | + if flag == 0: |
99 | + return |
100 | + else: |
101 | + return XML(message) |
102 | + |
103 | + |
104 | +# ----------------------------------------------------------------------------- |
105 | +def subscription_messages(): |
106 | + |
107 | + subs = None |
108 | + if request.args[0] == "daily": |
109 | + subs = db(db.msg_subscription.subscription_frequency == "daily").select( |
110 | + db.msg_subscription.ALL) |
111 | + if request.args[0] == "weekly": |
112 | + subs = db(db.msg_subscription.subscription_frequency=="weekly").select( |
113 | + db.msg_subscription.ALL) |
114 | + if request.args[0] == "monthly": |
115 | + subs = db(db.msg_subscription.subscription_frequency=="monthly").select( |
116 | + db.msg_subscription.ALL) |
117 | + if subs: |
118 | + for sub in subs: |
119 | + #check if the message is not empty |
120 | + message = check_updates(sub.user_id) |
121 | + if message == None: |
122 | + return |
123 | + person_id = auth.s3_user_to_person(sub.user_id) |
124 | + rows = db(db.pr_person.id == person_id).select(db.pr_person.ALL) |
125 | + for row in rows: |
126 | + pe_id = row.pe_id |
127 | + break |
128 | + msg.send_by_pe_id(pe_id, |
129 | + subject="Subscription Updates", |
130 | + message=message, |
131 | + sender_pe_id = None, |
132 | + pr_message_method = "EMAIL", |
133 | + sender="noreply@sahana.com", |
134 | + fromaddress="sahana@sahana.com") |
135 | + return |
136 | + |
137 | + |
138 | # ============================================================================= |
139 | # Enabled only for testing: |
140 | # |
141 | @@ -870,5 +1000,4 @@ |
142 | return s3_rest_controller(module, resourcename) |
143 | |
144 | |
145 | -# END ========================================================================= |
146 | - |
147 | +# END ================================================================================ |
148 | |
149 | === modified file 'controllers/pr.py' |
150 | --- controllers/pr.py 2011-08-16 16:10:39 +0000 |
151 | +++ controllers/pr.py 2011-08-20 19:52:33 +0000 |
152 | @@ -4,6 +4,7 @@ |
153 | VITA Person Registry, Controllers |
154 | |
155 | @author: nursix |
156 | + @author: Pratyush Nigam <pratyush.nigam@gmail.com> |
157 | @see: U{http://eden.sahanafoundation.org/wiki/BluePrintVITA} |
158 | """ |
159 | |
160 | @@ -108,6 +109,8 @@ |
161 | |
162 | # Load Model |
163 | s3mgr.load("pr_address") |
164 | + s3mgr.load("pr_save_search") |
165 | + s3mgr.load("msg_subscription") |
166 | |
167 | # Handle Personalised Map Configs |
168 | gis_config_form_setup() |
169 | @@ -146,8 +149,67 @@ |
170 | r.table.volunteer.writable = True |
171 | |
172 | return True |
173 | - |
174 | + |
175 | + def postp(r, output): |
176 | + if r.component_name == "save_search": |
177 | + # Handle Subscribe/Unsubscribe requests |
178 | + if "subscribe" in r.get_vars: |
179 | + save_search_id = r.get_vars.get("subscribe", None) |
180 | + db.pr_save_search[save_search_id] = dict(subscribed = True) |
181 | + if "unsubscribe" in r.get_vars: |
182 | + save_search_id = r.get_vars.get("unsubscribe", None) |
183 | + db.pr_save_search[save_search_id] = dict(subscribed = False) |
184 | + |
185 | + s3_action_buttons(r) |
186 | + rows = db(db.pr_save_search.subscribed == False).select( |
187 | + db.pr_save_search.id) |
188 | + restrict_s = [str(row.id) for row in rows] |
189 | + rows = db(db.pr_save_search.subscribed == True).select( |
190 | + db.pr_save_search.id) |
191 | + restrict_u = [str(row.id) for row in rows] |
192 | + response.s3.actions = \ |
193 | + response.s3.actions + [ |
194 | + dict(label=str(T("Load Search")), _class="action-btn", |
195 | + url=str(URL(r=request, |
196 | + f="load_search", |
197 | + args=["[id]"] |
198 | + ), |
199 | + ) |
200 | + ) |
201 | + ] |
202 | + vars = {} |
203 | + #vars["person.uid"] = r.uid |
204 | + vars["subscribe"] = "[id]" |
205 | + response.s3.actions.append( |
206 | + dict(label=str(T("Subscribe")), _class="action-btn", |
207 | + url = str( URL(r = request, |
208 | + f = "person", |
209 | + args = [s3_logged_in_person(), |
210 | + "save_search" |
211 | + ], |
212 | + vars = vars)), |
213 | + restrict = restrict_s |
214 | + ) |
215 | + ) |
216 | + var = {} |
217 | + #var["person.uid"] = r.uid |
218 | + var["unsubscribe"] = "[id]" |
219 | + response.s3.actions.append( |
220 | + dict(label=str(T("Unsubscribe")), _class="action-btn", |
221 | + url = str( URL(r = request, |
222 | + f = "person", |
223 | + args = [s3_logged_in_person(), |
224 | + "save_search", |
225 | + ], |
226 | + vars = var)), |
227 | + restrict = restrict_u |
228 | + ) |
229 | + ) |
230 | + |
231 | + return output |
232 | + |
233 | response.s3.prep = prep |
234 | + response.s3.postp = postp |
235 | |
236 | s3mgr.configure("pr_group_membership", |
237 | list_fields=["id", |
238 | @@ -179,10 +241,10 @@ |
239 | s3mgr.model.add_component("hrm_training", |
240 | pr_person="person_id") |
241 | tabs.append((T("Training"), "training")) |
242 | - |
243 | # Configuration tabs |
244 | tabs = tabs + [(T("Subscriptions"), "pe_subscription"), |
245 | (T("Saved Searches"), "save_search"), |
246 | + (T("Subscription Details"), "subscription"), |
247 | (T("Map Settings"), "config")] |
248 | |
249 | s3mgr.configure("pr_person", listadd=False, insertable=True) |
250 | @@ -539,67 +601,6 @@ |
251 | form2 = SQLFORM(persons, record, _id="form2", _action=("%s/%s" % (myUrl, perID2))) |
252 | return dict(form1=form1, form2=form2, perID1=perID1, perID2=perID2) |
253 | |
254 | -#------------------------------------------------------------------------------ |
255 | -#UI for Saved Searches |
256 | -# |
257 | -def save_search(): |
258 | - |
259 | - if not auth.is_logged_in(): |
260 | - redirect(URL(f="index") ) |
261 | - else : |
262 | - module = "pr" |
263 | - resourcename = "save_search" |
264 | - tablename = "%s_%s" % (module, resourcename) |
265 | - s3mgr.load(tablename) |
266 | - table = db[tablename] |
267 | - |
268 | - if "subscribe" in request.args: |
269 | - rows = db(db.pr_save_search.id == request.args[0]).select( |
270 | - db.pr_save_search.ALL) |
271 | - for row in rows: |
272 | - #process subscribe/un-subscribe action |
273 | - if str(row.id) in request.args: |
274 | - if row.subscribed: |
275 | - db.pr_save_search[row.id] = dict(subscribed = False) |
276 | - else: |
277 | - db.pr_save_search[row.id] = dict(subscribed = True) |
278 | - redirect(URL(f="save_search")) |
279 | - |
280 | - def prep(r): |
281 | - if r.interactive : |
282 | - s3mgr.configure(tablename, |
283 | - insertable = False, |
284 | - editable = False, |
285 | - listadd = False, |
286 | - deletable = True, |
287 | - list_fields=["search_vars","subscribed"]) |
288 | - return True |
289 | - |
290 | - def postp(r, output): |
291 | - s3_action_buttons(r) |
292 | - values = [dict(col=2, key="True", display=str(T("Yes"))), |
293 | - dict(col=2, key="False", display=str(T("No"))) |
294 | - ] |
295 | - response.s3.dataTableDisplay = values |
296 | - response.s3.actions = \ |
297 | - response.s3.actions + [ |
298 | - dict(label=str(T("Load Search")), _class="action-btn", |
299 | - url=URL(f="load_search", |
300 | - args=["[id]"]) |
301 | - ) |
302 | - ] |
303 | - response.s3.actions.append( |
304 | - dict(label=str(T("Subscribe/Unsubscribe")), _class="action-btn", |
305 | - url = str( URL(f="save_search", |
306 | - args = ["[id]", "subscribe"])) |
307 | - ) |
308 | - ) |
309 | - return output |
310 | - |
311 | - response.s3.prep = prep |
312 | - response.s3.postp = postp |
313 | - return s3_rest_controller(module, resourcename) |
314 | - |
315 | |
316 | #------------------------------------------------------------------------------ |
317 | #Function to redirect for loading the search |
318 | @@ -607,17 +608,16 @@ |
319 | def load_search(): |
320 | var = {} |
321 | var["load"] = request.args[0] |
322 | - rows = db(db.pr_save_search.id == request.args[0]).select( |
323 | - db.pr_save_search.ALL) |
324 | + s3mgr.load("pr_save_search") |
325 | + rows = db(db.pr_save_search.id == request.args[0]).select(db.pr_save_search.ALL) |
326 | + import cPickle |
327 | for row in rows: |
328 | search_vars = cPickle.loads(row.search_vars) |
329 | prefix = str(search_vars["prefix"]) |
330 | function = str(search_vars["function"]) |
331 | break |
332 | - redirect(URL(prefix,function, args=["search"], |
333 | - vars=var)) |
334 | + redirect(URL(r=request, c=prefix, f=function, args=["search"],vars=var)) |
335 | return |
336 | |
337 | |
338 | -# END ========================================================================= |
339 | - |
340 | +# END ========================================================================= |
341 | \ No newline at end of file |
342 | |
343 | === modified file 'deployment-templates/cron/crontab' |
344 | --- deployment-templates/cron/crontab 2011-07-08 22:55:36 +0000 |
345 | +++ deployment-templates/cron/crontab 2011-08-20 19:52:33 +0000 |
346 | @@ -28,3 +28,10 @@ |
347 | # Poll RMS Feeds (Haiti-specific) |
348 | #*/5 * * * * web2py *applications/eden/cron/rms_sms2record.py |
349 | #*/5 * * * * web2py *applications/eden/cron/rms_tweet2request.py |
350 | +# Send Subscription Messages |
351 | +# Daily |
352 | +# 0 0 * * * web2py *msg/subscription_updates/daily |
353 | +# Weekly |
354 | +# 0 0 * * 1 web2py *msg/subscription_updates/weekly |
355 | +# Monthly |
356 | +# 0 0 1 * * web2py *msg/subscription_updates/monthly |
357 | |
358 | === modified file 'deployment-templates/models/000_config.py' |
359 | --- deployment-templates/models/000_config.py 2011-08-19 04:23:49 +0000 |
360 | +++ deployment-templates/models/000_config.py 2011-08-20 19:52:33 +0000 |
361 | @@ -402,6 +402,9 @@ |
362 | # Human Resource Management |
363 | #deployment_settings.hrm.email_required = False |
364 | |
365 | +# Save Search Widget |
366 | +deployment_settings.save_search.widget = True |
367 | + |
368 | # Terms of Service to be able to Register on the system |
369 | #deployment_settings.options.terms_of_service = T("Terms of Service\n\nYou have to be eighteen or over to register as a volunteer.") |
370 | # Should we use internal Support Requests? |
371 | |
372 | === modified file 'models/04_pr.py' |
373 | --- models/04_pr.py 2011-08-14 13:15:49 +0000 |
374 | +++ models/04_pr.py 2011-08-20 19:52:33 +0000 |
375 | @@ -4,6 +4,7 @@ |
376 | Person Registry |
377 | |
378 | @author: nursix |
379 | + @author: Pratyush Nigam <pratyush.nigam@gmail.com> |
380 | @see: U{http://eden.sahanafoundation.org/wiki/BluePrintVITA} |
381 | |
382 | """ |
383 | @@ -853,78 +854,84 @@ |
384 | # ============================================================================= |
385 | # Saved Searches |
386 | # |
387 | -# @ToDo: Conditional Model Load |
388 | -tablename = "pr_save_search" |
389 | -table = db.define_table(tablename, |
390 | - Field("user_id", "integer", |
391 | - default = auth.user_id), |
392 | - Field("search_vars", "string", |
393 | - label = T("Search Criteria")), |
394 | - Field("subscribed", "boolean", |
395 | - default=False), |
396 | - person_id(), |
397 | - *s3_timestamp()) |
398 | -table.person_id.default = s3_logged_in_person() |
399 | -table.user_id.readable = False |
400 | -table.user_id.writable = False |
401 | - |
402 | -# @ToDo: If this can't be moved inside the conditional model load, then |
403 | -# move to 00_db.py with the other imports |
404 | -import cPickle |
405 | - |
406 | -def get_criteria(id): |
407 | - s = "" |
408 | - try: |
409 | - id = id.replace("'", "'") |
410 | - search_vars = cPickle.loads(id) |
411 | - s = "<p>" |
412 | - pat = '_' |
413 | - for var in search_vars.iterkeys(): |
414 | - if var == "criteria" : |
415 | - c_dict = search_vars[var] |
416 | - for j in c_dict.iterkeys(): |
417 | - if not re.match(pat,j): |
418 | - s = "%s<b>%s</b>: %s<br />" % (s, |
419 | - str(j).capitalize(), |
420 | - str(c_dict[j])) |
421 | - elif var == "simple" or var == "advanced": |
422 | - continue |
423 | - else: |
424 | - s = "%s<b>%s</b>: %s<br />" % (s, |
425 | - str(var).capitalize(), |
426 | - str(search_vars[var])) |
427 | - s = "%s</p>" % s |
428 | - return XML(s) |
429 | - except: |
430 | - return XML(s) |
431 | - |
432 | -table.search_vars.represent = lambda id: get_criteria(id = id) |
433 | - |
434 | -s3mgr.configure(tablename, |
435 | - insertable = False, |
436 | - editable = False, |
437 | - listadd = False, |
438 | - deletable = True, |
439 | - list_fields=["search_vars", |
440 | - "subscribed"]) |
441 | - |
442 | -s3mgr.model.add_component(tablename, pr_person="person_id") |
443 | - |
444 | -s3.crud_strings[tablename] = Storage( |
445 | - title_create = T("Save Search"), |
446 | - title_display = T("Saved Search Details"), |
447 | - title_list = T("Saved Searches"), |
448 | - title_update = T("Edit Saved Search"), |
449 | - title_search = T("Search Saved Searches"), |
450 | - subtitle_create = T("Add Saved Search"), |
451 | - subtitle_list = T("Saved Searches"), |
452 | - label_list_button = T("List Saved Searches"), |
453 | - label_create_button = T("Save Search"), |
454 | - label_delete_button = T("Delete Saved Search"), |
455 | - msg_record_created = T("Saved Search added"), |
456 | - msg_record_modified = T("Saved Search updated"), |
457 | - msg_record_deleted = T("Saved Search deleted"), |
458 | - msg_list_empty = T("No Search saved")) |
459 | +def saved_search_tables(): |
460 | + tablename = "pr_save_search" |
461 | + table = db.define_table(tablename, |
462 | + Field("user_id","integer", default = auth.user_id), |
463 | + Field("search_vars","string", label = T("Search Criteria")), |
464 | + Field("subscribed","boolean", default=False), |
465 | + person_id(label = T("Person")), |
466 | + migrate=migrate, *s3_timestamp()) |
467 | + db.pr_save_search.person_id.default = s3_logged_in_person() |
468 | + db.pr_save_search.user_id.readable = False |
469 | + db.pr_save_search.user_id.writable = False |
470 | + |
471 | + import cPickle |
472 | + def get_criteria(id): |
473 | + s = "" |
474 | + try: |
475 | + id = id.replace("'","'") |
476 | + search_vars = cPickle.loads(id) |
477 | + s = "<p>" |
478 | + pat = '_' |
479 | + for var in search_vars.iterkeys(): |
480 | + if var == "criteria" : |
481 | + c_dict = search_vars[var] |
482 | + #s = s + crud_string("pr_save_search", "Search Criteria") |
483 | + for j in c_dict.iterkeys(): |
484 | + if not re.match(pat,j): |
485 | + st = str(j) |
486 | + st = st.replace("_search_"," ") |
487 | + st = st.replace("_advanced","") |
488 | + st = st.replace("_simple","") |
489 | + st = st.replace("text","text matching") |
490 | + """st = st.replace(search_vars["function"],"") |
491 | + st = st.replace(search_vars["prefix"],"")""" |
492 | + st = st.replace("_"," ") |
493 | + s = "%s <b> %s </b>: %s <br />" %(s, st.capitalize(), str(c_dict[j])) |
494 | + elif var == "simple" or var == "advanced": |
495 | + continue |
496 | + else: |
497 | + if var == "function": |
498 | + v1 = "Resource Name" |
499 | + elif var == "prefix": |
500 | + v1 = "Module" |
501 | + s = "%s<b>%s</b>: %s<br />" %(s, v1, str(search_vars[var])) |
502 | + s = s + "</p>" |
503 | + return XML(s) |
504 | + except: |
505 | + return XML(s) |
506 | + |
507 | + db.pr_save_search.search_vars.represent = lambda id : get_criteria(id = id) |
508 | + |
509 | + s3mgr.configure(tablename, |
510 | + insertable = False, |
511 | + editable = False, |
512 | + listadd = False, |
513 | + deletable = True, |
514 | + list_fields=["search_vars"]) |
515 | + |
516 | + s3mgr.model.add_component(table, pr_person="person_id") |
517 | + |
518 | + s3.crud_strings[tablename] = Storage( |
519 | + title_create = T("Save Search"), |
520 | + title_display = T("Saved Search Details"), |
521 | + title_list = T("Saved Searches"), |
522 | + title_update = T("Edit Saved Search"), |
523 | + title_search = T("Search Saved Searches"), |
524 | + subtitle_create = T("Add Saved Search"), |
525 | + subtitle_list = T("Saved Searches"), |
526 | + label_list_button = T("List Saved Searches"), |
527 | + label_create_button = T("Save Search"), |
528 | + label_delete_button = T("Delete Saved Search"), |
529 | + msg_record_created = T("Saved Search added"), |
530 | + msg_record_modified = T("Saved Search updated"), |
531 | + msg_record_deleted = T("Saved Search deleted"), |
532 | + msg_list_empty = T("No Search saved")) |
533 | + |
534 | +# Provide a handle to this load function |
535 | +s3mgr.model.loader(saved_search_tables, |
536 | + "pr_save_search") |
537 | |
538 | |
539 | # ============================================================================= |
540 | |
541 | === modified file 'models/msg.py' (properties changed: -x to +x) |
542 | --- models/msg.py 2011-08-06 18:24:53 +0000 |
543 | +++ models/msg.py 2011-08-20 19:52:33 +0000 |
544 | @@ -40,7 +40,7 @@ |
545 | represent = lambda direction: \ |
546 | (direction and ["In"] or ["Out"])[0], |
547 | label = T("Direction")), |
548 | - |
549 | + migrate=migrate, |
550 | *(s3_timestamp() + s3_uid() + s3_deletion_status())) |
551 | |
552 | s3mgr.configure(tablename, |
553 | @@ -77,7 +77,7 @@ |
554 | Field("record_uuid", # null in this field implies subscription to the entire resource |
555 | type=s3uuid, |
556 | length=128), |
557 | - |
558 | + migrate=migrate, |
559 | *(s3_timestamp() + s3_uid() + s3_deletion_status())) |
560 | |
561 | s3mgr.configure(tablename, |
562 | @@ -105,7 +105,7 @@ |
563 | # - as easy for admin to edit source in 000_config.py as to edit DB (although an admin panel can be nice) |
564 | #Field("outbound_mail_server"), |
565 | #Field("outbound_mail_from"), |
566 | - *s3_timestamp()) |
567 | + migrate=migrate, *s3_timestamp()) |
568 | |
569 | # --------------------------------------------------------------------- |
570 | # SMS |
571 | @@ -118,7 +118,7 @@ |
572 | zero=None)), |
573 | # Moved to deployment_settings |
574 | #Field("default_country_code", "integer", default=44), |
575 | - *s3_timestamp()) |
576 | + migrate=migrate, *s3_timestamp()) |
577 | |
578 | # --------------------------------------------------------------------- |
579 | tablename = "msg_modem_settings" |
580 | @@ -128,7 +128,7 @@ |
581 | Field("modem_baud", "integer", default = 115200), |
582 | Field("enabled", "boolean", default = True), |
583 | #Field("preference", "integer", default = 5), To be used later |
584 | - *s3_timestamp()) |
585 | + migrate=migrate, *s3_timestamp()) |
586 | |
587 | # --------------------------------------------------------------------- |
588 | tablename = "msg_api_settings" |
589 | @@ -141,7 +141,7 @@ |
590 | Field("to_variable", "string", default = "to"), |
591 | Field("enabled", "boolean", default = True), |
592 | #Field("preference", "integer", default = 5), To be used later |
593 | - *s3_timestamp()) |
594 | + migrate=migrate, *s3_timestamp()) |
595 | |
596 | # --------------------------------------------------------------------- |
597 | tablename = "msg_smtp_to_sms_settings" |
598 | @@ -151,14 +151,14 @@ |
599 | Field("subject", length=64), |
600 | Field("enabled", "boolean", default = True), |
601 | #Field("preference", "integer", default = 5), To be used later |
602 | - *s3_timestamp()) |
603 | + migrate=migrate, *s3_timestamp()) |
604 | |
605 | # --------------------------------------------------------------------- |
606 | tablename = "msg_tropo_settings" |
607 | table = db.define_table(tablename, |
608 | Field("token_messaging"), |
609 | #Field("token_voice"), |
610 | - *s3_timestamp()) |
611 | + migrate=migrate, *s3_timestamp()) |
612 | |
613 | # --------------------------------------------------------------------- |
614 | # Outbound Messages |
615 | @@ -200,7 +200,7 @@ |
616 | opt_msg_status, |
617 | Field("system_generated", "boolean", default = False), |
618 | Field("log"), |
619 | - |
620 | + migrate=migrate, |
621 | *(s3_timestamp() + s3_uid() + s3_deletion_status())) |
622 | |
623 | s3mgr.model.add_component(table, msg_log="message_id") |
624 | @@ -222,7 +222,7 @@ |
625 | Field("recipient"), |
626 | Field("message"), |
627 | Field("network"), |
628 | - ) |
629 | + migrate=migrate) |
630 | |
631 | # --------------------------------------------------------------------- |
632 | # Inbound Messages |
633 | @@ -237,7 +237,7 @@ |
634 | zero=None), |
635 | default = "EMAIL"), |
636 | Field("log"), |
637 | - |
638 | + migrate=migrate, |
639 | *(s3_timestamp() + s3_uid() + s3_deletion_status())) |
640 | |
641 | # --------------------------------------------------------------------- |
642 | @@ -245,7 +245,7 @@ |
643 | tablename = "msg_email_inbound_status" |
644 | table = db.define_table(tablename, |
645 | Field("status"), |
646 | - ) |
647 | + migrate=migrate) |
648 | |
649 | # --------------------------------------------------------------------- |
650 | # SMS store for persistence and scratch pad for combining incoming xform chunks |
651 | @@ -256,7 +256,7 @@ |
652 | Field("totalno", "integer"), |
653 | Field("partno", "integer"), |
654 | Field("message", "string", length = 160), |
655 | - ) |
656 | + migrate=migrate) |
657 | |
658 | # ===================================================================== |
659 | def msg_compose( redirect_module = "msg", |
660 | @@ -278,8 +278,8 @@ |
661 | if auth.is_logged_in() or auth.basic(): |
662 | pass |
663 | else: |
664 | - redirect(URL(c="default", f="user", args="login", |
665 | - vars={"_next":URL(redirect_module,redirect_function, vars=redirect_vars)})) |
666 | + redirect(URL(r=request, c="default", f="user", args="login", |
667 | + vars={"_next":URL(r=request, c=redirect_module, f=redirect_function, vars=redirect_vars)})) |
668 | |
669 | # Model options |
670 | table1.sender.writable = table1.sender.readable = False |
671 | @@ -305,7 +305,7 @@ |
672 | """ Set the sender and use msg.send_by_pe_id to route the message """ |
673 | if not request.vars.pe_id: |
674 | session.error = T("Please enter the recipient") |
675 | - redirect(URL(redirect_module,redirect_function, |
676 | + redirect(URL(r=request, c=redirect_module, f=redirect_function, |
677 | vars=redirect_vars)) |
678 | table = db.pr_person |
679 | query = (table.uuid == auth.user.person_uuid) |
680 | @@ -319,11 +319,11 @@ |
681 | # Trigger a Process Outbox |
682 | msg.process_outbox(contact_method = request.vars.pr_message_method) |
683 | session.flash = T("Check outbox for the message status") |
684 | - redirect(URL(redirect_module,redirect_function, |
685 | + redirect(URL(r=request, c=redirect_module, f=redirect_function, |
686 | vars=redirect_vars)) |
687 | else: |
688 | session.error = T("Error in message") |
689 | - redirect(URL(redirect_module,redirect_function, |
690 | + redirect(URL(r=request, c=redirect_module, f=redirect_function, |
691 | vars=redirect_vars)) |
692 | |
693 | logform = crud.create(table1, |
694 | @@ -345,7 +345,7 @@ |
695 | Field("oauth_secret", |
696 | readable = False, writable = False), |
697 | Field("twitter_account", writable = False), |
698 | - *s3_timestamp()) |
699 | + migrate=migrate, *s3_timestamp()) |
700 | |
701 | def twitter_settings_onvalidation(form): |
702 | """ Complete oauth: take tokens from session + pin from form, and do the 2nd API call to Twitter """ |
703 | @@ -382,7 +382,7 @@ |
704 | tablename = "msg_twitter_search" |
705 | table = db.define_table(tablename, |
706 | Field("search_query", length = 140), |
707 | - ) |
708 | + migrate = migrate) |
709 | # --------------------------------------------------------------------- |
710 | resourcename = "twitter_search_results" |
711 | tablename = "msg_twitter_search_results" |
712 | @@ -391,7 +391,7 @@ |
713 | Field("posted_by"), |
714 | Field("posted_at"), |
715 | Field("twitter_search", db.msg_twitter_search), |
716 | - ) |
717 | + migrate = migrate) |
718 | #table.twitter_search.requires = IS_ONE_OF(db, "twitter_search.search_query") |
719 | #table.twitter_search.represent = lambda id: db(db.msg_twitter_search.id == id).select(db.msg_twitter_search.search_query, limitby = (0,1)).first().search_query |
720 | |
721 | @@ -404,7 +404,7 @@ |
722 | "posted_at", |
723 | "twitter_search", |
724 | ]) |
725 | - |
726 | + |
727 | # --------------------------------------------------------------------- |
728 | # Pass variables back to global scope (response.s3.*) |
729 | return dict(msg_compose=msg_compose, |
730 | @@ -422,6 +422,43 @@ |
731 | "msg_tag", |
732 | "msg_channel", |
733 | "msg_outbox") |
734 | + |
735 | + # --------------------------------------------------------------------- |
736 | + msg_subscription_mode_opts = { |
737 | + 1:T("Email"), |
738 | + #2:T("SMS"), |
739 | + #3:T("Email and SMS") |
740 | + } |
741 | + """msg_subscription_frequency_opts = { |
742 | + 1:T("Email"), |
743 | + 2:T("SMS"), |
744 | + 3:T("Email and SMS") |
745 | + }""" |
746 | + tablename = "msg_subscription" |
747 | + table = db.define_table(tablename, |
748 | + Field("user_id","integer", |
749 | + default = auth.user_id, |
750 | + ), |
751 | + Field("subscribe_mode","integer", |
752 | + default = 1, |
753 | + readable = False, |
754 | + requires = IS_IN_SET(msg_subscription_mode_opts, |
755 | + zero=None) |
756 | + ), |
757 | + Field("subscription_frequency", |
758 | + requires = IS_IN_SET(["daily","weekly","monthly"]), |
759 | + default = "daily", |
760 | + ), |
761 | + person_id(label = T("Person")), |
762 | + migrate=migrate, *s3_timestamp()) |
763 | + db.msg_subscription.person_id.default = s3_logged_in_person() |
764 | + db.msg_subscription.user_id.writable = False |
765 | + db.msg_subscription.user_id.readable = False |
766 | + db.msg_subscription.user_id.requires = IS_NOT_IN_DB(db, 'msg_subscription.user_id') |
767 | + s3mgr.configure("msg_subscription", |
768 | + list_fields=["subscribe_mode", |
769 | + "subscription_frequency"]) |
770 | + s3mgr.model.add_component("msg_subscription", pr_person="person_id") |
771 | |
772 | # ========================================================================= |
773 | # CAP: Common Alerting Protocol |
774 | @@ -488,7 +525,7 @@ |
775 | location_id(), |
776 | Field("image", "upload", autodelete = True), |
777 | Field("url", requires=IS_NULL_OR(IS_URL())), |
778 | - |
779 | + migrate=migrate, |
780 | *(s3_timestamp() + s3_uid() + s3_deletion_status())) |
781 | # Pass variables back to global scope (response.s3.*) |
782 | return dict() |
783 | @@ -498,4 +535,3 @@ |
784 | "msg_report") |
785 | |
786 | # END ========================================================================= |
787 | - |
788 | |
789 | === modified file 'models/zz_last.py' |
790 | --- models/zz_last.py 2011-08-10 07:39:32 +0000 |
791 | +++ models/zz_last.py 2011-08-20 19:52:33 +0000 |
792 | @@ -5,6 +5,7 @@ |
793 | # Pass Tasks to Scheduler instance |
794 | # http://www.vimeo.com/27478796 |
795 | # NB Avoid passing state into the async call as state may change before the message is executed (race condition) |
796 | +import sys |
797 | try: |
798 | from gluon.scheduler import Scheduler |
799 | except: |
800 | |
801 | === modified file 'modules/s3/s3aaa.py' |
802 | --- modules/s3/s3aaa.py 2011-08-17 23:44:42 +0000 |
803 | +++ modules/s3/s3aaa.py 2011-08-20 19:52:33 +0000 |
804 | @@ -1636,7 +1636,7 @@ |
805 | utable = db.pr_person |
806 | ptable = self.settings.table_user |
807 | query = (utable.id == user_id) & \ |
808 | - (utable.person_uuid == ptable.uuid) |
809 | + (ptable.person_uuid == utable.uuid) |
810 | record = db(query).select(ptable.id, |
811 | limitby=(0, 1)).first() |
812 | if record: |
813 | |
814 | === modified file 'modules/s3/s3cfg.py' |
815 | --- modules/s3/s3cfg.py 2011-08-18 18:20:37 +0000 |
816 | +++ modules/s3/s3cfg.py 2011-08-20 19:52:33 +0000 |
817 | @@ -63,9 +63,10 @@ |
818 | self.req = Storage() |
819 | self.inv = Storage() |
820 | self.hrm = Storage() |
821 | - |
822 | + self.save_search = Storage() |
823 | + |
824 | T = current.T |
825 | - |
826 | + |
827 | # These are copied from modules/s3/s3aaa.py |
828 | self.aaa.acl = Storage(CREATE = 0x0001, |
829 | READ = 0x0002, |
830 | @@ -446,6 +447,10 @@ |
831 | def get_hrm_email_required(self): |
832 | return self.hrm.get("email_required", True) |
833 | |
834 | + # Save Search and Subscription |
835 | + def get_save_search_widget(self): |
836 | + return self.save_search.get("widget", True) |
837 | + |
838 | # ----------------------------------------------------------------------------- |
839 | # Active modules list |
840 | def has_module(self, module_name): |
841 | |
842 | === modified file 'modules/s3/s3search.py' |
843 | --- modules/s3/s3search.py 2011-08-08 19:47:35 +0000 |
844 | +++ modules/s3/s3search.py 2011-08-20 19:52:33 +0000 |
845 | @@ -5,6 +5,7 @@ |
846 | |
847 | @author: Fran Boon <fran[at]aidiq.com> |
848 | @author: Dominic König <dominic[at]aidiq.com> |
849 | + @author: Pratyush Nigam <pratyush.nigam@gmail.com> |
850 | |
851 | @requires: U{B{I{gluon}} <http://web2py.com>} |
852 | |
853 | @@ -36,6 +37,7 @@ |
854 | import re |
855 | import sys |
856 | import gluon.contrib.simplejson as jsonlib |
857 | +import cPickle |
858 | |
859 | try: |
860 | import cPickle |
861 | @@ -1068,6 +1070,100 @@ |
862 | query = query & q |
863 | return (query, errors) |
864 | # ------------------------------------------------------------------------- |
865 | + def save_search_widget(self, r, search_vars, **attr): |
866 | + request = self.request |
867 | + user_id = current.session.auth.user.id |
868 | + save_search_btn_id = "save_my_filter_btn_%s" % str(request.utcnow.microsecond) |
869 | + save_search_processing_id = "save_search_processing_%s" % str(request.utcnow.microsecond) |
870 | + save_search_a_id = "save_search_a_%s" % str(request.utcnow.microsecond) |
871 | + arg = str(user_id) + "/save_search" |
872 | + save_search_a = DIV("View and Subscribe to Saved Searches ", |
873 | + A("Here", |
874 | + _href = URL(r=request, c="pr", f="person", args=[arg]), |
875 | + _target = "_blank" |
876 | + ), |
877 | + ".", |
878 | + _id = save_search_a_id, |
879 | + _class = "save_search_a" |
880 | + ) |
881 | + search_vars["prefix"] = r.prefix |
882 | + search_vars["function"] = r.function |
883 | + s3mgr = self.manager |
884 | + s3mgr.load("pr_save_search") |
885 | + db = current.db |
886 | + if len (db(db.pr_save_search.user_id == user_id).select(db.pr_save_search.id, |
887 | + limitby = (0,1))): |
888 | + rows = db(db.pr_save_search.user_id == user_id).select(db.pr_save_search.ALL) |
889 | + for row in rows: |
890 | + pat = '_' |
891 | + s_v = cPickle.loads(row.search_vars) |
892 | + if ((search_vars["prefix"] == s_v["prefix"]) and \ |
893 | + (search_vars["function"] == s_v["function"])): |
894 | + s_dict = s_v["criteria"] |
895 | + if "criteria" in search_vars: |
896 | + c_dict = search_vars["criteria"] |
897 | + else: |
898 | + break |
899 | + diff = [ k for k in c_dict if k not in s_dict ] |
900 | + if not len(diff): |
901 | + flag = 1 |
902 | + for j in s_dict.iterkeys(): |
903 | + if not re.match(pat,j): |
904 | + if c_dict[j] != s_dict[j]: |
905 | + flag = 0 |
906 | + break |
907 | + if flag == 1: |
908 | + return DIV(save_search_a, |
909 | + _style = "font-size:12px; padding:5px 0px 5px 90px;", |
910 | + _id = "save_search" |
911 | + ) |
912 | + |
913 | + save_search_btn = A("Save Search", |
914 | + _class = "save_search_btn", |
915 | + _id = save_search_btn_id, |
916 | + _href = "#", |
917 | + _title = "Save this search") |
918 | + save_search_a["_style"] = "display:none;" |
919 | + save_search_processing = IMG(_src = "/" + request.application + "/static/img/ajax-loader.gif", |
920 | + _id = save_search_processing_id, |
921 | + _class = "save_search_processing_id", |
922 | + _style = "display:none;" |
923 | + ) |
924 | + s_var = {} |
925 | + s_var["save"] = True |
926 | + jurl = URL(r=request, c=r.prefix, f=r.function, args=["search"], vars = s_var) |
927 | + save_search_script = SCRIPT("".join(""" |
928 | + $("#%s").live( 'click', function () { |
929 | + $("#%s").show(); |
930 | + $("#%s").hide(); |
931 | + $.ajax({ |
932 | + url: '%s', |
933 | + data: '%s', |
934 | + success: function(data) { |
935 | + $("#%s").show(); |
936 | + $("#%s").hide(); |
937 | + }, |
938 | + type: 'POST' |
939 | + }); |
940 | + return false; |
941 | + }); |
942 | + """% |
943 | + (save_search_btn_id, |
944 | + save_search_processing_id, |
945 | + save_search_btn_id, |
946 | + jurl, |
947 | + jsonlib.dumps(search_vars), |
948 | + save_search_a_id, |
949 | + save_search_processing_id))) |
950 | + save_search = DIV(save_search_processing, |
951 | + save_search_a, |
952 | + save_search_btn, |
953 | + save_search_script, |
954 | + _style = "font-size:12px; padding:5px 0px 5px 90px;", |
955 | + _id = "save_search" |
956 | + ) |
957 | + return save_search |
958 | + # ------------------------------------------------------------------------- |
959 | def search_interactive(self, r, **attr): |
960 | """ |
961 | Interactive search |
962 | @@ -1084,9 +1180,11 @@ |
963 | db = current.db |
964 | table = self.table |
965 | tablename = self.tablename |
966 | + s3mgr = self.manager |
967 | + gis = s3mgr.gis |
968 | gis = current.gis |
969 | T = current.T |
970 | - |
971 | + |
972 | vars = request.get_vars |
973 | |
974 | # Get representation |
975 | @@ -1191,6 +1289,7 @@ |
976 | if not search_id: |
977 | r.error(400, self.manager.ERROR.BAD_RECORD) |
978 | r.post_vars = r.vars |
979 | + s3mgr.load("pr_save_search") |
980 | search_table = current.db.pr_save_search |
981 | record = current.db(search_table.id == search_id).select(limitby=(0,1)).first() |
982 | if not record: |
983 | @@ -1237,60 +1336,12 @@ |
984 | errors = simple and self.__simple and simple_form.errors or \ |
985 | self.__advanced and advanced_form.errors or \ |
986 | None |
987 | - |
988 | - #Append the Save Search Widget |
989 | - if r.http == "POST" and session.auth : |
990 | - save_search_btn_id = "save_my_filter_btn_%s" % str(request.utcnow.microsecond) |
991 | - save_search_processing_id = "save_search_processing_%s" % str(request.utcnow.microsecond) |
992 | - save_search_a_id = "save_search_a_%s" % str(request.utcnow.microsecond) |
993 | - save_search_a = DIV(T("View and Subscribe to Saved Searches "), |
994 | - A("Here", |
995 | - _href = URL(c='pr',f='save_search'), |
996 | - _target = "_blank" |
997 | - ), |
998 | - ".", |
999 | - _id = save_search_a_id, |
1000 | - _class = "save_search_a" |
1001 | - ) |
1002 | - save_search_btn = A("Save Search", |
1003 | - _class = "save_search_btn", |
1004 | - _id = save_search_btn_id, |
1005 | - _href = "#", |
1006 | - _title = T("Save this search")) |
1007 | - save_search_a["_style"] = "display:none;" |
1008 | - save_search_processing = IMG(_src = "/" + request.application + "/static/img/ajax-loader.gif", |
1009 | - _id = save_search_processing_id, |
1010 | - _class = "save_search_processing_id", |
1011 | - _style = "display:none;" |
1012 | - ) |
1013 | - search_vars["prefix"] = r.prefix |
1014 | - search_vars["function"] = r.function |
1015 | - s_var = {} |
1016 | - s_var["save"] = True |
1017 | - save_search_script = SCRIPT( """ |
1018 | - $("#""" + save_search_btn_id + """").live( 'click', function () { |
1019 | - $("#""" + save_search_processing_id+ """").show(); |
1020 | - $("#""" + save_search_btn_id + """").hide(); |
1021 | - $.ajax({ |
1022 | - url: '""" + URL(r.prefix,r.function,args=["search"], |
1023 | - vars = s_var) + """', |
1024 | - data: '""" + jsonlib.dumps(search_vars) + """', |
1025 | - success: function(data) { |
1026 | - $("#""" + save_search_a_id + """").show(); |
1027 | - $("#""" + save_search_processing_id+ """").hide(); |
1028 | - }, |
1029 | - type: 'POST' |
1030 | - }); |
1031 | - return false; |
1032 | - }); |
1033 | - """) |
1034 | - save_search = DIV(save_search_processing, |
1035 | - save_search_a, |
1036 | - save_search_btn, |
1037 | - save_search_script, |
1038 | - _style = "font-size:12px; padding:5px 0px 5px 90px;", |
1039 | - _id = "save_search" |
1040 | - ) |
1041 | + |
1042 | + settings = resource.manager.deployment_settings |
1043 | + |
1044 | + # Append the Save Search Widget |
1045 | + if r.http == "POST" and session.auth and settings.get_save_search_widget : |
1046 | + save_search = self.save_search_widget(r, search_vars, **attr) |
1047 | else: |
1048 | save_search = DIV() |
1049 | if self.__simple: |
1050 | @@ -1738,6 +1789,7 @@ |
1051 | # r contains the resource name: |
1052 | tablename = r.tablename |
1053 | component = r.component_name |
1054 | + s3mgr = self.manager |
1055 | db = current.db |
1056 | session = current.session |
1057 | auth = current.auth |
1058 | @@ -1756,14 +1808,14 @@ |
1059 | key = str(i) |
1060 | s_vars[key] = str(search_vars[i]) |
1061 | search_str = cPickle.dumps(s_vars) |
1062 | - table = db.pr_save_search |
1063 | - query = (table.user_id == user_id) & \ |
1064 | - (table.search_vars == search_str) |
1065 | - if len (db(query).select()) == 0: |
1066 | + s3mgr.load("pr_save_search") |
1067 | + if len (db( (db.pr_save_search.user_id == user_id) & \ |
1068 | + (db.pr_save_search.search_vars == search_str)).select()) == 0: |
1069 | new_search = {} |
1070 | new_search["search_vars"] = search_str |
1071 | - _id = table.insert(**new_search) |
1072 | - msg = "success" |
1073 | + search_table = db.pr_save_search |
1074 | + _id = search_table.insert(**new_search) |
1075 | + msg = "success" |
1076 | return msg |
1077 | |
1078 | |
1079 | @@ -2232,4 +2284,3 @@ |
1080 | return output |
1081 | |
1082 | # ============================================================================= |
1083 | - |