def users(self): """ Use pagination to list out users in the database """ page = request.args.get('page', 1) page_size = request.args.get('page_size', 30) # return 30 users at a time max if page_size > 30: page_size = 30 sort_by = User.sort_by(request.args.get('sort', 'created_on'), request.args.get('direction', 'desc')) order_values = '{0} {1}'.format(sort_by[0], sort_by[1]) # a search feature is provided if the client wants to implement one # thats what request.args.get('q') is paginated_users = User.query \ .filter(User.search(request.args.get('q', text('')))) \ .order_by(User.role.asc(), User.payment_id, text(order_values)) \ .paginate(page, page_size, True) dumped_users = users_schema.dump(paginated_users.items) response = { 'data': { 'users': dumped_users, 'has_next': paginated_users.has_next, 'has_prev': paginated_users.has_prev, 'prev_num': paginated_users.prev_num, 'next_num': paginated_users.next_num, } } return response
def users(db): """ Create user fixtures. They reset per test. :param db: Pytest fixture :return: SQLAlchemy database session """ # db.session.query(User).delete() users = [ { 'role': 'admin', 'email': '*****@*****.**', 'username': '******', 'password': '******' }, { 'email': '*****@*****.**', 'username': '******', 'password': '******' } ] for user in users: exists = User.find_by_identity(user['username']) if exists: exists.delete() db.session.add(User(**user)) db.session.commit() return db
def post(self): json_data = request.get_json() if not json_data: response = {'error': 'Invalid input.'} return response, 400 try: data = registration_schema.load(json_data) except ValidationError as err: response = {'error': err.messages} return response, 422 user = User() user.email = data.get('email') user.username = data.get('username') user.password = User.encrypt_password(data.get('password')) user.save() # send verification email with celery as a background task User.init_verify_email(user.email) message = ('Please check the email you registered with for a' ' verification email.') response = {'data': {'created': True, 'message': message}} headers = {'Location': url_for('AuthView:post')} return response, 201, headers
def subscriptions(db): """ Create subscription fixutres. :param db: Pytest fixture :return: SQLAlchemy database session """ subscriber = User.find_by_identity('*****@*****.**') if subscriber: subscriber.delete() db.session.query(Subscription).delete() params = { 'role': 'member', 'email': '*****@*****.**', 'username': '******', 'name': 'Subby', 'payment_id': 'cus_000', 'password': '******', 'active': True } subscriber = User(**params) # User needs to be commited to be able to assign a subscription to it db.session.add(subscriber) db.session.commit() # Create a subscription params = { 'user_id': subscriber.id, 'plan': 'gold' } subscription = Subscription(**params) db.session.add(subscription) # Create the users CC params = { 'user_id': subscriber.id, 'brand': 'Visa', 'last4': '4242', 'exp_date': datetime.date(2019, 6, 1) } credit_card = CreditCard(**params) db.session.add(credit_card) db.session.commit() return db
def test_deserialize_token_tampered(self, token): """ User.deserialize_token returns None if a token has been tampered with """ tampered_token = 'hacked!!{0}'.format(token) user = User.deserialize_token(tampered_token) assert user is None
def delete_users(self): """Option to bulk delete or delete a single user""" json_data = request.get_json() if not json_data: response = {'error': 'Invalid input.'} return response, 400 try: data = bulk_delete_schema.load(json_data) except ValidationError as err: response = {'error': err.messages} return response, 422 ids = User.get_bulk_action_ids(scope=data['scope'], ids=data['bulk_ids'], omit_ids=[current_user.id], query=request.args.get('q', text(''))) # use a celery task to do this in the background from vidme.blueprints.admin.tasks import delete_users delete_users.delay(ids) response = { 'data': { 'deleted': True, 'message': '{0} user(s) were scheduled to be deleted.'.format(len(ids)) } } return response
def get_user(self, username): """Allows an admin to fetch specific user data """ user = User.find_by_identity(username) if user is None: response = {'error': USER_NOT_FOUND} return response, 404 invoices = Invoice.billing_history(user=user) if user.subscription: # get the upcoming invoice from Stripe upcoming = Invoice.upcoming(customer_id=user.payment_id) else: upcoming = None dumped_user = user_detail_schema.dump(user) dumped_invoices = invoices_schema.dump(invoices) response = { 'data': { 'user': dumped_user, 'invoices': dumped_invoices, 'upcoming_invoice': upcoming } } return response
def db(app): """ Set up test database, this only gets executed once per session. :param app: Pytest fixture :return: SQLAlchemy database session """ _db.drop_all() _db.create_all() # Create a single user, a lot of tests will not mutate this user params = { 'role': 'admin', 'email': '*****@*****.**', 'username': '******', 'password': '******', 'active': True } admin = User(**params) _db.session.add(admin) _db.session.commit() return _db
def edit_user(self, username): """ Admins can edit user accounts, for example if the username is offensive/goes against guidelines or update their permissions """ # find the User user = User.find_by_identity(username) if user is None: response = {'error': USER_NOT_FOUND} return response, 404 # load the json data json_data = request.get_json() # check for errors if not json_data: response = {'error': 'Invalid input.'} return response, 400 try: data = admin_edit_user_schema.load(json_data) except ValidationError as err: response = {'error': err.messages} return response, 422 # check if user is the last admin if User.is_last_admin(user, data['role']): response = {'error': 'User is the last admin in the system.'} return response, 400 # is username being changed if user.username != data['username']: existing_username = User.find_by_identity(data['username']) if existing_username is None: user.username = data['username'] else: response = {'error': 'Username is already taken.'} return response, 400 user.role = data['role'] user.save() headers = { 'Location': url_for('AdminView:get_user', username=user.username) } return '', 204, headers
def test_deliver_verification_email(self, token): """Successfully deliver a verification email""" with mail.record_messages() as outbox: user = User.find_by_identity('*****@*****.**') deliver_verification_email(user.id, token) assert len(outbox) == 1 assert token in outbox[0].body
def token(db): """ Serialize a JWS token. :param db: Pytest fixture :return: JWS token """ user = User.find_by_identity('*****@*****.**') return user.serialize_token()
def delete_users(ids): """ Delete users and potentially cancel their subscription. :param ids: List of ids to be deleted :type ids: list :return: int """ return User.bulk_delete(ids)
def ensure_unique_identity(data): """ Ensures that an email and/or username is not already taken :return: data from the request """ user = User.find_by_identity(data) if user: raise ValidationError('{0} already exists.'.format(data)) return data
def test_edit_user(self, subscriptions): """Successfully update a user account and set location headers""" self.authenticate() data = {'role': 'admin', 'username': '******'} response = self.client.put(url_for('AdminView:edit_user', username='******'), json=data) location = response.headers['Location'] assert response.status_code == 204 assert location == url_for('AdminView:get_user', username='******') user = User.find_by_identity('firstSub1') assert user.role == 'admin'
def test_cancel_subscription(self, subscriptions, mock_stripe): """Successfully cancel a user's subscription""" self.authenticate() response = self.client.delete( url_for('AdminView:cancel_subscription', username='******')) data = response.get_json()['data'] assert response.status_code == 200 assert data['deleted'] is True assert data['message'] == 'User\'s subscription has been cancelled.' user = User.find_by_identity('firstSub1') assert user.subscription is None assert user.cancelled_subscription_on <= \ datetime.datetime.now(pytz.utc)
def seed(): """ Seed the database with an initial user. The username, email and password are taken from the app config. :return: User instance """ params = { 'role': 'admin', 'email': app.config['SEED_ADMIN_EMAIL'], 'username': app.config['SEED_ADMIN_USERNAME'], 'password': app.config['SEED_ADMIN_PASSWORD'], 'active': True } return User(**params).save()
def activate_account(self, activation_token): user = User.deserialize_token(activation_token) if user is None: err = 'Your activation token has expired or was tampered with.' return {'error': err}, 400 user.active = True user.save() response = { 'data': { 'activated': True, 'message': 'Your account has been activated.' } } headers = {'Location': url_for('AuthView:post')} return response, 200, headers
def post(self): json_data = request.get_json() if not json_data: response = jsonify({'error': 'Invalid input.'}) return response, 400 try: data = auth_schema.load(json_data) except ValidationError as err: response = jsonify({'error': err.messages}) return response, 422 user = User.find_by_identity(data['identity']) if user and user.authenticated(password=data['password']): if user.is_active(): # identity is used to lookup a user on protected endpoints access_token = create_access_token(identity=user.username) user.update_activity_tracking(request.remote_addr) response = jsonify({'data': {'access_token': access_token}}) # Set the JWTs and the CSRF double submit protection cookies # Clients such as web browsers support cookies and # "set_access_cookies" will set two cookies in the browser, # 1)access_token 2)CSRF token set_access_cookies(response, access_token) return response, 200 else: error = ('This account is not active. If you recently signed' ' up for an account, check your email for a' ' verification link.') return jsonify({'error': error}), 400 response = jsonify({'error': 'Invalid credentials.'}) return response, 401
def cancel_subscription(self, username): """Admins can canel a user's subscription""" user = User.find_by_identity(username) if user is None: response = {'error': USER_NOT_FOUND} return response, 404 if not user.subscription: error = '{0} doesn\'t have an active subscription.'.format( username) response = {'error': error} return response, 400 subscription = Subscription() subscription.cancel(user=user) response = { 'data': { 'deleted': True, 'message': 'User\'s subscription has been cancelled.' } } return response, 200
def test_deserialize_token(self, token): """User.deserialize_token de-serializes a JWS correctly""" user = User.deserialize_token(token) assert user.email == '*****@*****.**'
def test_is_active(self): user = User.find_by_identity('*****@*****.**') assert user.is_active() is True