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)
Exemple #7
0
    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()
Exemple #23
0
    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()
Exemple #27
0
    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)
Exemple #28
0
 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