def test_reset_password_token_resets_password(self): with app.app_context(): found_user = UserDAO().get(self.test_uid) self.assertIsNotNone(found_user) original_token = found_user.reset_token original_password = found_user.password data = { 'email': self.test_user_email, } response = self.test_client.put( '/users/reset_password', content_type='application/json', data=json.dumps(data), ) self.assertEqual(response.status_code, HTTPStatus.OK) found_user = UserDAO().get(self.test_uid) self.assertIsNotNone(found_user) self.assertIsNotNone(found_user.reset_token) self.assertNotEqual(found_user.reset_token, original_token) # Now reset the password and verify it worked.. data = { 'token': found_user.reset_token, 'plaintext_password': '******' } response = self.test_client.post( '/users/reset_password', content_type='application/json', data=json.dumps(data), ) self.assertEqual(response.status_code, HTTPStatus.OK) found_user = UserDAO().get(self.test_uid) self.assertIsNotNone(found_user) self.assertIsNone(found_user.reset_token) self.assertNotEqual(found_user.password, original_password) # Verify new password works. self.assertTrue( User._bcrypt_compare(data['plaintext_password'], found_user.password)) # Kind of a duplicate, but verify old doesn't work. self.assertFalse( User._bcrypt_compare(data['plaintext_password'], original_password))
def regenerate_reset_password_token(self, email): """ Regenerates a reset password token and sends another email. :param str email: The email of the user who forgot/lost their reset password email token. :rtype: str :return: The newly generated token. """ try: new_token, user = UserDAO().regenerate_token(email, 'reset_token') MailQueueDAO().push_to_queue( '*****@*****.**', user.email, 'Please verify your account', """ Your new account at Kronikl.io is now available. Please go to <a href="http://{0}/#/reset_password/{1}">Reset my Password</a> to activate your account. """.format( 'localhost:8080' if current_app.config['ENVIRONMENT'] == 'Dev' else 'app.kronikl.io', new_token)) return new_token except DAOException as e: logging.error( 'Failed to regenerate reset token with exception: {0}'.format( e)) raise FacadeException('Failed to regenerate reset token.', e.status_code)
def create_user(self, email, password, local_tz, username): """ :param str email: The user's email to be registered with the account. :param str password: The desired password (not yet hashed). :param str local_tz: The local TZ of the user :param str username: The desired username for the new user. :rtype: UserTable :return: The UserTable row or None """ try: new_user = UserDAO().create_new_user(email, password, local_tz, username, skip_commit=True) logging.info( 'Added new user to database as a regular user: {0}'.format( new_user, )) self._send_verification_email( new_user.email, new_user.verify_token, ) db.session.commit() return new_user except Exception as e: db.session.rollback() raise e
def _assert_no_duplicate_submerchant(self, user_id): """ Handles asserting that a user doesn't already have a submerchant. :param str user_id: The user's UUID :raises: FacadeException """ try: UserDAO().get(user_id) except DAOException as e: logging.warning( 'Requested user {0} does not exist with exception: {1}'.format( user_id, e, )) raise FacadeException('Requested user does not exist.') merchant_dao = MerchantDAO() found_submerchant = merchant_dao.get_submerchant_by_id(user_id) if found_submerchant is not None: logging.warning( 'Attempted duplicate submerchant for user: {0}'.format( user_id, )) raise FacadeException( 'You already have a submerchant account created.')
def setUpClass(cls): with app.app_context(): db.drop_all() db.create_all() cls.test_client = app.test_client() cls.test_dao = UserDAO() scheduling = User( "*****@*****.**", "testpw", 'US/Central', 'scheduling_user', ) scheduled = User( "*****@*****.**", "testpw", 'US/Central', 'scheduled_user', ) cls.scheduling_uid = scheduling.public_id cls.scheduled_uid = scheduled.public_id db.session.add(scheduling) db.session.add(scheduled) db.session.commit() User.query.filter_by( public_id=cls.scheduled_uid ).update({ 'sixty_min_price': 15 }) db.session.add(Submerchant( cls.scheduled_uid, 'testaccountid', 'firstName', 'LastName', 'email', datetime.utcnow() + timedelta(days=-365*20), 'address_street', 'address_locality', 'address_region', 'address_zip', )) new_schedule = Schedule( datetime.utcnow(), datetime.utcnow() + timedelta(minutes=60), cls.scheduled_uid, 'US/Central' ) db.session.add(new_schedule) db.session.commit() cls.new_schedule_id = new_schedule.id
def delete(self, user_id): user_info = UserDAO().delete(user_id) logging.info( 'Successfully deleted user {0} for requesting user.'.format( user_id)) return jsonify(UserMarshal().dump(user_info).data)
def setUpClass(cls): with app.app_context(): app.config['TESTING'] = True db.drop_all() db.create_all() cls.test_client = app.test_client() cls.test_dao = UserDAO()
def login(self, user_challenge, plaintext_password): """ Handles logging in a user. :param str user_challenge: The email/username to get the user by :param str plaintext_password: The password to compare against. :raises: BadPasswordException :rtype: UserTable :return: The logged in user. """ user_dao = UserDAO() user_info = user_dao.get_by_email_or_username(user_challenge) if user_info is None: raise DAOException("Invalid email. User does not exist.") if user_info.compare_password(plaintext_password): return user_info raise DAOException("Invalid credentials. Try again.")
def get_user_by_id(self, user_id): """ Retrieves a single user by its user id and attaches other necessary metadata. :param str user_id: The User ID to look up. :rtype: UserTable :return: The UserTable row or None. """ found_user = UserDAO().get(user_id) return self._add_submerchant_to_user(found_user)
def get_user_by_email(self, email): """ Retrieves user info by the user's email and other necessary metadata. :param str email: The user to retrieve by email. Emails are unique so this is a safe retrieval. :rtype: UserTable :return: The UserTable row or None """ found_user = UserDAO().get_by_email(email) return self._add_submerchant_to_user(found_user)
def regenerate_verification_token(self, email): """ Handles regenerating a user's verification token so that they can log in. :param str email: The user's email. """ token, found_user = UserDAO().regenerate_token(email, 'verify_token') logging.info('Regenerated user token for email: {0}'.format(email)) self._send_verification_email(found_user.email, token)
def post(self): arg_fields = { 'token': String(required=True), } args = parser.parse(arg_fields) validated_user = UserDAO().verify_token(args['token']) logging.info('Successfully validated token {0} for user {1}.'.format( args['token'], validated_user, )) return jsonify(UserMarshal().dump(validated_user).data)
def test_reset_password(self): with app.app_context(): found_user = UserDAO().get(self.test_uid) self.assertIsNotNone(found_user) original_token = found_user.reset_token data = { 'email': self.test_user_email, } response = self.test_client.put( '/users/reset_password', content_type='application/json', data=json.dumps(data), ) self.assertEqual(response.status_code, HTTPStatus.OK) found_user = UserDAO().get(self.test_uid) self.assertIsNotNone(found_user) self.assertIsNotNone(found_user.reset_token) self.assertNotEqual(found_user.reset_token, original_token)
def test_regenerate_token(self): with app.app_context(): found_user = UserDAO().get(self.test_uid3) self.assertIsNotNone(found_user) original_token = found_user.verify_token data = { 'email': self.test_user_email3, } response = self.test_client.put( '/users/verify'.format(self.test_uid3), content_type='application/json', data=json.dumps(data), ) self.assertEqual(response.status_code, HTTPStatus.OK) found_user = UserDAO().get(self.test_uid3) self.assertIsNotNone(found_user) self.assertIsNotNone(found_user.verify_token) self.assertNotEqual(found_user.verify_token, original_token)
def post(self): """ Reset a users password. """ arg_fields = { 'token': String(required=True), 'plaintext_password': String(required=True) } args = parser.parse(arg_fields) validated_user = UserDAO().reset_user_password(**args) logging.info('Successfully validated token {0} for user {1}.'.format( args['token'], validated_user, )) return jsonify(UserMarshal().dump(validated_user).data)
def test_token_verification_fail_invalid_token(self): with app.app_context(): data = { 'token': 'asldkfjalksdjf', } response = self.test_client.post( '/users/verify'.format(self.test_uid2), content_type='application/json', data=json.dumps(data), ) self.assertEqual(response.status_code, HTTPStatus.NOT_FOUND) found_user = UserDAO().get(self.test_uid2) self.assertIsNotNone(found_user) self.assertIsNotNone(found_user.verify_token) self.assertFalse(found_user.is_validated)
def setUpClass(cls): with app.app_context(): db.drop_all() db.create_all() cls.test_client = app.test_client() cls.test_dao = UserDAO() test_user = User( '*****@*****.**', 'testpw', 'US/Central', 'auth_test_user', ) db.session.add(test_user) db.session.commit() cls.scheduled_uid = test_user.public_id
def setUpClass(cls): with app.app_context(): db.drop_all() db.create_all() cls.test_client = app.test_client() cls.test_dao = UserDAO() test_user = User( '*****@*****.**', 'testpw', 'US/Central', 'test5', ) cls.test_user_token = test_user.verify_token cls.test_uid = test_user.public_id db.session.add(test_user) db.session.commit()
def test_token_verification(self): with app.app_context(): data = { 'token': self.test_user_token, } response = self.test_client.post( '/users/verify'.format(self.test_uid), content_type='application/json', data=json.dumps(data), ) self.assertEqual(response.status_code, HTTPStatus.OK) self.assertIsNotNone(response) found_user = UserDAO().get(self.test_uid) self.assertIsNotNone(found_user) self.assertIsNone(found_user.verify_token) self.assertTrue(found_user.is_validated)
def put(self, user_id): arg_fields = { 'email': String(), # NOTE: If plaintext_password is provided, current_password must # also be provided. 'plaintext_password': String(), 'current_password': String(), 'five_min_price': Float(), 'fifteen_min_price': Float(), 'thirty_min_price': Float(), 'sixty_min_price': Float(), } args = parser.parse(arg_fields) user_info = UserDAO().put(user_id, **args) logging.info('Successfully updated {0} for user {1}'.format( args.keys(), user_id)) return jsonify(UserMarshal().dump(user_info).data)
def setUpClass(cls): with app.app_context(): db.drop_all() db.create_all() cls.test_client = app.test_client() cls.test_dao = UserDAO() test_user = User( "*****@*****.**", "testpw", 'US/Central', 'test-verify', ) test_user2 = User( "*****@*****.**", "testpw", 'US/Central', 'test-verify2', ) test_user3 = User( "*****@*****.**", "testpw", 'US/Central', 'test-verify3', ) cls.test_user_token = test_user.verify_token cls.test_uid = test_user.public_id cls.test_user2_token = test_user2.verify_token cls.test_uid2 = test_user2.public_id cls.test_user_email3 = test_user3.email cls.test_uid3 = test_user3.public_id db.session.add(test_user) db.session.add(test_user2) db.session.add(test_user3) db.session.commit()
def setUpClass(cls): with app.app_context(): db.drop_all() db.create_all() cls.test_client = app.test_client() cls.test_dao = UserDAO() test_user = User( "*****@*****.**", "testpw", 'US/Central', 'test', ) deleted_user = User( "*****@*****.**", "testpassword", 'US/Central', 'delete-test', ) deleted_user.is_deleted = True user_to_delete = User( "*****@*****.**", "testpw", 'US/Central', 'user-to-delete', ) cls.test_uid = test_user.public_id cls.deleted_uid = deleted_user.public_id cls.to_delete_uid = user_to_delete.public_id db.session.add(MasterMerchant('clarksoftware')) db.session.add(test_user) db.session.add(deleted_user) db.session.add(user_to_delete) db.session.commit()
def __init__(self, user_id, first_name, last_name, street_address, locality, region, postal_code, country_code_alpha2, is_default=False, extended_address=None): super().__init__() try: self.user_id = UserDAO().get(user_id).id except DAOException as e: logging.error( 'Failed to get user by pub ID {0} w/ exc of {1}'.format( user_id, e, )) raise TableException('Failed to find requested user.') except AttributeError as e: logging.error('Requested user ({0}) does not exist when ' 'creating new address.'.format(user_id, )) raise TableException(e) self.first_name = first_name self.last_name = last_name self.street_address = street_address self.locality = locality self.region = region self.postal_code = postal_code self.country_code_alpha2 = country_code_alpha2 self.is_default = is_default if extended_address is not None and extended_address != '': self.extended_address = extended_address
def update_address(self, address_id, user_public_id, **args): """ Handles updating any fields within the address :return: """ address = self.get_by_public_id(address_id, user_public_id) to_update = {} for k, v in args.items(): to_update[k] = v user = UserDAO().get(user_public_id) if len(to_update.keys()) > 0: db.session.query(Address).filter_by( is_deleted=False, public_id=address_id, user_id=user.id, ).update(to_update) db.session.commit() return address
def setUpClass(cls): with app.app_context(): app.config['TESTING'] = True db.drop_all() db.create_all() cls.test_client = app.test_client() cls.test_dao = UserDAO() test_user = User( "*****@*****.**", "testpw", 'US/Central', 'test', ) cls.test_uid = test_user.public_id db.session.add(test_user) db.session.commit() cls.schedule_ids = [] for i in range(10): start_time = datetime.utcnow() end_time = datetime.utcnow() + timedelta(minutes=60) if i >= 7: start_time = datetime.utcnow() + timedelta(minutes=120) end_time = datetime.utcnow() + timedelta(minutes=180) new_schedule = Schedule(start_time, end_time, cls.test_uid, 'US/Central') db.session.add(new_schedule) db.session.commit() cls.schedule_ids.append(new_schedule.public_id)
def __init__(self): self.customer_facade = CustomerFacade() self.customer_dao = CustomerDAO() self.subscription_integration = BraintreeSubscription() self.user_dao = UserDAO() self.subscription_dao = SubscriptionDAO()
def issue_new_payment(self, event, nonce, address): """ Issues a new payment w/in Braintree. :param EventTable event: The event that must be paid for. :param str nonce: The nonce which signifies which payment method is to be used. :param AddressTable address: The address information to be used whenever issuing a payment. :rtype: PaymentTable :return: The newly created payment. """ try: submerchant = MerchantDAO().get_submerchant_by_id( event.scheduled_user_id) except DAOException as e: logging.error('Invalid event ({0}) issued, no submerchant ' '({1}). Exception of: {2}.'.format( event.public_id, event.scheduled_user_id, e, )) raise DAOException(e) if submerchant is None: logging.error( 'Failed to retrieve submerchant by public ID {0} for a new ' 'event.'.format(event.scheduled_user_id)) raise FacadeException('Invalid requested user. Contact support.') try: # TODO(ian): This can be refactored to use # EventDAO().get_event_by_id and retrieve all the info in 1 query. new_transaction = BraintreeTransactions().create_transaction( submerchant, event.calculate_total_price( event.duration, UserDAO().get(event.scheduled_user_id), ), nonce, UserDAO().get(event.scheduling_user_id), address, ) if isinstance(new_transaction, ErrorResult): logging.error('Received error result {0} when creating new ' 'transaction for event {1}'.format( new_transaction, event)) raise FacadeException('Failed to complete transaction.') return BraintreePaymentsDAO().insert_new_transaction( submerchant, event.total_price, event.calculate_service_fee(submerchant), event, skip_commit=True, ) except Exception as e: db.session.rollback() logging.error( 'Exception encountered while creating and inserting ' 'transaction: {0}.'.format(e), ) raise FacadeException(e)
def wrapper(*args, **kwargs): if kwargs.get('user_id', False): return __authorize_uri(f, args, kwargs) if kwargs.get('email', False): user = UserDAO().get_by_email(kwargs['email']) return __authorize_uri(f, args, kwargs, user_id=user.public_id)
def setUpClass(cls): with app.app_context(): db.drop_all() db.create_all() cls.test_client = app.test_client() cls.test_dao = UserDAO() scheduling = User( "*****@*****.**", "testpw", 'UTC', 'scheduling_user1', ) scheduled = User( "*****@*****.**", "testpw", 'UTC', 'scheduled_user2', ) cls.scheduling_uid = scheduling.public_id cls.scheduled_uid = scheduled.public_id db.session.add(scheduling) db.session.add(scheduled) db.session.commit() default_address = Address( cls.scheduling_uid, 'first-default', 'last-default', 'street address1', 'Madison', 'WI', '53703-def', 'US', is_default=True, extended_address=None ) db.session.add(default_address) db.session.commit() User.query.filter_by( public_id=cls.scheduled_uid ).update({ 'sixty_min_price': 15 }) db.session.commit() db.session.add(Submerchant( cls.scheduled_uid, '3bX9oSVaocidZMxWGGMybj', 'firstName', 'LastName', 'email', datetime.utcnow() + timedelta(days=-365*20), 'address_street', 'address_locality', 'address_region', 'address_zip', )) new_schedule = Schedule( datetime.utcnow(), datetime.utcnow() + timedelta(minutes=60), cls.scheduled_uid, 'UTC' ) db.session.add(new_schedule) db.session.commit() cls.new_schedule_id = new_schedule.id
def create_user_as_submerchant(self, email, password, local_tz, submerchant): """ Handles creating a user and a submerchant at the same time. If either fails, nothing is committed to DB and rolled back. :param str email: The user's email to be registered with the account. :param str password: The desired password (not yet hashed). :param str local_tz: The local TZ of the user :param dict submerchant: A nested structure which defines all the info required to create a submerchant. :rtype: UserTable :return: The UserTable row or None """ try: new_user = UserDAO().create_new_user(email, password, local_tz, skip_commit=True) logging.info( 'Added new user to database as a submerchant: {0}'.format( new_user, )) new_address = AddressDAO().create_address( new_user.public_id, submerchant['individual']['first_name'], submerchant['individual']['last_name'], submerchant['individual']['address']['street_address'], submerchant['individual']['address']['locality'], submerchant['individual']['address']['region'], submerchant['individual']['address']['postal_code'], submerchant['individual']['address']['country_code_alpha2'], is_default=submerchant['individual']['address']['is_default'], skip_commit=True, ) del submerchant['individual']['address']['country_code_alpha2'] del submerchant['individual']['address']['is_default'] logging.info( 'Added new address to database as a submerchant: {0}'.format( new_address, )) new_submerchant = SubmerchantFacade().create_submerchant( submerchant, new_user.public_id, skip_commit=True, ) logging.info('Added new submerchant: {0}'.format( new_submerchant, )) MailQueueDAO().push_to_queue( new_user.email, '*****@*****.**', 'New Kronikl.io account verification', """ Your new account at Kronikl.io is now available. Please go to <a href="http://{0}/verify?q={1}">Verify my account</a> to activate your account. """.format( 'localhost:8080' if current_app.config['ENVIRONMENT'] == 'Dev' else 'app.kronikl.io', new_user.verify_token, ), ) db.session.commit() return new_user except Exception as e: db.session.rollback() raise e