def resend_activation(): """ Resend the activation token in the user's email. returns: 403 if any errors occur. 200 if successful, and user get the activation mail resent to him. """ req = request.get_json() try: user = (User.query .filter(User.email == req['email']) .one()) if user.is_active: return Error("User is already active", 403)() serializer = URLSafeSerializer(app.config['SECRET_KEY']) activation_token = serializer.dumps(user.email) activation_url = url_for('User.activate_user', activation_token=activation_token, _external=True) Mail(req['email'], subject_data={'name': user.full_name}, html_data={'token': activation_url}, text_data={'name': user.full_name}, template_root=SIGNUP_ACTIVATION ).send() return "" except NoResultFound: return Error("User with that email doesnt exist", 403)()
def start_test(test_id): """ Start a test. If an existing test_attempt that is not complete exists, it is returned. If not, if the user has access to the test, a new test attempt and section attempt(s) is created and returned. :param testID: :return: the id of the test attempt """ try: attempt = ( TestAttempt.query # can be made inner join because section attempts should # exist if question attempt exists .join(TestAttempt.section_attempts).options( contains_eager(TestAttempt.section_attempts)).filter( TestAttempt.test_id == test_id).filter( TestAttempt.user_id == current_user.id).one()) if attempt.is_complete: return Error("Test is already completed", 403, "TAC001")() sorted_section_attempts = sorted(attempt.section_attempts, key=lambda x: x.id) current_section = (filter(lambda x: x.is_complete == False, sorted_section_attempts)) # todo penalize the current_section by the value of # Pinger's time. current_section_id = list(current_section)[0].section_id except NoResultFound: # didn't find existing attempt, create a new one if not Test.user_has_access(current_user, test_id): return Error("Purchase the Test", 400)() current_section_id = TestAttempt.setup_test_attempt( test_id, current_user.id) test = (Test.query.filter(Test.id == test_id).options( load_only(Test.allow_section_jumps)).one()) # finally, update the cookie string = Pinger.push_data_from_data( test_id, current_section_id, test.allow_section_jumps == True, datetime.timestamp(datetime.now()) + Pinger.PING_GRACE, 0) resp = Response() resp.headers["ping"] = string AuditLog.log_start_test_event(user_id=current_user.id, test_id=test_id, current_section_id=current_section_id) return resp
def add_model(): """Add a new network model """ # parse the json request new_model = Model.from_dict(connexion.request.form) try: # parse the attached xml files req_files = connexion.request.files.getlist("files") files = [] for f in req_files: # Validate xml input filestr = f.stream.read() ElementTree.fromstring(filestr) f.stream.seek(0) files.append(f.stream) except ElementTree.ParseError: return Error(code=422, message="Invalid XML files"), 422 # create cimpy objects try: cimpy_data = cimpy.cim_import(files, new_model.version) except Exception: return Error(code=422, message="Invalid CIM files"), 422 new_id = model_db.put_model(new_model, cimpy_data, files) # Return the model as `ModelReply` return ModelReply.from_model(new_model, new_id)
def finish_section(testID, sectionID): try: test_id, section_id, jumps_allowed, _, _ = Pinger.split_pinger_string() except: return Error("No Pinger", 403)() try: test_attempt = (TestAttempt.query.filter( TestAttempt.test_id == test_id).filter( TestAttempt.user_id == current_user.id).filter( TestAttempt.is_complete == False).join( TestAttempt.section_attempts).one()) except NoResultFound: return Error("Data not found", 404)() pass sorted_section_attempts = sorted( test_attempt.section_attempts, key=lambda section_attempt: section_attempt.section_id) current_section_attempt = list( filter( lambda section_attempt: section_attempt.section_id == int( section_id), sorted_section_attempts))[0] section_ids = [section.section_id for section in sorted_section_attempts] current_section_idx = section_ids.index(int(section_id)) should_update = False # if there is an actual next section, # get its id , and update pinger if current_section_idx + 1 < len(section_ids): next_section_idx = section_ids[current_section_idx + 1] should_update = True current_section_attempt.is_complete = True db.session.commit() if should_update: string = Pinger.push_data_from_data( test_id, next_section_idx, jumps_allowed, datetime.timestamp(datetime.now()) + Pinger.PING_GRACE, 0) resp = Response() resp.headers["ping"] = string return resp
def set_key(self, new_key): if self.__class__.exists(new_key): raise Error('%s with key %s already exists' % ( self.__class__.__name__, new_key)) if self.get_key == new_key: pass del BaseModel.objects[self.__class__][self.get_key()] old_key = self.get_key() self._set_key(new_key) if self.get_key() != new_key: raise Error('subclass was expected to change key from %s to %s, ' 'but key is not %s' % ( old_key, new_key, self.get_key())) self.save()
def wrapped(*args, **kwargs): assert len(roles) == 1 and type(roles[0]) is str, \ "first argument is not a string" if not current_user.is_authenticated: return Error("Not Logged in", 400)() query = UserRoles.query.join(UserRoles.role) \ .filter(Role.name == roles[0]) \ .filter(UserRoles.user_id == current_user.id) \ .exists() if not db.session.query(query).scalar(): return Error("Unauthorized", 403)() return f(*args, **kwargs)
def get_tab_change(test_id, date): if not Corporate.can_access_test(CookieHelper.get_corporate_id(), test_id): return Error("No access", 403)() return (Corporate.get_tab_change(CookieHelper.get_corporate_id(), test_id, date))
def get_personality_analysis(test_id, date): if not Corporate.can_access_test(CookieHelper.get_corporate_id(), test_id): return Error("No access", 403)() return (Corporate.get_personality_analysis(CookieHelper.get_corporate_id(), test_id, date))
def get_overview(test_id, date): if not Corporate.can_access_test(CookieHelper.get_corporate_id(), test_id): return Error("No access", 403)() return (Corporate.get_test_performance(CookieHelper.get_corporate_id(), test_id, date))
def get_test_attempt_report(test_id, user_id): if (not Corporate.can_access_test(CookieHelper.get_corporate_id(), test_id) or not Corporate.can_access_user(CookieHelper.get_corporate_id(), user_id) ): return Error("No access", 403)() report = (TestAttemptReport .query .join(TestAttempt, and_(TestAttemptReport.test_attempt_id == TestAttempt.id, TestAttempt.test_id == test_id, TestAttempt.user_id == user_id)) .one() ) test_attempt = (TestAttempt.query .filter(TestAttempt.test_id == test_id) .filter(TestAttempt.user_id == user_id) .one()) report = report.todict() report['tab_change_count'] = test_attempt.focus_lost_count del report['test_attempt_id'] del report['domain_based_ability'] del report['paragraph_writing_ability'] return report
def export_model(id_): """Export model to file Returns an archive containing the grid data in CIM formatted files and profile files that might have been imported previously. :param id: Model id :type id: int :rtype: file """ model_record = model_db.get_model(id_) if isinstance(model_record, model_db.record): model_files = model_record.files # TODO: Which Profiles? Profile in Request? return cimpy.cimexport.generate_xml( model.cimobj, "cgmes_v2_4_15", cimpy.cgmes_v2_4_15.Base.Profile["EQ"], ["DI", "EQ", "SV", "TP"], ) else: return ( Error( code=404, message="No model with id: " + str(id_) + " found in database" ), 404, )
def get_question_details(testID, sectionID, questionID): """ Get question details for a questionID. This requires the test attempt for that user and the test to exist (along with section attempts) If the question has choices, they will be returned too FIXME there is a security vulnerability for non jumpable exams, the user may get unauthorized access to future sections' question details (that he will be allowed to attempt in the future) :param testID: :param sectionID: :param questionID: :return: """ try: if not Question.does_user_have_access(testID, sectionID, questionID, current_user.id): raise NoResultFound question = fetch_question(questionID) except NoResultFound: return Error("Unable to find data", 403)() return question
def get_question_solutions(testID, sectionID, questionID): """ Get question solutions details for a questionID. This requires the test attempt for that user and the test to exist (along with section attempts) If the question has choices, they will be returned too :param testID: :param sectionID: :param questionID: :return: """ try: if not TestAttempt.can_user_view_solutions(current_user.id, testID): raise NoResultFound question = fetch_solutions(questionID) except NoResultFound: return Error("Unable to find data", 403)() return question
def log(): log = { 'url': request.args.get('url'), 'error': request.args.get('error'), 'filename': request.args.get('filename'), 'line': request.args.get('line'), 'useragent': request.args.get('useragent') } log['host'] = None if log['url'] is not None: match = re.findall('^http:\/\/[\w.:-]+', log['url']) if match: log['host'] = match[0] if log['filename'] is not None: log['filename'] = log['filename'][:500] if log['line'] is not None: log['line'] = int(log['line']) error = Error(url=log['url'], host=log['host'], error=log['error'], filename=log['filename'], line=log['line'], useragent=log['useragent']) error.put() response = make_response('{callback}({data})'.format(callback=str( request.args.get('callback')), data=json.dumps(log))) response.mimetype = 'application/json' return response
def log_step_activity(user, new_step_count): """ Log a walking activity containing the number of steps specified in new_step_count. Return the new step count (0 if the POST request is unsuccessful). :param background.models.User user\n :param int new_step_count """ url = "{}/activities.json".format(BASE_URL) now = datetime.now() params = { "activityId": '90013', "startTime": now.strftime("%H:%M:%S"), "durationMillis": 3600000, "date": now.strftime("%Y-%m-%d"), "distance": new_step_count, "distanceUnit": "steps" } auth_headers = {"Authorization": "Bearer " + user.fb_token} response = requests.post(url, headers=auth_headers, params=params) if response != 201: return new_step_count else: error = Error(summary="Couldn't log step activity.", origin="background/fitbit.py, in log_step_activity", message=response.json()["errors"][0]["message"], user=user) session.add(error) session.commit() return 0
def forgot_password(): """ Sends Reset Password link to User's email address. User can change his/her password through the link mentioned in the Email. It won't be an endpoint, it will be a webpage :return: 403 if any errors, else return 200 """ req = request.get_json() serializer = URLSafeSerializer(app.config['SECRET_KEY']) try: user = User.query \ .filter(User.email == req['email']) \ .filter(User.is_active) \ .one() token = serializer.dumps(req['email']) reset_password_link = f"{request.url_root}reset_password?token={token}" Mail(user.email, subject_data={'name': user.full_name}, html_data={'token': reset_password_link}, text_data={'token': reset_password_link}, template_root=FORGOT_PASSWORD ).send() return "" except NoResultFound: return Error('Invalid Email Address', 403)()
def get_test(testID): """ Get Instruction html of a particular Test. This will return the html only if the user has access to a test. """ # left outer join on tests -> orders -> ordertest. if user has a # paid order it will be accessible by test.order. try: # if not Test.user_has_access(current_user, testID): # raise NoResultFound test = (Test.query .options( load_only(Test.id, Test.name, Test.character, Test.price, Test.instruction_html, Test.type, Test.allow_section_jumps)) .filter(Test.is_active == 1) .filter(Test.id == testID) .one()) except NoResultFound: return Error("You do not have access to this test", 403)() return test
def from_model(cls, model, id) -> 'ModelReply': """Converts the Model into a ModelReply """ if model is not None: return ModelReply(id, model.name, model.profiles, model.version) else: return Error(code=404, message="Model not found"), 404
def test(test_id): try: attempt = ( TestAttempt.query.join(TestAttempt.section_attempts).join( SectionAttempt.question_attempts).options( contains_eager(TestAttempt.section_attempts).load_only( SectionAttempt.section_id, SectionAttempt.is_complete, SectionAttempt.time_spent, SectionAttempt.score).contains_eager( SectionAttempt.question_attempts).load_only( QuestionAttempt.question_id, QuestionAttempt.choice_id, QuestionAttempt.tita_choice, QuestionAttempt.attempt_status, QuestionAttempt.question_id, QuestionAttempt.chosen_language_id, QuestionAttempt.time_spent, QuestionAttempt.score, # todo load this through an api if its too slow QuestionAttempt.long_answer)). filter(TestAttempt.test_id == test_id).filter( TestAttempt.user_id == current_user.id).one()) except NoResultFound: return Error("Please start the test first", 403)() return attempt
def activate_user(activation_token): """ Activate a particular user, based on activation token. This sets the is_active field to true in the db. :param activation_token: the token that user should have in email :return: 403 if any errors, else redirect to root , and user is activated """ serializer = URLSafeSerializer(app.config['SECRET_KEY']) try: email = serializer.loads( activation_token ) user = User.query \ .filter(User.email == email) \ .one() user.is_active = True db.session.commit() # Mail(user.email, # subject_data={'name': user.full_name}, # html_data={'name': user.full_name}, # text_data={'name': user.full_name}, # template_root=WELCOME_MAIL # ).send() activate_user_to_mautic.delay(user.email) return redirect(f"{request.url_root}login") except (NoResultFound, BadSignature): return Error('Invalid Token', 403)()
def delete_model(model_id): """Delete a network model :param id: Model id :type id: int :rtype: Model """ model_bytes = redis_connection.get(model_id) if model_bytes != None: print("MODEL_BYTES: ", model_bytes) model = eval(model_bytes.decode("utf-8")) model["id"] = int(model_id) else: return ( Error( code=404, message="Cannot delete model with id: " + str(model_id) + ", not found in database", ), 404, ) files_len_bytes = redis_connection.get(str(model_id) + "_files_len") files_len = int(files_len_bytes.decode("utf-8")) redis_connection.delete(str(model_id)) redis_connection.delete(str(model_id) + "_cimpy") redis_connection.delete(str(model_id) + "_files_len") for index in range(files_len): redis_connection.delete(str(model_id) + "_file_" + str(index)) redis_connection.srem("models", model_id) return model
def get_corporate(corporate_slug): try: corporate = Corporate.query \ .filter(Corporate.slug == corporate_slug) \ .one() return corporate except NoResultFound: return Error("Invalid Corporate Slug", 400)()
def error_track(): d = request.form logging.info(request.form) Error(msg=d['msg'], url=d['url'], line=d['line'], user=users.get_current_user()).put() return 'thanks'
def wrapped(*args, **kwargs): try: if request.json: handle_json(validator) elif request.form: handle_form(validator) else: return Error(message="Invalid request", http_code=400)() except BaseError as e: return Error(message="Invalid request", http_code=400, additional=e.to_primitive())() return f(*args, **kwargs)
def __setattr__(self, key, value): if key == 'server': if self.is_user(): raise Error('user XOR server must be passed to Actor') if value.actor: raise Error('server already has an actor set') self._server = value self._server.actor = self elif key == 'user': if self.is_server(): raise Error('user XOR server must be passed to Actor') if hasattr(value, 'actor'): raise Error('user already has an actor set') self._user = value self._user.actor = self else: super(BaseModel, self).__setattr__(key, value)
def create_order(): """ Creates Order row. Updates order with Razorpay Order ID. Inserts rows in Item tables with the Order ID :return: {'id': order.id, 'rp_order_id': razorpay_order_id} """ req = request.get_json() test_ids = req['tests'] if req['tests'] is not None else [] promo = req['promo_code'] # will be null if not present total_amount = 0 promo_id = None razorpay_order_id = None # set to null by default tests = Test.query \ .filter(Test.id.in_(test_ids)) \ .options(load_only('price')) \ .all() for test in tests: total_amount += test.price total_amount = max(0, total_amount) if promo: try: promo_amt, promo_id = PromoCode.consume_promo_code( promo, current_user.id) total_amount -= promo_amt except ValueError as e: return Error(str(e), 400)() order = Order(status=OrderStatusTypes.created, amount=total_amount, promo_code_id=promo_id, user_id=current_user.id) db.session.add(order) db.session.flush() if total_amount > 0: razorpay_order_id = Razorpay.create_order(order.id, total_amount) else: order.status = OrderStatusTypes.paid # mark free order as paid order.rp_order_id = razorpay_order_id # This adds rows to OrderTest which is important for User to get # access when Payment goes through for test in tests: test_id = test.id order_test = OrderTest(order_id=order.id, test_id=test_id) db.session.add(order_test) db.session.commit() return {'id': order.id, 'rp_order_id': razorpay_order_id}
def get_promo_codes(): """ Returns all available Promo Codes in database :return: [promo.todict()] """ try: promo_codes = PromoCode.query.all() return promo_codes except NoResultFound: return Error('Invalid Promo Code', 400)()
def save(self): exists = self.__class__.exists(self.get_key()) not_self = exists and self.__class__.get(self.get_key()) is not self if not_self: raise Error('%s with key %s already exists but ' 'is not the object to be saved' % ( self.__class__.__name__, self.get_key() )) if not self.__class__ in BaseModel.objects: BaseModel.objects[self.__class__] = {} BaseModel.objects[self.__class__][self.get_key()] = self
def get_promo_code(code): """ Fetch details based on Promo Code :param code: :return: promo.todict() """ try: promo_code = PromoCode.query.filter(PromoCode.promo_code == code).one() return promo_code except NoResultFound: return Error('Invalid Promo Code', 400)()
def __init__(self, name): if not self.is_valid_name(name): raise Error('Erroneous channel name') raw = abnf.parse(name, abnf.channel) self.mode = ChannelMode self.prefix = raw[0] self.id = raw[1] if self.prefix == '!' else None self.name = raw[2] if self.prefix == '!' else raw[1] self.users = [] self.topic = None