default.py 28.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
# -*- coding: utf-8 -*-
# this file is released under public domain and you can use without limitations

#########################################################################
## This is a sample controller
## - index is the default action of any application
## - user is required for authentication and authorization
## - download is for downloading files uploaded in the db (does streaming)
## - call exposes all registered services (none by default)
#########################################################################

12
import defs
13
import vidjil_utils
14
import StringIO
15
import logging
16
from controller_utils import error_message
17

18
import gluon.contrib.simplejson, time, datetime
19
if request.env.http_origin:
20
    response.headers['Access-Control-Allow-Origin'] = request.env.http_origin
21 22
    response.headers['Access-Control-Allow-Credentials'] = 'true'
    response.headers['Access-Control-Max-Age'] = 86400
23

24
#########################################################################
25
##return the default index page for vidjil (redirect to the browser)
26 27 28
def index():
    return dict(message=T('hello world'))

29 30
#########################################################################
##return the view default/help.html
31 32 33
def help():
    return dict(message=T('help i\'m lost'))

34 35 36
#########################################################################
## default home page
def home():
37 38 39
    if auth.is_admin():
        redirect = URL('admin', 'index', scheme=True, host=True)
    else:
40
        redirect = URL('sample_set', 'all', vars={'type': defs.SET_TYPE_PATIENT, 'page': 0}, scheme=True, host=True)
41
    res = {"redirect" : redirect}
42
    return gluon.contrib.simplejson.dumps(res, separators=(',',':'))
43 44 45 46 47 48 49 50

def logger():
    '''Log to the server'''
    res = {"success" : "false",
           "message" : "/client/: %s" % request.vars['msg']}

    try:
        lvl = int(request.vars['lvl'])
51
    except:
52 53 54
        lvl = logging.INFO
    log.log(lvl, res)

55
def init_db():
56
    if (db(db.auth_user.id > 0).count() == 0) :
57
        return dict(message=T('create admin user and initialise database'))
58 59 60 61 62 63 64
    res = {"redirect" : "default/user/login"}
    return gluon.contrib.simplejson.dumps(res, separators=(',',':'))


def init_db_form():
    if (db(db.auth_user.id > 0).count() == 0) :
        error = ""
65
        force = False
66 67 68 69 70 71
        if request.vars['email'] == "":
            error += "You must specify an admin email address, "
        if len(request.vars['password']) < 8:
            error += "Password must be at least 8 characters long, "
        if request.vars['confirm_password'] != request.vars['password']:
            error += "Passwords didn't match"
72 73
        if "force" in request.vars and request.vars["force"].lower() == 'true':
            force = True
74
        if error == "":
75
            vidjil_utils.init_db_helper(db, auth, force=force, admin_email=request.vars['email'], admin_password=request.vars['password'])
76 77 78 79 80 81 82 83
        else :
            res = {"success" : "false",
                   "message" : error}
            log.error(res)
            return gluon.contrib.simplejson.dumps(res, separators=(',',':'))

    res = {"redirect" : "default/user/login"}
    return gluon.contrib.simplejson.dumps(res, separators=(',',':'))
84

85 86
def init_from_csv():
    if db(db.auth_user.id > 0).count() == 0:
87 88 89 90
        res = {"success" : "true", "message" : "Importing " + defs.DB_BACKUP_FILE}
        log.info(res)

        try:
91
            db.import_from_csv_file(open(defs.DB_BACKUP_FILE, 'rb'))
92 93
            # db.scheduler_task.truncate()
            # db.scheduler_run.truncate()
94 95 96 97 98 99 100
        except Exception as e:
            res = {"success": "false", "message": "!" + str(e)}
            log.error(res)
            raise

        res = {"success" : "true", "message" : "coucou"}
        log.info(res)
101

102
#########################################################################
103
## add a scheduller task to run vidjil on a specific sequence file
104
# need sequence_file_id, config_id
105
# need patient admin permission
106
def run_request():
107
    error = ""
108
    enough_space = vidjil_utils.check_enough_space(defs.DIR_RESULTS)
109
    if not enough_space:
HERBERT Ryan's avatar
HERBERT Ryan committed
110 111
        mail.send(to=defs.ADMIN_EMAILS,
            subject="[Vidjil] Server space",
112
            message="The space in directory %s has passed below %d%%." % (defs.DIR_RESULTS, defs.FS_LOCK_THRESHHOLD))
113
        return error_message("Runs are temporarily disabled. System admins have been made aware of the situation.")
114

115
    ##TODO check
116 117 118 119
    if not "sequence_file_id" in request.vars :
        error += "id sequence file needed, "
    if not "config_id" in request.vars:
        error += "id config needed, "
120 121 122
        id_config = None
    else:
        id_config = request.vars["config_id"]
123
    if not auth.can_process_sample_set(request.vars['sample_set_id']):
124
        error += "permission needed"
125

126
    id_sample_set = request.vars["sample_set_id"]
127

128 129 130 131 132
    if "grep_reads" in request.vars:
        grep_reads = request.vars["grep_reads"]
    else:
        grep_reads = None

133 134
    if not auth.can_modify_sample_set(id_sample_set) :
        error += "you do not have permission to launch process for this sample_set ("+str(id_sample_set)+"), "
135

136
    if id_config:
137 138
        if not auth.can_use_config(id_config) :
            error += "you do not have permission to launch process for this config ("+str(id_config)+"), "
139

140
    if error == "" :
141
        res = schedule_run(request.vars["sequence_file_id"], id_config, grep_reads)
142
        log.info("run requested", extra={'user_id': auth.user.id, 'record_id': request.vars['sequence_file_id'], 'table_name': 'sequence_file'})
143 144 145
        return gluon.contrib.simplejson.dumps(res, separators=(',',':'))

    else :
146
        res = {"success" : "false",
147
               "message" : "default/run_request : " + error}
148
        log.error(res)
149
        return gluon.contrib.simplejson.dumps(res, separators=(',',':'))
150

151 152 153 154 155 156 157 158 159 160 161
def run_contamination():
    task = scheduler.queue_task('compute_contamination', pvars=dict(sequence_file_id=request.vars["sequence_file_id"],
                                                                    results_file_id=request.vars["results_file_id"],
                                                                    config_id=request.vars["config_id"]),
             repeats = 1, timeout = defs.TASK_TIMEOUT,immediate=True)
    
    res = {"success" : "true",
           "processId" : task.id}
    log.error(res)
    return gluon.contrib.simplejson.dumps(res, separators=(',',':'))

162 163 164 165 166 167 168 169
def run_extra():
    task = scheduler.queue_task('compute_extra', pvars=dict(id_file=request.vars["sequence_file_id"],
                                                            id_config=request.vars["config_id"],
                                                            min_threshold=5))
    res = {"success" : "true",
           "processId" : task.id}
    log.debug(res)
    return gluon.contrib.simplejson.dumps(res, separators=(',',':'))
170

171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
def checkProcess():
    task = db.scheduler_task[request.vars["processId"]]
    
    if task.status == "COMPLETED" :
        run = db( db.scheduler_run.task_id == task.id ).select()[0]
    
        res = {"success" : "true",
               "status" : task.status,
               "data" : run.run_result,
               "processId" : task.id}
    else :
        res = {"success" : "true",
               "status" : task.status,
               "processId" : task.id}
        
    log.error(res)
    return gluon.contrib.simplejson.dumps(res, separators=(',',':'))

189

190 191
#########################################################################
## return .data file
192
# need sample_set/patient, config
193
# need sample_set admin or read permission
194
def get_data():
195
    from subprocess import Popen, PIPE, STDOUT
196
    if not auth.user :
197 198
        res = {"redirect" : URL('default', 'user', args='login', scheme=True, host=True,
                            vars=dict(_next=URL('default', 'get_data', scheme=True, host=True,
199
                                                vars=dict(sample_set_id = request.vars["sample_set_id"],
200 201 202 203
                                                          config =request.vars["config"]))
                                      )
                            )}
        return gluon.contrib.simplejson.dumps(res, separators=(',',':'))
204

205
    error = ""
206 207 208
    
    if "patient" in request.vars :
        request.vars["sample_set_id"] = db.patient[request.vars["patient"]].sample_set_id
209

210 211 212 213
    download = False
    if "filename" in request.vars:
        download = True

214 215 216
    if "run" in request.vars :
        request.vars["sample_set_id"] = db.run[request.vars["run"]].sample_set_id
    
217
    if not "sample_set_id" in request.vars or request.vars['sample_set_id'] is None:
218 219 220 221
        error += "id sampleset file needed, "
    else : 
        if not auth.can_view_sample_set(request.vars["sample_set_id"]):
            error += "you do not have permission to consult this sample_set ("+str(request.vars["sample_set_id"])+")"
222
    if not "config" in request.vars:
223
        error += "id config needed, "
224

225 226 227 228

    sample_set = db.sample_set[request.vars["sample_set_id"]]
    
    query = db( ( db.fused_file.sample_set_id == request.vars["sample_set_id"])
229
               & ( db.fused_file.config_id == request.vars["config"] )
230 231 232 233
               ).select(db.fused_file.ALL).first()
    if query is not None:
        fused_file = defs.DIR_RESULTS+'/'+query.fused_file
        sequence_file_list = query.sequence_file_list
234

235 236
    if not 'fused_file' in locals():
        error += "file not found"
237

238
    if error == "" :
239

240
        f = open(fused_file, "r")
241
        data = gluon.contrib.simplejson.loads(f.read())
242
        f.close()
243
        
244 245
        patient_name = ""
        run_name = ""
246
        config_name = db.config[request.vars["config"]].name
247
        command = db.config[request.vars["config"]].command
HERBERT Ryan's avatar
HERBERT Ryan committed
248 249

        log_reference_id = request.vars["sample_set_id"]
250 251

        if (sample_set.sample_type == defs.SET_TYPE_GENERIC) :
252 253 254 255 256 257 258
            for row in db( db.generic.sample_set_id == request.vars["sample_set_id"] ).select() :
                log_reference_id = row.id
                generic_name = db.generic[row.id].name
                data["dataFileName"] = generic_name + " (" + config_name + ")"
                data["info"] = db.generic[row.id].info
                data["generic_id"] = row.id
                data["sample_name"] = generic_name
259
                data["group_id"] = get_set_group(row.sample_set_id)
260

261
        if (sample_set.sample_type == defs.SET_TYPE_PATIENT):
262
            for row in db( db.patient.sample_set_id == request.vars["sample_set_id"] ).select() :
HERBERT Ryan's avatar
HERBERT Ryan committed
263
                log_reference_id = row.id
264
                patient_name = vidjil_utils.anon_ids([row.id])[0]
265 266
                data["dataFileName"] = patient_name + " (" + config_name + ")"
                data["info"] = db.patient[row.id].info
267
                data["patient_id"] = row.id
268
                data["sample_name"] = patient_name
269
                data["group_id"] = get_set_group(row.sample_set_id)
270

271
        if (sample_set.sample_type == defs.SET_TYPE_RUN) :
272
            for row in db( db.run.sample_set_id == request.vars["sample_set_id"] ).select() :
HERBERT Ryan's avatar
HERBERT Ryan committed
273
                log_reference_id = row.id
274 275
                run_name = db.run[row.id].name
                data["dataFileName"] = run_name + " (" + config_name + ")"
276 277
                data["info"] = db.run[row.id].info
                data["run_id"] = row.id
278
                data["sample_name"] = run_name
279
                data["group_id"] = get_set_group(row.sample_set_id)
280

HERBERT Ryan's avatar
HERBERT Ryan committed
281 282 283 284 285 286 287 288
        log_query = db(  ( db.user_log.record_id == log_reference_id )
                       & ( db.user_log.table_name == sample_set.sample_type )
                      ).select(db.user_log.ALL, orderby=db.user_log.created)

        data["logs"] = []
        for row in log_query:
            data["logs"].append({'message': row.msg, 'created': str(row.created)})

289
        ## récupération des infos stockées sur la base de données
290 291
        query = db(  ( db.sample_set.id == request.vars["sample_set_id"] )
                   & ( db.sample_set.id == db.sample_set_membership.sample_set_id )
292
                   & ( db.sequence_file.id == db.sample_set_membership.sequence_file_id)
293 294
                   & ( db.results_file.sequence_file_id == db.sequence_file.id )
                   & ( db.results_file.config_id == request.vars["config"]  )
295 296
                   ).select(db.sequence_file.ALL,db.results_file.ALL, db.sample_set.id, orderby=db.sequence_file.id|~db.results_file.run_date)

297
        query2 = {}
298 299 300
        sequence_file_id = 0
        for row in query : 
            if row.sequence_file.id != sequence_file_id :
301
                query2[row.sequence_file.data_file]=row
302 303
                sequence_file_id = row.sequence_file.id
        
304 305 306 307 308 309 310 311 312 313
        data["sample_set_id"] = sample_set.id

        data["config_name"] = config_name
        data["samples"]["info"] = []
        data["samples"]["timestamp"] = []
        data["samples"]["sequence_file_id"] = []
        data["samples"]["results_file_id"] = []
        data["samples"]["config_id"] = []
        data["samples"]["names"] = []
        data["samples"]["db_key"] = []
314 315
        data["samples"]["id"] = []
        data["samples"]["patient_id"] = []
316
        data["samples"]["sample_name"] = []
317
        data["samples"]["run_id"] = []
318
        for i in range(len(data["samples"]["original_names"])) :
319
            o_n = data["samples"]["original_names"][i].split('/')[-1]
320 321 322 323
            data["samples"]["original_names"][i] = data["samples"]["original_names"][i].split('/')[-1]
            data["samples"]["config_id"].append(request.vars['config'])
            data["samples"]["db_key"].append('')
            data["samples"]["commandline"].append(command)
324 325
            if o_n in query2:
                row = query2[o_n]
326 327 328 329 330
                data["samples"]["info"].append(row.sequence_file.info)
                data["samples"]["timestamp"].append(str(row.sequence_file.sampling_date))
                data["samples"]["sequence_file_id"].append(row.sequence_file.id)
                data["samples"]["results_file_id"].append(row.results_file.id)
                data["samples"]["names"].append(row.sequence_file.filename.split('.')[0])
331 332
                data["samples"]["id"].append(row.sequence_file.id)
                data["samples"]["patient_id"].append(get_patient_id(row.sequence_file.id))
333
                data["samples"]["sample_name"].append(row.sequence_file.id)
334
                data["samples"]["run_id"].append(row.sequence_file.id)
335 336
            else :
                data["samples"]["info"].append("this file has been deleted from the database, info relative to this sample are no longer available")
337
                data["samples"]["timestamp"].append("None")
338 339 340
                data["samples"]["sequence_file_id"].append("")
                data["samples"]["results_file_id"].append("")
                data["samples"]["names"].append("deleted")
341
                data["samples"]["id"].append("")
342

343
        log.debug("get_data (%s) c%s -> %s (%s)" % (request.vars["sample_set_id"], request.vars["config"], fused_file, "downloaded" if download else "streamed"))
344
        log.info("load sample", extra={'user_id': auth.user.id, 'record_id': request.vars['sample_set_id'], 'table_name': 'sample_set'})
345 346 347 348 349

        dumped_json = gluon.contrib.simplejson.dumps(data, separators=(',',':'))

        if download:
             return response.stream(StringIO.StringIO(dumped_json), attachment = True, filename = request.vars['filename'])
350

351
        return dumped_json
352 353
    else :
        res = {"success" : "false",
354
               "message" : "get_data (%s) c%s : %s " % (request.vars["sample_set_id"], request.vars["config"], error)}
355
        log.error(res)
356
        return gluon.contrib.simplejson.dumps(res, separators=(',',':'))
357 358 359 360 361 362 363 364 365
    
#########################################################################
def get_custom_data():
    from subprocess import Popen, PIPE, STDOUT
    if not auth.user :
        res = {"redirect" : URL('default', 'user', args='login', scheme=True, host=True)} #TODO _next
        return gluon.contrib.simplejson.dumps(res, separators=(',',':'))

    error = ""
366

367 368
    samples = []

369 370 371
    if not "custom" in request.vars :
        error += "no file selected, "
    else:
372 373 374
        samples = request.vars['custom'] if request.vars['custom'] is list else [request.vars['custom']]
        if not samples:
            error += "incorrect query, need at least one sample"
375
        else:
376
            for id in samples:
377 378
                log.debug("id = '%s'" % str(id))
                sequence_file_id = db.results_file[id].sequence_file_id
379 380 381 382
                sample_set_id = db((db.sample_set_membership.sequence_file_id == sequence_file_id)
                ).select(db.sample_set_membership.sample_set_id).first().sample_set_id
                if not auth.can_view_sample_set(sample_set_id):
                    error += "you do not have permission to consult this element ("+str(sample_set_id)+")"
383 384
            
    if error == "" :
385
        try:
386
            data = custom_fuse(samples)
387 388
        except IOError, error:
            return error_message(str(error))
389
        
390
        generic_info = "Compare samples" if len(samples) > 1 else "Sample %s" % samples[0]
391
        data["sample_name"] = generic_info
392 393
        data["dataFileName"] = generic_info
        data["info"] = generic_info
394 395 396
        data["samples"]["original_names"] = []
        data["samples"]["timestamp"] = []
        data["samples"]["info"] = []
397
        data["samples"]["commandline"] = []
398
        
399
        for id in samples:
400
            sequence_file_id = db.results_file[id].sequence_file_id
401
            sample_set = db((db.sequence_file.id == sequence_file_id)
402 403
                            & (db.sample_set_membership.sequence_file_id == db.sequence_file.id)
                            & (db.sample_set.id == db.sample_set_membership.sample_set_id)
404
                            & (db.sample_set.sample_type.belongs([defs.SET_TYPE_PATIENT, defs.SET_TYPE_RUN, defs.SET_TYPE_GENERIC]))
405
                            ).select(db.sample_set.id, db.sample_set.sample_type).first()
406

407
            patient_run = db(db[sample_set.sample_type].sample_set_id == sample_set.id).select().first()
408
            config_id = db.results_file[id].config_id
409
            name = vidjil_utils.anon_ids([patient_run.id])[0] if sample_set.sample_type == defs.SET_TYPE_PATIENT else patient_run.name
410
            filename = db.sequence_file[sequence_file_id].filename
411
            data["samples"]["original_names"].append(name + "_" + filename)
412 413
            data["samples"]["timestamp"].append(str(db.sequence_file[sequence_file_id].sampling_date))
            data["samples"]["info"].append(db.sequence_file[sequence_file_id].info)
414
            data["samples"]["commandline"].append(db.config[config_id].command)
415

416 417
        log.info("load custom data #TODO log db")

418 419 420 421 422 423 424 425
        return gluon.contrib.simplejson.dumps(data, separators=(',',':'))

    else :
        res = {"success" : "false",
               "message" : "default/get_custom_data : " + error}
        log.error(res)
        return gluon.contrib.simplejson.dumps(res, separators=(',',':'))
    
426 427
#########################################################################
## return .analysis file
428
# need patient_id
429
# need patient admin or read permission
430 431 432
def get_analysis():
    error = ""

433 434 435 436
    if "custom" in request.vars :
        res = {"success" : "true"}
        return gluon.contrib.simplejson.dumps(res, separators=(',',':'))

437 438 439
    if "patient" in request.vars :
        request.vars["sample_set_id"] = db.patient[request.vars["patient"]].sample_set_id

440 441 442 443
    download = False
    if "filename" in request.vars:
        download = True

444 445 446
    if "run" in request.vars :
        request.vars["sample_set_id"] = db.run[request.vars["run"]].sample_set_id
    
447
    if not "sample_set_id" in request.vars or request.vars['sample_set_id'] is None:
448 449 450
        error += "id sample_set file needed, "
    if not auth.can_view_sample_set(request.vars["sample_set_id"]):
        error += "you do not have permission to consult this sample_set ("+str(request.vars["sample_set_id"])+")"
451

452
    if "custom" in request.vars :
453
        return gluon.contrib.simplejson.dumps(get_default_analysis(), separators=(',',':'))
454
    
455
    if error == "" :
456
        
457
        ## récupération des infos se trouvant dans le fichier .analysis
458
        analysis_data = get_analysis_data(request.vars['sample_set_id'])
459
        #analysis_data["info_patient"] = db.patient[request.vars["patient"]].info
460 461
        dumped_json = gluon.contrib.simplejson.dumps(analysis_data, separators=(',',':'))

462
        log.info("load analysis", extra={'user_id': auth.user.id, 'record_id': request.vars['sample_set_id'], 'table_name': 'sample_set'})
463

464 465 466 467
        if download:
            return response.stream(StringIO.StringIO(dumped_json), attachment = True, filename = request.vars['filename'])

        return dumped_json
468

469 470 471
    else :
        res = {"success" : "false",
               "message" : "default/get_analysis : " + error}
472
        log.error(res)
473
        return gluon.contrib.simplejson.dumps(res, separators=(',',':'))
474 475


476 477
#########################################################################
## upload .analysis file and store it on the database
478
# need patient_id, fileToUpload
479
# need patient admin permission
480 481
def save_analysis():
    error = ""
HERBERT Ryan's avatar
HERBERT Ryan committed
482

483 484 485 486 487
    if "patient" in request.vars :
        request.vars["sample_set_id"] = db.patient[request.vars["patient"]].sample_set_id

    if "run" in request.vars :
        request.vars["sample_set_id"] = db.run[request.vars["run"]].sample_set_id
488

489
    if not "sample_set_id" in request.vars :
490
        error += "It is currently not possible to save an analysis on a comparison of samples, "
HERBERT Ryan's avatar
HERBERT Ryan committed
491
    elif not auth.can_save_sample_set(request.vars['sample_set_id']) :
492
        error += "you do not have permission to save changes on this sample set"
493

494 495
    if error == "" :
        f = request.vars['fileToUpload']
496
        ts = time.time()
497
        
498
        sample_set_id = request.vars['sample_set_id']
499
        
500
        analysis_id = db.analysis_file.insert(analysis_file = db.analysis_file.analysis_file.store(f.file, f.filename),
501
                                              sample_set_id = sample_set_id,
502 503
                                              analyze_date = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
                                              )
504

505
        sample_type = db.sample_set[sample_set_id].sample_type
506
        if (request.vars['info'] is not None):
507
            if (sample_type == defs.SET_TYPE_PATIENT) :
508
                db(db.patient.sample_set_id == sample_set_id).update(info = request.vars['info']);
509 510

            if (sample_type == defs.SET_TYPE_RUN) :
511 512 513 514 515
                db(db.run.sample_set_id == sample_set_id).update(info = request.vars['info']);

        if (request.vars['samples_id'] is not None and request.vars['samples_info'] is not None):
	    ids = request.vars['samples_id'].split(',')
	    infos = request.vars['samples_info'].split(',')
516 517
        
        
518 519 520 521
            # TODO find way to remove loop ?
            for i in range(0, len(ids)):
                if(len(ids[i]) > 0):
                    db(db.sequence_file.id == int(ids[i])).update(info = infos[i])
522

523
        #patient_name = db.patient[request.vars['patient']].first_name + " " + db.patient[request.vars['patient']].last_name
524

525
        res = {"success" : "true",
526
               "message" : "(%s): analysis saved" % (sample_set_id)}
527
        log.info(res, extra={'user_id': auth.user.id})
528

529
        log.info("save analysis", extra={'user_id': auth.user.id, 'record_id': sample_set_id, 'table_name': 'sample_set'})
530 531
        return gluon.contrib.simplejson.dumps(res, separators=(',',':'))
    else :
532 533
        res = {"success" : "false",
               "message" : error}
534
        log.error(res)
535
        return gluon.contrib.simplejson.dumps(res, separators=(',',':'))
536 537


538

Vidjil Team's avatar
Vidjil Team committed
539
#########################################################################
540
def error():
Vidjil Team's avatar
Vidjil Team committed
541 542 543 544
    """
    Custom error handler that returns correct status codes,
    adapted from http://www.web2pyslices.com/slice/show/1529/custom-error-routing
    """
545

Vidjil Team's avatar
Vidjil Team committed
546 547
    code = request.vars.code
    request_url = request.vars.request_url
548
    requested_uri = request.vars.requested_uri
Vidjil Team's avatar
Vidjil Team committed
549
    ticket = request.vars.ticket
550
    response.status = int(code)
551

552
    assert(response.status == 500 and request_url != request.url) # avoid infinite loop
Vidjil Team's avatar
Vidjil Team committed
553

554 555 556
    ticket_url = '<a href="https://%(host)s/admin/default/ticket/%(ticket)s">%(ticket)s</a>' % { 'host':request.env.http_host,
                                                                                                 'ticket':ticket }
    log.error("Server error // %s" % ticket_url)
557

558
    user_str, x = log.process('', None)
559
    user_str = user_str.replace('<','').replace('>','').strip()
560

561 562 563
    mail.send(to=defs.ADMIN_EMAILS,
              subject="[Vidjil] Server error - %s" % user_str,
              message="<html>Ticket: %s<br/>At: %s<br />User: %s</html>" % (ticket_url, requested_uri, user_str))
Vidjil Team's avatar
Vidjil Team committed
564 565

    return "Server error"
566

567
    
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
def user():
    """
    exposes:
    http://..../[app]/default/user/login
    http://..../[app]/default/user/logout
    http://..../[app]/default/user/register
    http://..../[app]/default/user/profile
    http://..../[app]/default/user/retrieve_password
    http://..../[app]/default/user/change_password
    http://..../[app]/default/user/manage_users (requires membership in
    use @auth.requires_login()
        @auth.requires_membership('group name')
        @auth.requires_permission('read','table name',record_id)
    to decorate functions that need access control
    """
583

584
    #redirect already logged user 
585
    if auth.user and request.args[0] == 'login' :
586
        res = {"redirect" : URL('default', 'home', scheme=True, host=True)}
587
        return gluon.contrib.simplejson.dumps(res, separators=(',',':'))
588 589 590 591 592 593 594 595
    
    #only authentified admin user can access register view
    if auth.user and request.args[0] == 'register' :
        #save admin session (the registering will automatically login the new user in order to initialize its default values)
        admin_auth = session.auth
        auth.is_logged_in = lambda: False
        
        def post_register(form):
596
            # Set up a new user, after register
597 598

            # Default permissions
599
            add_default_group_permissions(auth, auth.user_group())
600 601 602

            # Appartenance to the public group
            group_id = db(db.auth_group.role == 'public').select()[0].id
603
            db.auth_membership.insert(user_id = auth.user.id, group_id = group_id)
604 605 606

            log.admin('User %s <%s> registered, group %s' % (auth.user.id, auth.user.email, auth.user_group()))

607 608 609 610
            #restore admin session after register
            session.auth = admin_auth
            auth.user = session.auth.user
        auth.settings.register_onaccept = post_register
611 612 613 614 615
        
        #redirect to the last added user view
        auth.settings.logged_url = URL('user', 'info')
        auth.settings.login_next = URL('user', 'info')
        
616 617 618 619 620 621 622
        return dict(form=auth.register())
    
    #reject others
    if request.args[0] == 'register' :
        res = {"message": "you need to be admin and logged to add new users"}
        return gluon.contrib.simplejson.dumps(res, separators=(',',':'))
    
623
    return dict(form=auth())
624

Marc Duez's avatar
Marc Duez committed
625 626 627 628
def impersonate() :
    if auth.is_impersonating() :
        stop_impersonate()
    if request.vars["id"] != 0 :
629
        log.debug({"success" : "true", "message" : "impersonate >> %s" % request.vars["id"]})
Marc Duez's avatar
Marc Duez committed
630
        auth.impersonate(request.vars["id"]) 
631
        log.debug({"success" : "true", "message" : "impersonated"})
632 633 634 635
    if not 'admin' in request.vars['next']:
        res = {"redirect": "reload"}
    else:
        res = {"redirect" : URL('patient', 'index', scheme=True, host=True)}
Marc Duez's avatar
Marc Duez committed
636 637 638 639
    return gluon.contrib.simplejson.dumps(res, separators=(',',':'))

def stop_impersonate() :
    if auth.is_impersonating() :
640
        log.debug({"success" : "true", "message" : "impersonate << stop"})
Marc Duez's avatar
Marc Duez committed
641 642 643 644
        auth.impersonate(0) 
        # force clean login (default impersonate don't restore everything :/ )
        auth.login_user(db.auth_user(auth.user.id))

645
    res = {"redirect" : "reload"}
Marc Duez's avatar
Marc Duez committed
646 647 648 649
    return gluon.contrib.simplejson.dumps(res, separators=(',',':'))



650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
## TODO make custom download for .data et .analysis
@cache.action()
def download():
    """
    allows downloading of uploaded files
    http://..../[app]/default/download/[filename]
    """
    return response.download(request, db, download_filename=request.vars.filename)

def download_data():

    file = "test"
    return response.stream( file, chunk_size=4096, filename=request.vars.filename)



#########################################################################