def verify_user(database, user_id): db = models.get_database(database) or abort(404) user = db.session.query(db.User).get(user_id) or abort(404) if user.verified: flash('User already verified.') return redirect( url_for('frontend.experiments_index', database=database)) user.verified = True try: db.session.commit() msg = Message("[" + db.label + "] Account verified", recipients=[user.email]) msg.body = "Dear " + user.firstname + " " + user.lastname + ",\n\n" + \ "Your account was verified and you can now log in:\n" + \ request.url_root[:-1] + url_for('accounts.login', database=database) mail.send(msg) flash('Verified the account.') except Exception as e: db.session.rollback() flash( "Couldn't update verification status of user or send the notification mail: " + str(e)) return redirect(url_for('frontend.experiments_index', database=database))
def activate(database, activation_hash): db = models.get_database(database) or abort(404) user = db.session.query(db.User).filter_by(activation_hash=activation_hash).first() or abort(404) user.activation_hash = "" try: db.session.commit() user = db.session.query(db.User).filter_by(email=user.email).first() msg = Message("[" + db.label + "][Admin] Account was activated", recipients=[config.DEFAULT_MAIL_SENDER]) msg.body = ("The following account was just activated by a user:\n\n" + \ "Last name: %s\n" \ "First name: %s\n" \ "E-mail: %s\n" \ "Postal address: %s\n" \ "Affiliation: %s\n" \ "Affiliation type: %s\n" \ "Country: %s\n\n\n" \ "Use the following link to verify this user: " + request.url_root[:-1] + url_for( 'accounts.verify_user', database=database, user_id=user.idUser)) \ % ( user.lastname, user.firstname, user.email, user.postal_address, user.affiliation, user.affiliation_type, user.country) mail.send(msg) flash('Account activated. You will be able to log in when your account was verified by an administrator.') except Exception as e: db.session.rollback() print e flash('Could not activate account. Please contact an administrator.') return redirect(url_for('frontend.experiments_index', database=database))
def activate(database, activation_hash): db = models.get_database(database) or abort(404) user = db.session.query(db.User).filter_by( activation_hash=activation_hash).first() or abort(404) user.activation_hash = "" try: db.session.commit() user = db.session.query(db.User).filter_by(email=user.email).first() msg = Message("[" + db.label + "][Admin] Account was activated", recipients=[config.DEFAULT_MAIL_SENDER]) msg.body = ("The following account was just activated by a user:\n\n" + \ "Last name: %s\n" \ "First name: %s\n" \ "E-mail: %s\n" \ "Postal address: %s\n" \ "Affiliation: %s\n" \ "Affiliation type: %s\n" \ "Country: %s\n\n\n" \ "Use the following link to verify this user: " + request.url_root[:-1] + url_for( 'accounts.verify_user', database=database, user_id=user.idUser)) \ % ( user.lastname, user.firstname, user.email, user.postal_address, user.affiliation, user.affiliation_type, user.country) mail.send(msg) flash( 'Account activated. You will be able to log in when your account was verified by an administrator.' ) except Exception as e: db.session.rollback() print e flash('Could not activate account. Please contact an administrator.') return redirect(url_for('frontend.experiments_index', database=database))
def reset_password(database): db = models.get_database(database) or abort(404) form = forms.ResetPasswordForm() if form.validate_on_submit(): # find user by lower case email address user = db.session.query( db.User).filter_by(email=form.email.data.lower()).first() if not user or not user.verified: if not user: flash('No account with this e-mail address exists.') if user and not user.verified: flash('Account was not verified yet.') return render('/accounts/reset_password.html', db=db, database=database, form=form) hash = hashlib.sha256() hash.update(config.SECRET_KEY) hash.update(user.email) hash.update(str(datetime.datetime.now())) hash.update(user.password) # reuse the activation hash (user should be activated at this point already) user.activation_hash = 'pw_reset_' + hash.hexdigest() try: db.session.commit() msg = Message("[" + db.label + "] Password reset instructions", recipients=[user.email]) msg.body = "Dear " + user.firstname + " " + user.lastname + ",\n\n" + \ "If you did not use the password reset link on the website ignore this mail.\n\n" + \ "To reset your password please use the following link:\n" + \ request.url_root[:-1] + url_for('accounts.change_password', database=database, reset_hash=hash.hexdigest()) mail.send(msg) flash( 'E-mail was sent. Please refer to the mail for further instructions.' ) except Exception as e: print e flash( 'Could not send reset mail. Please contact an administrator.') return render('/accounts/reset_password.html', db=db, database=database, form=form)
def submit_benchmarks(database): db = models.get_database(database) or abort(404) form = forms.BenchmarksForm() if form.validate_on_submit(): upload_dir = os.path.join(config.UPLOAD_FOLDER, database, str(g.User.idUser)) move_dir = os.path.join(config.UPLOAD_FOLDER, database, secure_filename(form.category.data), str(g.User.idUser)) try: os.makedirs(upload_dir, mode=0700) except: pass try: os.makedirs(move_dir, mode=0700) except: pass try: for file in session.get('benchmarks', list()): try: os.rename(os.path.join(upload_dir, file), os.path.join(move_dir, file)) except Exception as ex: print ex flash('Benchmark submission successful.') try: msg = Message("[" + db.label + "][Admin] Benchmarks submitted", recipients=[config.DEFAULT_MAIL_SENDER]) msg.body = ( "The user %s %s with id %d just submitted some benchmarks" % (g.User.firstname, g.User.lastname, g.User.idUser)) mail.send(msg) except: pass session.pop('benchmarks', None) return redirect( url_for('frontend.experiments_index', database=database)) except Exception as ex: print ex flash('Error occured when trying to move the uploaded files.') return render('/accounts/submit_benchmarks.html', db=db, database=database, form=form)
def submit_benchmarks(database): db = models.get_database(database) or abort(404) form = forms.BenchmarksForm() if form.validate_on_submit(): upload_dir = os.path.join(config.UPLOAD_FOLDER, database, str(g.User.idUser)) move_dir = os.path.join(config.UPLOAD_FOLDER, database, secure_filename(form.category.data), str(g.User.idUser)) try: os.makedirs(upload_dir, mode=0700) except: pass try: os.makedirs(move_dir, mode=0700) except: pass try: for file in session.get('benchmarks', list()): try: os.rename(os.path.join(upload_dir, file), os.path.join(move_dir, file)) except Exception as ex: print ex flash('Benchmark submission successful.') try: msg = Message("[" + db.label + "][Admin] Benchmarks submitted", recipients=[config.DEFAULT_MAIL_SENDER]) msg.body = ("The user %s %s with id %d just submitted some benchmarks" % ( g.User.firstname, g.User.lastname, g.User.idUser)) mail.send(msg) except: pass session.pop('benchmarks', None) return redirect(url_for('frontend.experiments_index', database=database)) except Exception as ex: print ex flash('Error occured when trying to move the uploaded files.') return render('/accounts/submit_benchmarks.html', db=db, database=database, form=form)
def reset_password(database): db = models.get_database(database) or abort(404) form = forms.ResetPasswordForm() if form.validate_on_submit(): # find user by lower case email address user = db.session.query(db.User).filter_by(email=form.email.data.lower()).first() if not user or not user.verified: if not user: flash('No account with this e-mail address exists.') if user and not user.verified: flash('Account was not verified yet.') return render('/accounts/reset_password.html', db=db, database=database, form=form) hash = hashlib.sha256() hash.update(config.SECRET_KEY) hash.update(user.email) hash.update(str(datetime.datetime.now())) hash.update(user.password) # reuse the activation hash (user should be activated at this point already) user.activation_hash = 'pw_reset_' + hash.hexdigest() try: db.session.commit() msg = Message("[" + db.label + "] Password reset instructions", recipients=[user.email]) msg.body = "Dear " + user.firstname + " " + user.lastname + ",\n\n" + \ "If you did not use the password reset link on the website ignore this mail.\n\n" + \ "To reset your password please use the following link:\n" + \ request.url_root[:-1] + url_for('accounts.change_password', database=database, reset_hash=hash.hexdigest()) mail.send(msg) flash('E-mail was sent. Please refer to the mail for further instructions.') except Exception as e: print e flash('Could not send reset mail. Please contact an administrator.') return render('/accounts/reset_password.html', db=db, database=database, form=form)
def verify_user(database, user_id): db = models.get_database(database) or abort(404) user = db.session.query(db.User).get(user_id) or abort(404) if user.verified: flash('User already verified.') return redirect(url_for('frontend.experiments_index', database=database)) user.verified = True try: db.session.commit() msg = Message("[" + db.label + "] Account verified", recipients=[user.email]) msg.body = "Dear " + user.firstname + " " + user.lastname + ",\n\n" + \ "Your account was verified and you can now log in:\n" + \ request.url_root[:-1] + url_for('accounts.login', database=database) mail.send(msg) flash('Verified the account.') except Exception as e: db.session.rollback() flash("Couldn't update verification status of user or send the notification mail: " + str(e)) return redirect(url_for('frontend.experiments_index', database=database))
def register(database): """ User registration """ db = models.get_database(database) or abort(404) form = forms.RegistrationForm() errors = [] if form.validate_on_submit(): if db.session.query(db.User).filter_by(email=form.email.data.lower()) \ .count() > 0: errors.append( "An account with this email address already exists. Please check your e-mail account for the activation link.") try: captcha = map(int, form.captcha.data.split()) if not utils.satisfies(captcha, session['captcha']): errors.append("Wrong solution to the captcha challenge.") except: errors.append("Wrong format of the solution") if not errors: user = db.User() user.lastname = form.lastname.data user.firstname = form.firstname.data user.password = password_hash(form.password.data) user.email = form.email.data.lower() # store email in lower case for easier password reset etc user.postal_address = form.address.data user.affiliation = form.affiliation.data user.verified = False user.accepted_terms = form.accepted_terms.data user.affiliation_type = form.affiliation_type.data user.country = form.country.data hash = hashlib.sha256() hash.update(config.SECRET_KEY) hash.update(user.email) hash.update(str(datetime.datetime.now())) hash.update(user.password) user.activation_hash = hash.hexdigest() db.session.add(user) try: db.session.commit() except Exception: db.session.rollback() errors.append('Error while trying to save the account to the database. Please \ contact an administrator.') return render('/accounts/register.html', database=database, db=db, errors=errors, form=form) session.pop('captcha', None) msg = Message("[" + db.label + "] Account activation", recipients=[user.email]) msg.body = "Dear " + user.firstname + " " + user.lastname + ",\n\n" + \ "Please use the following link to activate your account:\n" + \ request.url_root[:-1] + url_for('accounts.activate', database=database, activation_hash=user.activation_hash) mail.send(msg) flash("Account created successfully. An e-mail has been sent to your account with an activation link.") return redirect(url_for('frontend.experiments_index', database=database)) # Save captcha to the session. The user will have to provide a solution for # the same captcha that was given to him. random.seed() f = utils.random_formula(2, 3) while not utils.SAT(f): f = utils.random_formula(2, 3) session['captcha'] = f return render('/accounts/register.html', database=database, db=db, errors=errors, form=form)
def submit_solver(database, id=None): """ Form to submit solvers to a database """ db = models.get_database(database) or abort(404) # Disallow submissions of new solvers in phase 4 if db.competition_phase() == 4 and id is None: abort(401) if id is not None: solver = db.session.query(db.Solver).get(id) or abort(404) if solver.user.idUser != g.User.idUser: abort(401) if db.competition_phase() == 4 and solver.competition_frozen: flash( 'This solver was found to be compatible with our execution environment, i.e. has no crashed test runs or test runs with unknown result, and can not be updated anymore. Please contact the organizers if there\'s a reason to submit a new version.') return redirect(url_for('accounts.list_solvers', database=database, user_id=g.User.idUser)) solver_binary = solver.binaries[0] if solver.binaries else None form = forms.SolverForm(request.form, solver) if request.method == 'GET': form.parameters.data = utils.parameter_template(solver) form.description_pdf.data = '' form.binary.data = '' form.code.data = '' if solver_binary: form.run_command.data = solver_binary.runCommand form.run_path.data = solver_binary.runPath else: form = forms.SolverForm() form.competition_categories.query = db.session.query(db.CompetitionCategory).all() error = None if form.validate_on_submit(): valid = True # assume valid, try to falsify with the following checks name = form.name.data description = form.description.data version = form.version.data authors = form.authors.data parameters = form.parameters.data run_path = form.run_path.data if id is None and db.session.query(db.Solver) \ .filter_by(name=name, version=version) \ .first() is not None: error = 'Solver with this name and version already exists' valid = False if id is None and not form.code.data and not form.binary.data: error = 'Please provide either a binary or the code (or both).' valid = False bin = None if (id is None or (id is not None and form.binary.data)) and form.binary.data: # if this is a new solver or a resubmission with new binary update binary bin = request.files[form.binary.name].stream.read() hash = hashlib.md5() hash.update(bin) # save the binary in the FS as log store_path = os.path.join(config.UPLOAD_FOLDER, 'solvers', secure_filename(str(g.User.idUser) + '-' + g.User.lastname), 'bin') try: os.makedirs(store_path) except: pass with open(os.path.join(store_path, hash.hexdigest()), 'wb') as f: f.write(bin) if not form.binary.data.filename.endswith('.zip'): tmpfile = StringIO() zip_file = zipfile.ZipFile(tmpfile, 'w', compression=zipfile.ZIP_DEFLATED) zip_file.writestr(form.binary.data.filename, bin) zip_file.close() tmpfile.seek(0) bin = tmpfile.read() run_path = form.binary.data.filename else: if not run_path: error = 'Since your binary is a .zip file, please provide the path of the executable within the archive' valid = False code = None if id is None or (id is not None and form.code.data): code = request.files[form.code.name].stream.read() code_hash = hashlib.md5() code_hash.update(code) # save the code in the FS as log store_path = os.path.join(config.UPLOAD_FOLDER, 'solvers', secure_filename(str(g.User.idUser) + '-' + g.User.lastname), 'code') try: os.makedirs(store_path) except: pass with open(os.path.join(store_path, code_hash.hexdigest()), 'wb') as f: f.write(code) description_pdf = None if id is None or (id is not None and form.description_pdf.data): description_pdf = request.files[form.description_pdf.name].stream.read() if id is None and not description_pdf: valid = False error = "Please provide a description pdf." params = utils.parse_parameters(parameters) if valid: if id is None: solver = db.Solver() if bin: solver_binary = db.SolverBinary() solver_binary.solver = solver else: solver_binary = None else: if solver_binary: for solver_config in solver_binary.solver_configurations: for pi in solver_config.parameter_instances: db.session.delete(pi) db.session.commit() db.session.delete(solver_config) db.session.commit() if not solver_binary and bin: solver_binary = db.SolverBinary() solver_binary.solver = solver solver.name = name solver.description = description solver.authors = authors solver.user = g.User solver.version = version solver.competition_categories = form.competition_categories.data if solver_binary: solver_binary.binaryName = name solver_binary.runPath = run_path solver_binary.version = version solver_binary.runCommand = form.run_command.data if bin: # new or updated binary solver_binary.binaryArchive = bin solver_binary.md5 = hash.hexdigest() if code: # new or updated code solver.code = code if description_pdf: # new or updated description pdf solver.description_pdf = description_pdf db.session.add(solver) if bin: db.session.add(solver_binary) # on resubmissions delete old parameters if id is not None: for p in solver.parameters: db.session.delete(p) db.session.commit() for p in params: param = db.Parameter() param.name = None if p[0] == '' else p[0] param.prefix = None if p[1] == '' else p[1] param.defaultValue = p[2] or '' param.hasValue = not p[3] # p[3] actually means 'is boolean' param.order = int(p[4]) param.space = p[5] param.solver = solver db.session.add(param) try: db.session.commit() if code: msg = Message("[" + db.label + "][Admin] Code submitted", recipients=[config.DEFAULT_MAIL_SENDER]) msg.body = ("The user %s %s just submitted code for the solver with id %d" % ( g.User.firstname, g.User.lastname, solver.idSolver)) mail.send(msg) except Exception as e: print e db.session.rollback() flash("Couldn't save solver to the database. Please contact an administrator for support.") return render('/accounts/submit_solver.html', database=database, error=error, db=db, id=id, form=form) flash( 'Solver submitted successfully. If you provided a binary, test jobs will be generated within the next minute. You will be notified by email once they are computed. Please check the Results page at any time for the computation progress.') return redirect(url_for('accounts.list_solvers', database=database, user_id=g.User.idUser)) return render('/accounts/submit_solver.html', database=database, error=error, db=db, id=id, form=form)
def register(database): """ User registration """ db = models.get_database(database) or abort(404) form = forms.RegistrationForm() errors = [] if form.validate_on_submit(): if db.session.query(db.User).filter_by(email=form.email.data.lower()) \ .count() > 0: errors.append( "An account with this email address already exists. Please check your e-mail account for the activation link." ) try: captcha = map(int, form.captcha.data.split()) if not utils.satisfies(captcha, session['captcha']): errors.append("Wrong solution to the captcha challenge.") except: errors.append("Wrong format of the solution") if not errors: user = db.User() user.lastname = form.lastname.data user.firstname = form.firstname.data user.password = password_hash(form.password.data) user.email = form.email.data.lower( ) # store email in lower case for easier password reset etc user.postal_address = form.address.data user.affiliation = form.affiliation.data user.verified = False user.accepted_terms = form.accepted_terms.data user.affiliation_type = form.affiliation_type.data user.country = form.country.data hash = hashlib.sha256() hash.update(config.SECRET_KEY) hash.update(user.email) hash.update(str(datetime.datetime.now())) hash.update(user.password) user.activation_hash = hash.hexdigest() db.session.add(user) try: db.session.commit() except Exception: db.session.rollback() errors.append( 'Error while trying to save the account to the database. Please \ contact an administrator.') return render('/accounts/register.html', database=database, db=db, errors=errors, form=form) session.pop('captcha', None) msg = Message("[" + db.label + "] Account activation", recipients=[user.email]) msg.body = "Dear " + user.firstname + " " + user.lastname + ",\n\n" + \ "Please use the following link to activate your account:\n" + \ request.url_root[:-1] + url_for('accounts.activate', database=database, activation_hash=user.activation_hash) mail.send(msg) flash( "Account created successfully. An e-mail has been sent to your account with an activation link." ) return redirect( url_for('frontend.experiments_index', database=database)) # Save captcha to the session. The user will have to provide a solution for # the same captcha that was given to him. random.seed() f = utils.random_formula(2, 3) while not utils.SAT(f): f = utils.random_formula(2, 3) session['captcha'] = f return render('/accounts/register.html', database=database, db=db, errors=errors, form=form)
def submit_solver(database, id=None): """ Form to submit solvers to a database """ db = models.get_database(database) or abort(404) # Disallow submissions of new solvers in phase 4 if db.competition_phase() == 4 and id is None: abort(401) if id is not None: solver = db.session.query(db.Solver).get(id) or abort(404) if solver.user.idUser != g.User.idUser: abort(401) if db.competition_phase() == 4 and solver.competition_frozen: flash( 'This solver was found to be compatible with our execution environment, i.e. has no crashed test runs or test runs with unknown result, and can not be updated anymore. Please contact the organizers if there\'s a reason to submit a new version.' ) return redirect( url_for('accounts.list_solvers', database=database, user_id=g.User.idUser)) solver_binary = solver.binaries[0] if solver.binaries else None form = forms.SolverForm(request.form, solver) if request.method == 'GET': form.parameters.data = utils.parameter_template(solver) form.description_pdf.data = '' form.binary.data = '' form.code.data = '' if solver_binary: form.run_command.data = solver_binary.runCommand form.run_path.data = solver_binary.runPath else: form = forms.SolverForm() form.competition_categories.query = db.session.query( db.CompetitionCategory).all() error = None if form.validate_on_submit(): valid = True # assume valid, try to falsify with the following checks name = form.name.data description = form.description.data version = form.version.data authors = form.authors.data parameters = form.parameters.data run_path = form.run_path.data if id is None and db.session.query(db.Solver) \ .filter_by(name=name, version=version) \ .first() is not None: error = 'Solver with this name and version already exists' valid = False if id is None and not form.code.data and not form.binary.data: error = 'Please provide either a binary or the code (or both).' valid = False bin = None if (id is None or (id is not None and form.binary.data)) and form.binary.data: # if this is a new solver or a resubmission with new binary update binary bin = request.files[form.binary.name].stream.read() hash = hashlib.md5() hash.update(bin) # save the binary in the FS as log store_path = os.path.join( config.UPLOAD_FOLDER, 'solvers', secure_filename(str(g.User.idUser) + '-' + g.User.lastname), 'bin') try: os.makedirs(store_path) except: pass with open(os.path.join(store_path, hash.hexdigest()), 'wb') as f: f.write(bin) if not form.binary.data.filename.endswith('.zip'): tmpfile = StringIO() zip_file = zipfile.ZipFile(tmpfile, 'w', compression=zipfile.ZIP_DEFLATED) zip_file.writestr(form.binary.data.filename, bin) zip_file.close() tmpfile.seek(0) bin = tmpfile.read() run_path = form.binary.data.filename else: if not run_path: error = 'Since your binary is a .zip file, please provide the path of the executable within the archive' valid = False code = None if id is None or (id is not None and form.code.data): code = request.files[form.code.name].stream.read() code_hash = hashlib.md5() code_hash.update(code) # save the code in the FS as log store_path = os.path.join( config.UPLOAD_FOLDER, 'solvers', secure_filename(str(g.User.idUser) + '-' + g.User.lastname), 'code') try: os.makedirs(store_path) except: pass with open(os.path.join(store_path, code_hash.hexdigest()), 'wb') as f: f.write(code) description_pdf = None if id is None or (id is not None and form.description_pdf.data): description_pdf = request.files[ form.description_pdf.name].stream.read() if id is None and not description_pdf: valid = False error = "Please provide a description pdf." params = utils.parse_parameters(parameters) if valid: if id is None: solver = db.Solver() if bin: solver_binary = db.SolverBinary() solver_binary.solver = solver else: solver_binary = None else: if solver_binary: for solver_config in solver_binary.solver_configurations: for pi in solver_config.parameter_instances: db.session.delete(pi) db.session.commit() db.session.delete(solver_config) db.session.commit() if not solver_binary and bin: solver_binary = db.SolverBinary() solver_binary.solver = solver solver.name = name solver.description = description solver.authors = authors solver.user = g.User solver.version = version solver.competition_categories = form.competition_categories.data if solver_binary: solver_binary.binaryName = name solver_binary.runPath = run_path solver_binary.version = version solver_binary.runCommand = form.run_command.data if bin: # new or updated binary solver_binary.binaryArchive = bin solver_binary.md5 = hash.hexdigest() if code: # new or updated code solver.code = code if description_pdf: # new or updated description pdf solver.description_pdf = description_pdf db.session.add(solver) if bin: db.session.add(solver_binary) # on resubmissions delete old parameters if id is not None: for p in solver.parameters: db.session.delete(p) db.session.commit() for p in params: param = db.Parameter() param.name = None if p[0] == '' else p[0] param.prefix = None if p[1] == '' else p[1] param.defaultValue = p[2] or '' param.hasValue = not p[3] # p[3] actually means 'is boolean' param.order = int(p[4]) param.space = p[5] param.solver = solver db.session.add(param) try: db.session.commit() if code: msg = Message("[" + db.label + "][Admin] Code submitted", recipients=[config.DEFAULT_MAIL_SENDER]) msg.body = ( "The user %s %s just submitted code for the solver with id %d" % (g.User.firstname, g.User.lastname, solver.idSolver)) mail.send(msg) except Exception as e: print e db.session.rollback() flash( "Couldn't save solver to the database. Please contact an administrator for support." ) return render('/accounts/submit_solver.html', database=database, error=error, db=db, id=id, form=form) flash( 'Solver submitted successfully. If you provided a binary, test jobs will be generated within the next minute. You will be notified by email once they are computed. Please check the Results page at any time for the computation progress.' ) return redirect( url_for('accounts.list_solvers', database=database, user_id=g.User.idUser)) return render('/accounts/submit_solver.html', database=database, error=error, db=db, id=id, form=form)