Une MAJ de sécurité est nécessaire sur notre version actuelle. Elle sera effectuée lundi 02/08 entre 12h30 et 13h. L'interruption de service devrait durer quelques minutes (probablement moins de 5 minutes).

vidjil_utils.py 7.09 KB
Newer Older
1
import math
2
import re
3
import defs
4
import json
5
from gluon import current
6
from datetime import date
7

8
def format_size(n, unit='B'):
9 10
    '''
    Takes an integer n, representing a filesize and returns a string
11 12
    where the size is formatted with the correct SI prefix and
    with a constant number of significant digits.
13 14

    Example:
15 16 17 18 19 20
    >>> format_size(42)
    '42 B'
    >>> format_size(123456)
    '123 kB'
    >>> format_size(1000*1000)
    '1.00 MB'
21
    >>> format_size(1024*1024*1024)
22 23 24
    '1.07 GB'
    >>> format_size(42*(2**40))
    '46.2 TB'
25
    '''
26 27 28 29

    if n == 0:
        return '0'

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
    size = float(n)
    PREFIXES = ['', 'k', 'M', 'G', 'T', 'P']

    for prefix in PREFIXES:
        if size < 1000:
            break
        size /= 1000


    if size > 100 or not prefix:
        fmt = '%.0f'
    elif size > 10:
        fmt = '%.1f'
    else:
        fmt = '%.2f'

    return fmt % size + ' ' + prefix + unit

48

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67


def age_years_months(birth, months_below_year=4):
    '''Get the age in years, and possibly months.'''

    today = date.today()
    years = today.year - birth.year - ((today.month, today.day) < (birth.month, birth.day))
    age = '%dy' % years

    if years >= months_below_year:
        return age

    months = today.month - birth.month - (today.day < birth.day)
    if months < 0:
        months += 12

    age += ' %dm' % months
    return age

68 69 70 71 72 73 74 75 76 77 78 79 80
def anon_birth(patient_id, user_id):
    '''Anonymize birth date. Only the 'anon' access see the full birth date.'''
    db = current.db
    auth=current.auth

    birth = db.patient[patient_id].birth
    age = age_years_months(birth)

    if auth.has_permission("anon", "patient", patient_id, user_id):
        return "%s (%s)" % (birth, age)
    else:
        return age

81
def anon(patient_id, user_id):
82
    '''Anonymize patient name. Only the 'anon' access see the full patient name.'''
83 84 85 86 87 88 89
    db = current.db
    auth=current.auth
    
    last_name = db.patient[patient_id].last_name
    first_name = db.patient[patient_id].first_name
    
    if auth.has_permission("anon", "patient", patient_id, user_id):
90
        name = last_name + " " + first_name
91
    else:
92 93 94 95 96 97
        try:
            ln = unicode(last_name, 'utf-8')
        except UnicodeDecodeError:
            ln = last_name
        name = ln[:3]

98 99 100 101
    # Admins also see the patient id
    if auth.has_membership("admin"):
        name += ' (%s)' % patient_id

102
    return name
103 104 105 106 107 108 109 110 111


# take a string to check and a filter_str (list of word to find (or not)) 
# return true if the string respect the filter list 
def filter(str, filter_str):
    filter_list = filter_str.split(" ")
    
    for f in filter_list :
        if len(f) > 0 and f[0] == "-" :
112
            if f[1:].lower() in str.lower():
113 114
                return False
        else :
115
            if f.lower() not in str.lower():
116 117
                return False
    return True
118 119


120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
#### Utilities on regex
def search_first_regex_in_file(regex, filename, max_nb_line=None):
    try:
        if max_nb_line is None:
            results = open(filename).readlines()
        else:
            results = open(filename).readlines(max_nb_line)
    except IOError as e:
        results = []

    matched_keys = {}
    for r in regex:
        for line in results:
            m = r.search(line)
            if m:
                for (key, val) in m.groupdict().items():
                    matched_keys[key] = val.replace('\\', '')
                break
    return matched_keys

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177

#### Utilities on JSON

def extract_value_from_json_path(json_path, json):
    '''
    Highly inspired from http://stackoverflow.com/a/7320664/1192742

    Takes a path (for instance field1/field2/field3) and returns
    the value at that path.

    If the value doesn't exist None will be returned.
    '''
    elem = json
    try:
        for x in json_path.strip("/").split("/"):
            elem = elem.get(x)
    except:
        pass

    return elem

def extract_fields_from_json(json_fields, pos_in_list, filename):
    '''
    Takes a map of JSON fields (the key is a common name
    and the value is a path) and return a similar map
    where the values are the values from the JSON filename.

    If the value retrieved from a JSON is an array, we will
    get only the item at position <pos_in_list>
    '''
    try:
        json_dict = json.loads(open(filename).read())
    except IOError:
        json_dict = {}

    matched_keys = {}
    for field in json_fields:
        value = extract_value_from_json_path(json_fields[field], json_dict)
178 179 180 181 182
        if value is not None:
            if  not isinstance(value, basestring) and len(value) > pos_in_list:
                matched_keys[field] = value[pos_in_list]
            else:
                matched_keys[field] = value
183 184 185 186 187

    return matched_keys

####

188 189 190 191 192 193 194 195
SOURCES = "https://github.com/vidjil/vidjil/blob/master/server/web2py/applications/vidjil/%s#L%s"
SOURCES_DIR_DEFAULT = 'controllers/'
SOURCES_DIR = {
    'task.py': 'models/',
    'db.py': 'models/',
}


196 197
log_patient = re.compile('\((\d+)\)')
log_config = re.compile(' c(\d+)')
198
log_task = re.compile('\[(\d+)\]')
199
log_py = re.compile('(.*[.]py):(\d+)')
200 201 202 203 204 205

def log_links(s):
    '''Add HTML links to a log string

    >>> log_links("abcdef")
    'abcdef'
206
    >>> log_links("[1234]abcdef")
207
    '[<a class="loglink pointer" onclick="db.call(\\'admin/showlog\\', {\\'file\\': \\'../..//mnt/result/tmp/out-001234/001234.vidjil.log\\', \\'format\\': \\'raw\\'})">1234</a>]abcdef'
208
    >>> log_links("abcdef(234)")
209
    'abcdef(<a class="loglink pointer" onclick="db.call(\\'patient/info\\', {\\'id\\': \\'234\\'})">234</a>)'
210
    >>> log_links("abcdef(234)abcdef c11")
211
    'abcdef(234)abcdef <a class="loglink pointer" href="?patient=234&config=11">c11</a>'
212 213 214 215 216 217 218 219 220 221
    '''

    ### Parses the input string

    m_patient = log_patient.search(s)
    patient = m_patient.group(1) if m_patient else None

    m_config = log_config.search(s)
    config = m_config.group(1) if m_config else None

222 223 224
    m_task = log_task.search(s)
    task = int(m_task.group(1)) if m_task else None

225 226 227 228 229 230 231 232
    m_py = log_py.search(s)
    if m_py:
        source = m_py.group(1)
        if source in SOURCES_DIR:
            source = SOURCES_DIR[source] + source
        else:
            source = SOURCES_DIR_DEFAULT + source

233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
    ### Rules

    url = ''  # href link
    call = '' # call to db

    if patient and config:
        url = "?patient=%s&config=%s" % (patient, config)
        (start, end) = m_config.span()
        start += 1

    elif patient:
        call = "patient/info"
        args = {'id': patient}
        (start, end) = m_patient.span()
        start += 1
        end -= 1

250
    if task:
251
        call = "admin/showlog"
252
        args = {'file': '../../' + defs.DIR_OUT_VIDJIL_ID % task + defs.BASENAME_OUT_VIDJIL_ID % task + '.vidjil.log', 'format': 'raw'}
253 254 255 256
        (start, end) = m_task.span()
        start += 1
        end -= 1

257 258 259 260
    if m_py:
        (start, end) = m_py.span(2)
        url = SOURCES % (source, m_py.group(2))

261 262 263 264 265 266 267 268 269
    ### Build final string

    link = ''
    if url:
        link = 'href="%s"' % url
    if call:
        link = '''onclick="db.call('%s', %s)"''' % (call, str(args))

    if link:
270
        s = '%s<a class="loglink pointer" %s>%s</a>%s' % (s[:start], link, s[start:end], s[end:])
271 272

    return s