~dongpo-deng/sahana-eden/test

« back to all changes in this revision

Viewing changes to models/00_utils.py

  • Committer: Deng Dongpo
  • Date: 2010-08-01 09:29:44 UTC
  • Revision ID: dongpo@dhcp-21193.iis.sinica.edu.tw-20100801092944-8t9obt4xtl7otesb
initial

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
 
 
3
"""
 
4
    Utilities
 
5
"""
 
6
 
 
7
def shn_sessions():
 
8
    """
 
9
    Extend session to support:
 
10
        Multiple flash classes
 
11
        Settings
 
12
            Debug mode
 
13
            Security mode
 
14
            Restricted mode
 
15
            Theme
 
16
            Audit modes
 
17
    """
 
18
    response.error = session.error
 
19
    response.confirmation = session.confirmation
 
20
    response.warning = session.warning
 
21
    session.error = []
 
22
    session.confirmation = []
 
23
    session.warning = []
 
24
    # Keep all our configuration options in a single pair of global variables
 
25
    # Use session for persistent variables
 
26
    if not session.s3:
 
27
        session.s3 = Storage()
 
28
    # Use response for one-off variables which are visible in views without explicit passing
 
29
    response.s3 = Storage()
 
30
    response.s3.formats = Storage()
 
31
 
 
32
    roles = []
 
33
    try:
 
34
        user_id = auth.user.id
 
35
        _memberships = db.auth_membership
 
36
        memberships = db(_memberships.user_id == user_id).select(_memberships.group_id) # Cache this & invalidate when memberships are changed?
 
37
        for membership in memberships:
 
38
            roles.append(membership.group_id)
 
39
    except:
 
40
        # User not authenticated therefore has no roles other than '0'
 
41
        pass
 
42
    session.s3.roles = roles
 
43
 
 
44
    controller_settings_table = "%s_setting" % request.controller
 
45
    controller_settings = controller_settings_table in db.tables and \
 
46
       db(db[controller_settings_table].id > 0).select(limitby=(0, 1)).first()
 
47
 
 
48
    settings = db(db.s3_setting.id > 0).select(db.s3_setting.debug, db.s3_setting.security_policy, db.s3_setting.self_registration, db.s3_setting.audit_read, db.s3_setting.audit_write, limitby=(0, 1)).first()
 
49
    # Are we running in debug mode?
 
50
    session.s3.debug = "debug" in request.vars or settings and settings.debug
 
51
    session.s3.self_registration = (settings and settings.self_registration) or 1
 
52
    session.s3.security_policy = (settings and settings.security_policy) or 1
 
53
 
 
54
    # We Audit if either the Global or Module asks us to
 
55
    # (ignore gracefully if module author hasn't implemented this)
 
56
    session.s3.audit_read = (settings and settings.audit_read) \
 
57
        or (controller_settings and controller_settings.audit_read)
 
58
    session.s3.audit_write = (settings and settings.audit_write) \
 
59
        or (controller_settings and controller_settings.audit_write)
 
60
    return settings
 
61
 
 
62
s3_settings = shn_sessions()
 
63
 
 
64
#
 
65
# List of supported languages
 
66
#
 
67
shn_languages = {
 
68
    "en": T("English"),
 
69
    "fr": T("French")
 
70
}
 
71
auth.settings.table_user.language.requires = IS_IN_SET(shn_languages, zero=None)
 
72
 
 
73
#
 
74
# List of Nations - added by nursix
 
75
#
 
76
shn_list_of_nations = {
 
77
    1:T("Afghanistan"),
 
78
    2:T("Albania"),
 
79
    3:T("Algeria"),
 
80
    4:T("Andorra"),
 
81
    5:T("Angola"),
 
82
    6:T("Antigua and Barbuda"),
 
83
    7:T("Argentina"),
 
84
    8:T("Armenia"),
 
85
    9:T("Australia"),
 
86
    10:T("Austria"),
 
87
    11:T("Azerbaijan"),
 
88
    12:T("Bahamas"),
 
89
    13:T("Bahrain"),
 
90
    14:T("Bangladesh"),
 
91
    15:T("Barbados"),
 
92
    16:T("Belarus"),
 
93
    17:T("Belgium"),
 
94
    18:T("Belize"),
 
95
    19:T("Benin"),
 
96
    20:T("Bhutan"),
 
97
    21:T("Bolivia"),
 
98
    22:T("Bosnia and Herzegovina"),
 
99
    23:T("Botswana"),
 
100
    24:T("Brazil"),
 
101
    25:T("Brunei"),
 
102
    26:T("Bulgaria"),
 
103
    27:T("Burkina Faso"),
 
104
    28:T("Burundi"),
 
105
    29:T("Cambodia"),
 
106
    30:T("Cameroon"),
 
107
    31:T("Canada"),
 
108
    32:T("Cape Verde"),
 
109
    33:T("Central African Republic"),
 
110
    34:T("Chad"),
 
111
    35:T("Chile"),
 
112
    36:T("China"),
 
113
    37:T("Colombia"),
 
114
    38:T("Comoros"),
 
115
    39:T("Congo, Democratic Republic of the (Congo-Kinshasa)"),
 
116
    40:T("Congo, Republic of the (Congo-Brazzaville)"),
 
117
    41:T("Costa Rica"),
 
118
    42:T("Côte d'Ivoire"),
 
119
    43:T("Croatia"),
 
120
    44:T("Cuba"),
 
121
    45:T("Cyprus"),
 
122
    46:T("Czech Republic"),
 
123
    47:T("Denmark"),
 
124
    48:T("Djibouti"),
 
125
    49:T("Dominica"),
 
126
    50:T("Dominican Republic"),
 
127
    51:T("East Timor"),
 
128
    52:T("Ecuador"),
 
129
    53:T("Egypt"),
 
130
    54:T("El Salvador"),
 
131
    55:T("Equatorial Guinea"),
 
132
    56:T("Eritrea"),
 
133
    57:T("Estonia"),
 
134
    58:T("Ethiopia"),
 
135
    59:T("Fiji"),
 
136
    60:T("Finland"),
 
137
    61:T("France"),
 
138
    62:T("Gabon"),
 
139
    63:T("The Gambia"),
 
140
    64:T("Georgia"),
 
141
    65:T("Germany"),
 
142
    66:T("Ghana"),
 
143
    67:T("Greece"),
 
144
    68:T("Grenada"),
 
145
    69:T("Guatemala"),
 
146
    70:T("Guinea"),
 
147
    71:T("Guinea-Bissau"),
 
148
    72:T("Guyana"),
 
149
    73:T("Haiti"),
 
150
    74:T("Honduras"),
 
151
    75:T("Hungary"),
 
152
    76:T("Iceland"),
 
153
    77:T("India"),
 
154
    78:T("Indonesia"),
 
155
    79:T("Iran"),
 
156
    80:T("Iraq"),
 
157
    81:T("Ireland"),
 
158
    82:T("Israel"),
 
159
    83:T("Italy"),
 
160
    84:T("Jamaica"),
 
161
    85:T("Japan"),
 
162
    86:T("Jordan"),
 
163
    87:T("Kazakhstan"),
 
164
    88:T("Kenya"),
 
165
    89:T("Kiribati"),
 
166
    90:T("Korea, North"),
 
167
    91:T("Korea, South"),
 
168
    92:T("Kuwait"),
 
169
    93:T("Kyrgyzstan"),
 
170
    94:T("Laos"),
 
171
    95:T("Latvia"),
 
172
    96:T("Lebanon"),
 
173
    97:T("Lesotho"),
 
174
    98:T("Liberia"),
 
175
    99:T("Libya"),
 
176
    100:T("Liechtenstein"),
 
177
    101:T("Lithuania"),
 
178
    102:T("Luxembourg"),
 
179
    103:T("Macedonia"),
 
180
    104:T("Madagascar"),
 
181
    105:T("Malawi"),
 
182
    106:T("Malaysia"),
 
183
    107:T("Maldives"),
 
184
    108:T("Mali"),
 
185
    109:T("Malta"),
 
186
    110:T("Marshall Islands"),
 
187
    111:T("Mauritania"),
 
188
    112:T("Mauritius"),
 
189
    113:T("Mexico"),
 
190
    114:T("Micronesia"),
 
191
    115:T("Moldova"),
 
192
    116:T("Monaco"),
 
193
    117:T("Mongolia"),
 
194
    118:T("Montenegro"),
 
195
    119:T("Morocco"),
 
196
    120:T("Mozambique"),
 
197
    121:T("Myanmar"),
 
198
    122:T("Namibia"),
 
199
    123:T("Nauru"),
 
200
    124:T("Nepal"),
 
201
    125:T("Netherlands"),
 
202
    126:T("New Zealand"),
 
203
    127:T("Nicaragua"),
 
204
    128:T("Niger"),
 
205
    129:T("Nigeria"),
 
206
    130:T("Norway"),
 
207
    131:T("Oman"),
 
208
    132:T("Pakistan"),
 
209
    133:T("Palau"),
 
210
    134:T("Panama"),
 
211
    135:T("Papua New Guinea"),
 
212
    136:T("Paraguay"),
 
213
    137:T("Peru"),
 
214
    138:T("Philippines"),
 
215
    139:T("Poland"),
 
216
    140:T("Portugal"),
 
217
    141:T("Qatar"),
 
218
    142:T("Romania"),
 
219
    143:T("Russia"),
 
220
    144:T("Rwanda"),
 
221
    145:T("Saint Kitts and Nevis"),
 
222
    146:T("Saint Lucia"),
 
223
    147:T("Saint Vincent and the Grenadines"),
 
224
    148:T("Samoa"),
 
225
    149:T("San Marino"),
 
226
    150:T("São Tomé and Príncipe"),
 
227
    151:T("Saudi Arabia"),
 
228
    152:T("Senegal"),
 
229
    153:T("Serbia"),
 
230
    154:T("Seychelles"),
 
231
    155:T("Sierra Leone"),
 
232
    156:T("Singapore"),
 
233
    157:T("Slovakia"),
 
234
    158:T("Slovenia"),
 
235
    159:T("Solomon Islands"),
 
236
    160:T("Somalia"),
 
237
    161:T("South Africa"),
 
238
    162:T("Spain"),
 
239
    163:T("Sri Lanka"),
 
240
    164:T("Sudan"),
 
241
    165:T("Suriname"),
 
242
    166:T("Swaziland"),
 
243
    167:T("Sweden"),
 
244
    168:T("Switzerland"),
 
245
    169:T("Syria"),
 
246
    170:T("Tajikistan"),
 
247
    171:T("Tanzania"),
 
248
    172:T("Thailand"),
 
249
    173:T("Togo"),
 
250
    174:T("Tonga"),
 
251
    175:T("Trinidad and Tobago"),
 
252
    176:T("Tunisia"),
 
253
    177:T("Turkey"),
 
254
    178:T("Turkmenistan"),
 
255
    179:T("Tuvalu"),
 
256
    180:T("Uganda"),
 
257
    181:T("Ukraine"),
 
258
    182:T("United Arab Emirates"),
 
259
    183:T("United Kingdom"),
 
260
    184:T("United States"),
 
261
    185:T("Uruguay"),
 
262
    186:T("Uzbekistan"),
 
263
    187:T("Vanuatu"),
 
264
    188:T("Vatican City"),
 
265
    189:T("Venezuela"),
 
266
    190:T("Vietnam"),
 
267
    191:T("Yemen"),
 
268
    192:T("Zambia"),
 
269
    193:T("Zimbabwe"),
 
270
    194:T("Abkhazia"),
 
271
    195:T("Kosovo"),
 
272
    196:T("Nagorno-Karabakh"),
 
273
    197:T("Northern Cyprus"),
 
274
    198:T("Somaliland"),
 
275
    199:T("South Ossetia"),
 
276
    200:T("Taiwan"),
 
277
    201:T("Transnistria"),
 
278
    999:T("unknown")
 
279
    }
 
280
 
 
281
# User Time Zone Operations:
 
282
 
 
283
from datetime import timedelta
 
284
import time
 
285
 
 
286
def shn_user_utc_offset():
 
287
    """
 
288
        returns the UTC offset of the current user or None, if not logged in
 
289
    """
 
290
 
 
291
    if auth.is_logged_in():
 
292
        return db(db.auth_user.id == session.auth.user.id).select(db.auth_user.utc_offset, limitby=(0, 1)).first().utc_offset
 
293
    else:
 
294
        try:
 
295
            offset = db().select(db.s3_setting.utc_offset, limitby=(0, 1)).first().utc_offset
 
296
        except:
 
297
            offset = None
 
298
        return offset
 
299
 
 
300
 
 
301
def shn_as_local_time(value):
 
302
    """
 
303
        represents a given UTC datetime.datetime object as string:
 
304
 
 
305
        - for the local time of the user, if logged in
 
306
        - as it is in UTC, if not logged in, marked by trailing +0000
 
307
    """
 
308
 
 
309
    format="%Y-%m-%d %H:%M:%S"
 
310
 
 
311
    offset = IS_UTC_OFFSET.get_offset_value(shn_user_utc_offset())
 
312
 
 
313
    if offset:
 
314
        dt = value + timedelta(seconds=offset)
 
315
        return dt.strftime(str(format))
 
316
    else:
 
317
        dt = value
 
318
        return dt.strftime(str(format))+" +0000"
 
319
 
 
320
# Make URLs clickable
 
321
shn_url_represent = lambda url: (url and [A(url, _href=url, _target="blank")] or [""])[0]
 
322
 
 
323
# Phone number requires
 
324
shn_phone_requires = IS_NULL_OR(IS_MATCH('\+?\s*[\s\-\.\(\)\d]+(?:(?: x| ext)\s?\d{1,5})?$'))
 
325
 
 
326
def Tstr(text):
 
327
    """Convenience function for non web2py modules"""
 
328
    return str(T(text))
 
329
 
 
330
 
 
331
def myname(user_id):
 
332
    user = db.auth_user[user_id]
 
333
    return user.first_name if user else "None"
 
334
 
 
335
 
 
336
def shn_last_update(table, record_id):
 
337
 
 
338
    if table and record_id:
 
339
        record = table[record_id]
 
340
        if record:
 
341
            mod_on_str  = T(" on ")
 
342
            mod_by_str  = T(" by ")
 
343
 
 
344
            modified_on = ""
 
345
            if "modified_on" in table.fields:
 
346
                modified_on = "%s%s" % (mod_on_str, shn_as_local_time(record.modified_on))
 
347
 
 
348
            modified_by = ""
 
349
            if "modified_by" in table.fields:
 
350
                user = auth.settings.table_user[record.modified_by]
 
351
                if user:
 
352
                    person = db(db.pr_person.uuid == user.person_uuid).select(limitby=(0, 1)).first()
 
353
                    if person:
 
354
                        modified_by = "%s%s" % (mod_by_str, vita.fullname(person))
 
355
 
 
356
            if len(modified_on) or len(modified_by):
 
357
                last_update = "%s%s%s" % (T("Record last updated"), modified_on, modified_by)
 
358
                return last_update
 
359
    return None
 
360
 
 
361
def shn_compose_message(data, template):
 
362
    " Compose an SMS Message from an XSLT "
 
363
    from lxml import etree
 
364
    if data:
 
365
        root = etree.Element("message")
 
366
        for k in data.keys():
 
367
            entry = etree.SubElement(root, k)
 
368
            entry.text = s3xrc.xml.xml_encode(str(data[k]))
 
369
 
 
370
        message = None
 
371
        tree = etree.ElementTree(root)
 
372
 
 
373
        if template:
 
374
            template = os.path.join(request.folder, "static", template)
 
375
            if os.path.exists(template):
 
376
                message = s3xrc.xml.transform(tree, template)
 
377
 
 
378
        if message:
 
379
            return str(message)
 
380
        else:
 
381
            return s3xrc.xml.tostring(tree, pretty_print=True)
 
382
 
 
383
 
 
384
def shn_crud_strings(table_name,
 
385
                     table_name_plural = None):
 
386
    """
 
387
    @author: Michael Howden (michael@aidiq.com)
 
388
 
 
389
    @description:
 
390
        Creates the strings for the title of/in the various CRUD Forms.
 
391
 
 
392
    @arguments:
 
393
        table_name - string - The User's name for the resource in the table - eg. "Person"
 
394
        table_name_plural - string - The User's name for the plural of the resource in the table - eg. "People"
 
395
 
 
396
    @returns:
 
397
        class "gluon.storage.Storage" (Web2Py)
 
398
 
 
399
    @example
 
400
        s3.crud_strings[<table_name>] = shn_crud_strings(<table_name>, <table_name_plural>)
 
401
    """
 
402
 
 
403
    if not table_name_plural:
 
404
        table_name_plural = table_name + "s"
 
405
 
 
406
    ADD = T("Add " + table_name)
 
407
    LIST = T("List "+ table_name_plural)
 
408
 
 
409
    table_strings = Storage(
 
410
    title = T(table_name),
 
411
    title_plural = T(table_name_plural),
 
412
    title_create = ADD,
 
413
    title_display = T(table_name + " Details"),
 
414
    title_list = LIST,
 
415
    title_update = T("Edit "+ table_name) ,
 
416
    title_search = T("Search " + table_name_plural) ,
 
417
    subtitle_create = T("Add New " + table_name) ,
 
418
    subtitle_list = T(table_name_plural),
 
419
    label_list_button = LIST,
 
420
    label_create_button = ADD,
 
421
    msg_record_created =  T(table_name +" added"),
 
422
    msg_record_modified =  T(table_name + " updated"),
 
423
    msg_record_deleted = T( table_name + " deleted"),
 
424
    msg_list_empty = T("No " + table_name_plural + " currently registered"))
 
425
 
 
426
    return table_strings
 
427
 
 
428
 
 
429
def shn_get_crud_strings(tablename):
 
430
 
 
431
    """ Get the CRUD strings for a table """
 
432
 
 
433
    return s3.crud_strings.get(tablename, s3.crud_strings)
 
434
 
 
435
 
 
436
def shn_import_table(table_name,
 
437
                     import_if_not_empty = False):
 
438
    """
 
439
    @author: Michael Howden (michael@aidiq.com)
 
440
 
 
441
    @description:
 
442
        If a table is empty, it will import values into that table from:
 
443
        /private/import/tables/<table>.csv.
 
444
 
 
445
    @arguments:
 
446
        table_name - string - The name of the table
 
447
        import_if_not_empty - bool
 
448
    """
 
449
 
 
450
    table = db[table_name]
 
451
    if not db(table.id).count() or import_if_not_empty:
 
452
        import_file = os.path.join(request.folder,
 
453
                                   "private", "import", "tables",
 
454
                                   table_name + ".csv")
 
455
        table.import_from_csv_file(open(import_file,"r"))
 
456
 
 
457
 
 
458
def shn_represent_file(file_name,
 
459
                       table,
 
460
                       field = "file"):
 
461
    """
 
462
    @author: Michael Howden (michael@aidiq.com)
 
463
 
 
464
    @description:
 
465
        Represents a file (stored in a table) as the filename with a link to that file
 
466
    """
 
467
    import base64
 
468
    url_file = crud.settings.download_url + "/" + file_name
 
469
 
 
470
    if db[table][field].uploadfolder:
 
471
        path = db[table][field].uploadfolder
 
472
    else:
 
473
        path = os.path.join(db[table][field]._db._folder, "..", "uploads")
 
474
    pathfilename = os.path.join(path, file_name)
 
475
 
 
476
    try:
 
477
        #f = open(pathfilename,"r")
 
478
        #filename = f.filename
 
479
        regex_content = re.compile("([\w\-]+\.){3}(?P<name>\w+)\.\w+$")
 
480
        regex_cleanup_fn = re.compile('[\'"\s;]+')
 
481
 
 
482
        m = regex_content.match(file_name)
 
483
        filename = base64.b16decode(m.group("name"), True)
 
484
        filename = regex_cleanup_fn.sub("_", filename)
 
485
    except:
 
486
        filename = file_name
 
487
 
 
488
    return A(filename, _href = url_file)
 
489
 
 
490
 
 
491
def shn_rheader_tabs(jr, tabs=[]):
 
492
 
 
493
    """ Constructs a DIV of component links for a S3RESTRequest """
 
494
 
 
495
    rheader_tabs = []
 
496
    for (title, component) in tabs:
 
497
        _class = "rheader_tab_other"
 
498
        if component:
 
499
            if jr.component and jr.component.name == component or \
 
500
               jr.custom_action and jr.method == component:
 
501
                _class = "rheader_tab_here"
 
502
            args = [jr.id, component]
 
503
            _href = URL(r=request, f=jr.name, args=args)
 
504
        else:
 
505
            if not jr.component:
 
506
                _class = "rheader_tab_here"
 
507
            args = [jr.id]
 
508
            _next = URL(r=request, f=jr.name, args=[jr.id])
 
509
            _href = URL(r=request, f=jr.name, args=args, vars = {"_next": _next})
 
510
        tab = SPAN(A(title, _href=_href), _class=_class)
 
511
        rheader_tabs.append(tab)
 
512
 
 
513
    if rheader_tabs:
 
514
        rheader_tabs = DIV(rheader_tabs, _id="rheader_tabs")
 
515
    else:
 
516
        rheader_tabs = ""
 
517
 
 
518
    return rheader_tabs
 
519
 
 
520
def shn_action_buttons(jr, deletable=True):
 
521
    """ Provide the usual Action Buttons for Column views. Designed to be called from a postp """
 
522
 
 
523
    if not jr.component:
 
524
        if auth.is_logged_in():
 
525
            # Provide the ability to delete records in bulk
 
526
            if deletable:
 
527
                response.s3.actions = [
 
528
                    dict(label=str(UPDATE), _class="action-btn", url=str(URL(r=request, args=["[id]", "update"]))),
 
529
                    dict(label=str(DELETE), _class="action-btn", url=str(URL(r=request, args=["[id]", "delete"])))
 
530
                ]
 
531
            else:
 
532
                response.s3.actions = [
 
533
                    dict(label=str(UPDATE), _class="action-btn", url=str(URL(r=request, args=["[id]", "update"])))
 
534
                ]
 
535
        else:
 
536
            response.s3.actions = [
 
537
                dict(label=str(READ), _class="action-btn", url=str(URL(r=request, args=["[id]"])))
 
538
            ]
 
539
 
 
540
    return
 
 
b'\\ No newline at end of file'