def test_create_user(test_client, admin_user):
    """ Test for successful creation of a new user by an admin and for presense of user in the database  """
    response_login = test_client.post('/login',
                                      data=dict(email=admin_user.email,
                                                password="******"),
                                      follow_redirects=True)
    response_login_json = response_login.get_json()
    header = {
        'Authorization':
        'Bearer {}'.format(response_login_json["access_token"])
    }

    response_create = test_client.post('/admin/create_new_user',
                                       data=dict(email="*****@*****.**",
                                                 fullname="New User",
                                                 admin="True",
                                                 password="******"),
                                       headers=header,
                                       follow_redirects=True)
    response_create_json = response_create.get_json()
    assert b"created successfull" in response_create.data
    assert response_create.status_code == 201
    assert Users.find_by_email("*****@*****.**") != None

    db.session.delete(Users.find_by_email("*****@*****.**"))
    db.session.commit()
예제 #2
0
    def patch(self) -> (str, int):
        """
		API that allows a user change their password in the users table
		Parameters can be passed using a PATCH request that contains a JSON
		with the following fields:
		:param email: users email address
		:param password_old: users current password
		:param password_new: users new password that they want to replace
							 password_old
		:type email: string
		:type password_old: string
		:type password_new: string
		:return: A message that indicates whether a user's password has been
				updated. If they have not, the message indicates why not.
		:rtype: JSON
		"""
        args = self.parser.parse_args()
        current_user = Users.find_by_email(args['email'])  #t

        if current_user and Users.verify_hash(
                args['password_old'].encode("utf8"),
                current_user.password.encode("utf8")):
            current_user.password = Users.generate_hash(
                args["password_new"].encode("utf8")
            ).decode(
                "utf8"
            )  # decode necessary so that string (and not binary) is stored in the DB
            current_user.commit()
            return {"message": "Password has been updated"}, 200
        else:
            return {"message": "Incorrect credentials. Please Try again"}, 403
예제 #3
0
    def post(self) -> (str, int):
        """
        API resource class which deletes a user from the database

        Parameters can be passed using a DELETE request that contains a JSON with the following fields:
        :required: valid access JWT where the admin claim has to be true
        :param email: users email address
        :type email: str
        :return: An empty string and a 204 response on success or an error message and relevant status code when unsuccessful
        """
        args = self.delete_reqparser.parse_args()

        # User needs admin rights to continue
        if not get_jwt_claims()['admin']:
            abort(HTTPStatus.FORBIDDEN.value,
                  error="administration privileges required")

        # Get user instance
        user = Users.find_by_email(args["email"])

        if not user:
            return abort(HTTPStatus.BAD_REQUEST.value, error='user not found')

        try:
            # Remove the user
            user.delete()
            user.commit()
        except exc.SQLAlchemyError as e:
            logging.critical(e,
                             HTTPStatus.BAD_REQUEST.value,
                             error="User not removed")
            abort(HTTPStatus.BAD_REQUEST.value, error="User not removed")

        return "", 204
    def post(self) -> (str, int):
        """
        API resource class which updates a users admin and/or activated field
        Parameters can be passed using a POST request that contains a JSON with the following fields:
        :required: valid access JWT where the admin claim has to be true
        :param email: users email address
        :param activated: the value of the user's activated field
        :param admin: whether the the value of the user's activated field
        :type email: str
        :type activated: str
        :type admin: str
        :return: The user's credentials on success or an error message and corresponding status code when unsuccessful
        """
        args = self.post_reqparser.parse_args()

        # User needs admin rights to continue
        if not get_jwt_claims()['admin']:
            abort(HTTPStatus.FORBIDDEN.value,
                  error="administration privileges required")

        # Get user instance
        user = Users.find_by_email(args["email"])
        if not user:
            return abort(HTTPStatus.BAD_REQUEST.value, error='User not found')

        if "activated" in args:
            user.activated = inputs.boolean(args["activated"])

        if "admin" in args:
            user.admin = inputs.boolean(args["admin"])

        # Save changes to user permissions
        user.save()
        user.commit()
        return user.json(), HTTPStatus.OK.value
def test_edit_user(test_client, admin_user, dummy_user):
    """ Test that the changes a user makes to their fullname persists to the database """
    response_login = test_client.post('/login',
                                      data=dict(email=admin_user.email,
                                                password="******"),
                                      follow_redirects=True)
    response_login_json = response_login.get_json()
    header = {
        'Authorization':
        'Bearer {}'.format(response_login_json["access_token"])
    }

    response_change = test_client.post('/admin/edit_user',
                                       data=dict(email=dummy_user.email,
                                                 fullname="Not a dummy",
                                                 password="******",
                                                 admin=False,
                                                 activated=False),
                                       headers=header,
                                       follow_redirects=True)
    assert response_change.status_code == 200
    changed_user = Users.find_by_email(dummy_user.email)
    assert changed_user.fullname == "Not a dummy"
    assert Users.verify_hash("new password".encode("utf8"),
                             dummy_user.password.encode("utf8")) == True
    assert changed_user.admin == False
    assert changed_user.admin == False
def test_create_user() -> NoReturn:
    """tests the user creation"""
    global dependencies
    new_user = dependencies.get_dummy_user()
    same_user = Users.find_by_email(new_user.email)
    assert same_user is new_user
    new_user.delete()
    new_user.commit()
 def post(self) -> (str,int):
     """
     POST requests that creates a new valid access JWT for the requesting user
     :required: A valid refresh JWT in the Authorization Header in the format - Bearer <JWT>
     :return: The user's corresponding access JWT
     :rtype: JSON
     """  
     current_user = get_jwt_identity() # extracts the users identity from the refresh token
     current_user = Users.find_by_email(current_user)
     access_token = create_access_token(identity = current_user)
     return {'access_token': access_token}, 200
    def test_forgot_password(self):
        """
        Test forgot password sets user's password to a system generated
        password
        """

        forgotten_password = self.dummy_user.password
        response = self.testing_client.post('/forgot_password', data=dict(
            email=self.dummy_user.email))
        self.assertIn(b"success", response.data)
        self.assertEquals(response.status_code, 200)
        updated_user = Users.find_by_email(self.dummy_user.email)
        self.assertNotEqual(updated_user.password, forgotten_password)
예제 #9
0
    def post(self) -> (str, int):
        """
        POST request that allows user to change their credentials in the
        Users table. A valid access JWT is required where the admin
        claim has to be True
        Parameters can be passed using a POST request that contains a JSON with the following fields:
        :required:
            :param email: users current email address
            :type email: str
        :optional:
            :param fullname: users to be fullname
            :param password: users to be password
            :param admin: users to be admin status
            :param activated: users to be activated status
            :type fullname: str
            :type password: str
            :type admin: bool
            :type activated: bool

        :return: A message indicating success or failure and the corresponding response code
        """
        if not get_jwt_claims()['admin']:
            abort(HTTPStatus.FORBIDDEN.value,
                  error="administration privileges required")

        args = self.post_reqparser.parse_args()
        current_user = Users.find_by_email(args["email"])

        if current_user:
            if "fullname" in args:
                current_user.fullname = args["fullname"]
            if "activated" in args:
                current_user.activated = bool(args["activated"])
            if "admin" in args:
                current_user.admin = bool(args["admin"])
            if "password" in args:
                current_user.password = Users.generate_hash(
                    args["password"].encode("utf8")).decode("utf8")

            try:
                current_user.commit()
            except Exception as e:
                logging.error(e)
                return {"message": "failed saving details to database"}, 500

            return {"message": "success"}, 200

        else:
            return {"message": "error: could not find user"}, 403
    def get(self) -> (dict, HTTPStatus):
        """
        Check for triggered alerts.
        :return: On success, an HTTP response with a JSON body content
        containing the maximum and minimum alerts that have been exceeded with
        an HTTP status code of 200 (OK), otherwise an HTTP response with a JSON
        body content containing an appropriate error message and appropriate an
        HTTP status code
        """
        args = self.reqparser.parse_args()

        # Use current user_id if not user_id was parsed
        if "user_id" not in args:
            user = Users.find_by_email(get_jwt_identity())
            if user:
                args["user_id"] = user.id
            else:
                # Return Error current user id not found
                return (dict(error="User id not found for Current user, "
                             "User session may have timed out"),
                        HTTPStatus.INTERNAL_SERVER_ERROR)
        else:
            user = Users.find_by_id(args["user_id"])
            if not user:
                # Return error Parsed User Id not found
                return dict(error="User with id {} not found.".format(
                    args["user_id"])), HTTPStatus.NOT_FOUND

        # Check Attribute exists
        if not Attributes.get_by_id(args["attribute_id"]):
            # Return Error Attribute ID not found
            return dict(error="Attribute id {} not found.".format(
                args["attribute_id"])), HTTPStatus.NOT_FOUND

        # Get Attribute Max and Minimums
        attribute_range = AttributeRange.get_by_attr_id(args["attribute_id"])

        if not attribute_range:
            # Return eroor Attribute range not found
            return (dict(error="Attribute range not found",
                         **args), HTTPStatus.NOT_FOUND)

        # Check Alerts
        max_alerts = AlertWidgetModel.get_max_alerts(attribute_range,
                                                     user_id=user.id)
        min_alerts = AlertWidgetModel.get_min_alerts(attribute_range,
                                                     user_id=user.id)

        return dict(max=max_alerts, min=min_alerts), 200
 def create_admin_user(self) -> Users:
     """
     Create Admin user
     :return: an admin user
     """
     password_hash = bcrypt.hashpw("wfnbqk".encode("utf-8"), bcrypt.gensalt())
     user = Users.find_by_email("*****@*****.**")
     if not user:
         user = Users("Admin", "*****@*****.**", password_hash.decode("utf8"), True, True)
         try:
             user.save()
             user.commit()
         except Exception as e:
             pass
     return user
def test_change_user_fullname() -> NoReturn:
    """
    tests the user name is changed using the '/admin/change_user_fullname' endpoint
    """
    user = dependencies.get_dummy_user()
    json_data = {"email": user.email, "fullname": "asdfghjkl"}
    response = dependencies.client.post('/admin/change_user_fullname',
                                        json=json_data,
                                        headers=dependencies.auth_header,
                                        follow_redirects=True)
    user = Users.find_by_email(user.email)
    assert user.fullname == "asdfghjkl"

    user.delete()
    user.commit()
def test_change_user_password() -> NoReturn:
    """
    tests that the user password is changed using the '/admin/change_user_password' endpoint
    """
    user = dependencies.get_dummy_user()
    json_data = {
        "email": "*****@*****.**",
        "password": "******",
        "verify_password": "******"
    }
    response = dependencies.client.post('/admin/change_user_password',
                                        json=json_data,
                                        headers=dependencies.auth_header,
                                        follow_redirects=True)
    user = Users.find_by_email()
    def post(self) -> (str, int):
        """
        Save or Update a Widget
        Parameters can be passed using a POST request.
        POST request JSON body parameters:
            :param data:  Widget JSON data
            :param widgetID: Widget Id
            :param x: x coordinate of the widget layout
            :param y: y coordinate of the widget layout
            :param h: height of the widget layout
            :param w: width of the widget layout
            :param static: layout static property
        :returns : A response message and an appropriate HTTP status code
        """
        args = self.reqparse_post.parse_args()

        current_user = Users.find_by_email(get_jwt_identity())
        curr_widget = None

        if "widget_id" in args:
            curr_widget = WidgetModel.get_widget_by_id_and_user_id(
                args["widget_id"], current_user.id)

            if curr_widget:
                curr_widget.data = args["data"]
            else:
                abort(HTTPStatus.NOT_FOUND,
                      error="Widget with Id {} not found".format(
                          args["widget_id"]))

        else:
            # Create a layout for the new widget
            layout = Layouts(1, 0, 0, args['height'], args['width'], False)
            curr_widget = WidgetModel(current_user.id, layout, args["data"])

        try:
            db.session.add(curr_widget)
            # flush session to get new widgetID to assign to layout
            db.session.flush()
            self.update_layout(curr_widget, args)
            db.session.commit()
        except exc.SQLAlchemyError as e:
            logger.error(e.with_traceback(e.__traceback__))
            abort(HTTPStatus.BAD_REQUEST.value,
                  error="exc.SQLAlchemyError: create_widget")
        response = self.get_reponse_template(curr_widget,
                                             updated="widget_id" in args)
        return response, HTTPStatus.OK
예제 #15
0
 def _does_user_exsist(email: str = None) -> bool:
     """
     Checks if a user with the email passed exists
     :param email: users email address
     :type email: str
     :return: true if the user exists otherwise false
     """
     if not email:
         return abort(HTTPStatus.BAD_REQUEST.value,
                      error='email not supplied')
     try:
         user_exsists = Users.find_by_email(email)
     except exc.SQLAlchemyError as error:
         return abort(HTTPStatus.BAD_REQUEST.value,
                      jsonify({'error': error}))
     return user_exsists is not None
    def post(self) -> (str, int):
        """
        API resource class which returns a user from the database
        Parameters can be passed using a POST request that contains the following fields in the url:
        :required: valid access JWT where the admin claim may be true or false
        :param email: users email address
        :type email: str
        :return: The user's credentials on success or an error message and relevant status code when unsuccessful
        """
        args = self.get_reqparser.parse_args()
        # Fetch user from database using the users email
        user = Users.find_by_email(args["email"])

        if not user:
            # No user with that email address
            return abort(HTTPStatus.BAD_REQUEST.value, error='User not found')
        return user.json(), HTTPStatus.OK.value
    def post(self) -> (dict, HTTPStatus):
        """
        Create an alert.
        :return: On success return the new alert Id and an HTTP status code 201
                (Created), Otherwise return an error with the appropriate
                HTTP status code
        """
        args = self.reqparser.parse_args()

        if "user_id" not in args:
            # Not user_id in args get current user_id
            user = Users.find_by_email(get_jwt_identity())
            if user:
                args["user_id"] = user.id
            else:
                # Return Error current user id not found
                return (dict(error="User id not found for Current user, "
                                   "User session may have timed out"),
                        HTTPStatus.INTERNAL_SERVER_ERROR)

        elif not Users.find_by_id(args["user_id"]):
            # User not found return an error
            return dict(error="User id {} not found".format(
                args["user_id"])), HTTPStatus.NOT_FOUND

        if "max_threshold" not in args and "min_threshold" not in args:
            # No Threshold value in args at least one is required return an error
            return dict(
                error="A Threshold value is required"), HTTPStatus.BAD_REQUEST

        # Create AlertModel
        alert_model = AlertWidgetModel(args["user_id"], args["widget_id"],
                                       args["attribute_id"],
                                       args["max_threshold"],
                                       args["min_threshold"],
                                       args["activated"])

        if not alert_model:
            # Unable to create AlertModel return an error
            return dict(error="Unable to create Alert", args=args), \
                   HTTPStatus.INTERNAL_SERVER_ERROR
        # Persist Alert to database
        alert_model.save()
        alert_model.commit()

        return dict(id=alert_model.id), HTTPStatus.CREATED
예제 #18
0
 def create_admin_user() -> Users:
     """
     Create an Admin user
     :return: an Admin user
     """
     password_hash = bcrypt.hashpw("@p@22M0rd#@!".encode("utf-8"),
                                   bcrypt.gensalt())
     user = Users.find_by_email("test_admin_user@no_an_email.cr")
     if not user:
         user = Users("test_admin_user", "test_admin_user@no_an_email.cr",
                      password_hash.decode("utf8"), True, True)
         try:
             user.save()
             user.commit()
         except Exception as e:
             pass
     return user
def test_delete_user(test_client, admin_user, dummy_user):
    """ Test for successful deletion of a specified user by an admin and for absence of user in the database  """
    response_login = test_client.post('/login',
                                      data=dict(email=admin_user.email,
                                                password="******"),
                                      follow_redirects=True)
    response_login_json = response_login.get_json()
    header = {
        'Authorization':
        'Bearer {}'.format(response_login_json["access_token"])
    }

    response_delete = test_client.delete('/admin/delete_user',
                                         data=dict(email=dummy_user.email),
                                         headers=header,
                                         follow_redirects=True)
    assert response_delete.status_code == 204
    assert Users.find_by_email(dummy_user.email) == None
예제 #20
0
 def post(self) -> (str, int):
     """
     API resource class which changes username and saves changes to the database
     Parameters can be passed using a POST request that contains a JSON with the following fields:
     :required: valid access JWT where the admin claim may be either true or false
     :param email: users email address
     :param fullname: users fullname
     :type email: str
     :type fullname: str
     :return: Empty string and 200 status code
     """
     args = self.post_reqparser.parse_args()
     user = Users.find_by_email(args["email"])
     if not user:
         abort(HTTPStatus.NOT_FOUND.value, error='User not found.')
     user.fullname = args["fullname"]
     user.save()
     user.commit()
     return "", 200
def test_create_user_endpoint() -> NoReturn:
    """
    tests the '/admin/create_new_user' endpoint
    """
    global dependencies
    print(dependencies.user.id)
    json_data = {
        "email": "*****@*****.**",
        "fullname": "fullname",
        "admin": True,
        "password": "******"
    }
    response = dependencies.client.post('/admin/create_new_user',
                                        json=json_data,
                                        headers=dependencies.auth_header,
                                        follow_redirects=True)
    assert response.status_code == 201
    user = Users.find_by_email('*****@*****.**')
    if user:
        user.delete()
        user.commit
    def post(self) -> (dict, HTTPStatus):
        """
        Delete an alert.
        :return: On success, A HTTP response with a a JSON body content
                 containing  a message, a list of deleted alerts and an HTTP
                 status code 200 (OK) otherwise an appropriate error message
                 and an appropriate HTTP status code
        """
        args = self.reqparser.parse_args()

        # Check if enough arguments where passed to perform a deletion
        if all(arg not in args for arg in ["user_id", "attribute_id", "id"]):
            # Return an error responseDid not receive enough
            # arguments to find an alert accurately
            return (dict(error="Insufficient Arguments",
                         possible_args="user_id, attribute_id, alert_id"),
                    HTTPStatus.BAD_REQUEST)

        # Use current user_id if not user_id was parsed
        if "user_id" not in args:
            user = Users.find_by_email(get_jwt_identity())
            if user:
                args["user_id"] = user.id
            else:
                # Return Error current user id not found
                return (dict(error="User id not found for Current user, "
                             "User session may have timed out"),
                        HTTPStatus.INTERNAL_SERVER_ERROR)

        # Get Alerts using parsed args as filter arguments
        alerts = AlertWidgetModel.get_by_kwargs(**args)
        response_data = []
        for alert in alerts:
            response_data.append(alert.json)
            alert.delete()
            alert.commit()

        AlertWidgetModel.commit()

        return dict(message="Alert(s) Deleted", alerts=response_data), 200
    def post(self) -> (dict, int):
        """
        API resource class which changes a users password and saves changes to the database
        Parameters can be passed using a POST request that contains a JSON with the following fields:
        :required: valid access JWT where the admin claim may be either true or false
        :param email: users email address
        :param password: the new password which the user wants to store in the database
        :param verify_password: a repitition of the the 'password' param
        :type email: str
        :type password: str
        :type verify_password: str
        :return: A message indicating a successful or unsuccessful change
         """
        args = self.post_reqparser.parse_args()
        user = None

        # User must be an admin
        if not get_jwt_claims()['admin']:
            abort(HTTPStatus.FORBIDDEN.value,
                  error="administration privileges required")

        # get user instance using email address
        if args["email"]:
            user = Users.find_by_email(args["email"])
            if not user:
                abort(HTTPStatus.BAD_REQUEST.value, error="User not found")

        if args["password"] == args["verify_password"]:
            user.password = Users.generate_hash(
                args["password"].encode("utf-8")).decode("utf-8")

        try:
            user.save()
            user.commit()
        except exc.SQLAlchemyError as e:
            logging.critical(e)
            abort(HTTPStatus.BAD_REQUEST.value,
                  error="User password not changed")

        return {"user": "******".format(args["email"])}, 201
    def post(self) -> (str, int):
        """
		POST requests, activate user's account and change their password
		Parameters can be passed using a POST request that contains a JSON of the following fields:
		:param fullname: users fullname
		:param email: users email address
		:param password: users password that was sent when they were added on the admin page
		:type fullname: string
		:type email: string
		:type password: string
		:return: A message that indicates whether a user has been registered. If they have not, the message indicates why not
		"""
        args = self.parser.parse_args()
        current_user = Users.find_by_email(args['email'])  #t

        if not current_user:
            return {
                'message':
                'User {} is not authorised to access Sharing Cities Dashboard'.
                format(args['email'])
            }, 403

        if not Users.verify_hash(args['password'].encode("utf8"),
                                 current_user.password.encode("utf8")):
            return {
                'message':
                'The password entered does not correspond to the password sent to {}. Please try again'
                .format(args['email'])
            }, 403

        current_user.activated = True
        current_user.password = Users.generate_hash(
            args["password_new"].encode("utf8")).decode("utf8")
        current_user.commit()
        return {
            'message':
            '{}\'s account has been registered. Redirect to login'.format(
                args['email'])
        }, 201
예제 #25
0
    def post(self) -> (str, int):
        args = self.parser.parse_args()
        current_user = Users.find_by_email(args['email'])

        if current_user \
         and Users.verify_hash(
          args['password'].encode("utf8"),
          current_user.password.encode("utf8")):
            if current_user.activated:
                remember_access_token = timedelta(hours=3)
                remember_refresh_token = timedelta(hours=6)

                if args['remember'] is True:
                    remember_access_token = timedelta(weeks=1)
                    remember_refresh_token = timedelta(weeks=2)

                access_token = create_access_token(
                    identity=current_user, expires_delta=remember_access_token)
                refresh_token = create_refresh_token(
                    identity=current_user,
                    expires_delta=remember_refresh_token)

                return {
                    'message': 'Logged in as {}'.format(current_user.email),
                    'access_token': access_token,
                    'refresh_token': refresh_token,
                    'id': current_user.id,
                    'fullname': current_user.fullname
                }, 200
            else:
                return {
                    'message':
                    'User {} has not been activated. '
                    'Please register when redirected to registration '
                    'page'.format(current_user.email)
                }, 403
        else:
            return {'message': 'Incorrect credentials. Please try again'}, 403
예제 #26
0
    def post(self):
        args = self.post_reqparser.parse_args()
        user = None

        #User must be an admin
        if not get_jwt_claims()['admin']:
            abort(HTTPStatus.FORBIDDEN.value, error="administration privileges required")

        #get user instance using email
        if args["email"]:
            user = Users.find_by_email(args["email"])
            if not user:
                abort(HTTPStatus.BAD_REQUEST.value, error="User not found")

        if args["password"] == args["verify_password"]:
            user.password = Users.generate_hash(args["password"].encode("utf-8"))

        try:
            user.save()
            user.commit()
        except exc.SQLAlchemyError:
            abort(HTTPStatus.BAD_REQUEST.value, error="User password not changed")

        return {"user": "******".format(args["email"])}, 201
    def post(self) -> (str, int):
        """
        POST request endpoint. Set user password to a system generated
        password and send password to user's email
        """

        args = self.parser.parse_args()
        current_user = Users.find_by_email(args["email"])

        if current_user:
            system_password = self.generate_random_password(
                self.system_password_length)

            if self.send_forgot_password_email(current_user.fullname,
                                               current_user.email,
                                               system_password):
                current_user.password = Users.generate_hash(
                    system_password.encode("utf8")).decode("utf8")
                current_user.commit()
                return {"message": "success"}, 200
            else:
                return {"message": "could not send email"}, 500
        else:
            return {"message": "cannot find user"}, 403