Exemplo n.º 1
0
def not_empty(key, value):
    """
    Verify if the value is empty or not. Raises validation error if empty
    Raises error if no value

    :param key: key value where the value is from
    :param value: value
    :return: None
    """
    if not value:
        raise err.ValidationError({key: "Value cannot be empty"})

    if isinstance(value, str) and not value.strip():
        raise err.ValidationError({key: "Value cannot be empty"})
Exemplo n.º 2
0
    def save(self, *args, **kwargs):
        """
        Clean the data before saving to the database also generate api key if no key
        :param args:
        :param kwargs:
        :return:
        """
        self.username = self.normalize_username(self.username)
        self.work_email = BaseUserManager.normalize_email(self.work_email)

        if self.reporting_manager:
            try:
                _reporting_manager = Employee.get_employee_by_email(
                    self.reporting_manager)
            except err.NotFoundError:
                log.error(self.reporting_manager)
                raise err.ValidationError({
                    "reporting_manager":
                    "Given reporting manager not available"
                })
            if _reporting_manager.id == self.id:
                raise err.ValidationError({
                    "reporting_manager":
                    "You cannot assign yourself as reporting manager"
                })
            self.reporting_manager = _reporting_manager.id

        if not hasattr(self, "_api_key") or not getattr(self, "_api_key"):
            log.info("Creating a new api key")
            api_key, key = APIKey.objects.create_key(name=self.work_email)
            self._api_key = APIKey.objects.get_from_key(key)

        _fields = ("employee_id", )
        for _field in _fields:
            val = getattr(self, _field)
            if val:
                setattr(self, _field, val.lower().strip())

        if not self.graduated_year:
            self.graduated_year = None

        # TODO default array doesnt work - Hack
        if not getattr(self, "skills"):
            self.skills = list()

        return super(self.__class__, self).save(*args, **kwargs)
Exemplo n.º 3
0
def _search_employee_for_pagination(app_context, data_dict):
    """
    This function is for internal use only. Utilized by views for pagination
    :return: Elastic search document
    """

    auth.is_authenticated(app_context)
    search_fields = data_dict.get('search_fields', '')
    search_value = data_dict.get('q', '')
    query_dict = data_dict.get('query_dict', '')

    if query_dict and not isinstance(query_dict, dict):
        raise err.ValidationError(
            {"raw_query": "Raw query should be of type json"})

    if search_fields and not isinstance(search_fields, list):
        try:
            search_fields = search_fields.split(",")
            if not search_fields:
                raise err.ValidationError(
                    {"search_fields": "Search fields should be list"})
        except Exception as e:
            log.error(e)
            raise err.ValidationError({
                "search_fields":
                "Something wrong while converting text to list in search_fields"
            })

    if not search_value and not query_dict:
        log.info("No search value given, returning all with limit")
        profiles = EmployeeDocument.search()
    else:
        if query_dict:
            log.info("given query dict for searching")
            profiles = EmployeeDocument.search().from_dict(query_dict)
        else:
            log.info("Given search value: {}".format(search_value))
            if not search_fields:
                search_fields = EmployeeDocument.default_search_fields_full_text(
                )

            profiles = EmployeeDocument.search().query('multi_match',
                                                       query=search_value,
                                                       fields=search_fields)

    return profiles
Exemplo n.º 4
0
def search_employee(app_context, data_dict):
    """
    This api provides a way to search for an employee by
        - first name,
        - middle name
        - last name
        - work email
        - employee id
        - employee position
        - country

    Max limit is 100. If no search_fields are give - full text search is performed.
    Employee can also be searched from elastic search dictionary using parameter raw_query

    :parameter
        search_fields: list
            Fields to perform search operation, if not given defaulkt value is used
        search: str
            Value to be searched
        offset: int
            Offset
        limit: int
            max value is 100

    :param app_context: dict application context
    :param data_dict: dict
    :return: dict
    """
    limit = data_dict.get('limit', 20)
    offset = data_dict.get('offset', 0)
    if not isinstance(offset, int):
        raise err.ValidationError({'offset': "Offset should be integer"})

    if not isinstance(limit, int) or limit > 100:
        raise err.ValidationError(
            {"limit": "Should be integer and max value allowed is 100"})

    # Authorization is checked in this function
    profiles = _search_employee_for_pagination(app_context, data_dict)

    results = {"results": [], "res_count": profiles.count()}

    for _p in profiles[offset:limit]:
        results['results'].append(_p.as_dict())
    return results
Exemplo n.º 5
0
def number_validator(key, value):
    """
    Check if the given value is number
    :param key: str
    :param value: str
    :return: None
    """
    try:
        int(value)
    except Exception as e:
        raise err.ValidationError({key: "Value must be integer"})
Exemplo n.º 6
0
def country_code_validator(key, value):
    """
    Validate the given country code. Country code should follow (ISO 3166) standards
    :param key: str
    :param value: str
    :return: None
    """
    try:
        _country = pycountry.countries.get(alpha_2=value)
        if not _country:
            raise err.ValidationError({
                key:
                "Not a valid country code - should follow ISO 3166 standard."
            })
    except Exception as e:
        log.error(e)
        raise err.ValidationError({
            key:
            "Something wrong with given country code - should follow ISO 3166 standard."
        })
Exemplo n.º 7
0
def validate_existing_user(key, value):
    """
    See if the user already exists. If exists raise an error existing user
    :return:
    """
    try:
        _employee = models.Employee.get_employee_by_id(value)
        raise err.ValidationError({
            key: "User with employee id already exists"
        })
    except err.NotFoundError:
        pass
Exemplo n.º 8
0
def validate_avatar_file(file_upload):
    """
    Validate the avatar uploaded or updated for an employee
    :param file_upload: class UploadedFile
    :return: Boolean
    """

    _allowed_formats = tuple(config.get('AVATAR_FILE_FORMATS', ["png", "jpeg", "jpg"]))

    file_name, file_ext = os.path.splitext(file_upload.name)
    if not file_ext or file_ext.replace(".", "").lower() not in _allowed_formats:
        raise err.ValidationError({
            "upload_avatar": "File not in required format only allowed format is png, jpeg and jpg"
        })

    if file_upload.size > int(config.get('MAX_AVATAR_SIZE_BYTES')):
        raise err.ValidationError({
            "avatar": "Uploaded image file exceeded limit."
        })

    return True
Exemplo n.º 9
0
def url_validator(key, value):
    """

    :param key:
    :param value:
    :return:
    """
    try:
        _val = py_validators.url(value)
        if not _val:
            raise Exception
    except Exception as e:
        raise err.ValidationError({key: "Not a valid url - use full url"})
Exemplo n.º 10
0
def email_validator(key, value):
    """
    Verify if the given email id is valid or not. Raises a validation error if not valid.

    :param key: key value where the value is from
    :param value: value should be of type email
    :return: None
    """
    try:
        validate_email(value)
    except EmailNotValidError as e:
        raise err.ValidationError(
            {key: "Not a valid email. Please verify your email"})
Exemplo n.º 11
0
def check_if_user_exists(key, value):
    """
    Check if the given employee exists
    :param key:
    :param value:
    :return:
    """
    try:
        _employee = models.Employee.get_employee_by_id(value)
    except err.NotFoundError:
        raise err.ValidationError(
            {
                key: "Given employee not found"
            }
        )
Exemplo n.º 12
0
def show_employee(app_context, data_dict):
    """
    Show employee for the given employee id or employee unique identifier.

    Note: Access control is given is schema in show attribute - space separated string e.g. admin hr member all

        - admin: show to only to admin
        - admin hr: show admin and to hr
        - admin hr member: show admin and to hr and user profile (logged in user ==  requested user profile)
        - all: show to every logged in user

    :param app_context: dict
    :param data_dict: dict (containing employee_id oir id)
    :return: dict
    """
    log.info("Show employee api...")
    auth.employee_show(app_context)
    _user = app_context.get('user')
    role = app_context.get('role')
    _id = data_dict.get('id', '')
    _schema = schemas.get_schema('employee_schema')

    log.info("Showing the employee data for id: {}".format(_id))

    if not _id:
        raise err.ValidationError({"id": "id parameter is required."})

    _employee = models.Employee.get_employee_by_id(_id)

    # If logged in user and requesting profile are not same
    if role == "member":
        if _user.id != _employee.id:
            role = "all"

    _data = _employee.as_dict()

    response = dict()

    for _property in _schema['properties']:
        _show = _schema['properties'][_property].get('show', "").split(" ")
        if role in _show:
            response[_property] = _data[_property]

    for x in ("id", "created_at", "updated_at", "avatar"):
        response[x] = _data[x]

    return response
Exemplo n.º 13
0
def send_email(subject=None, body=None, to=None):
    """
    Send an email given subject body and user list

    :param subject: str Email subject
    :param body: str Email body
    :param to: str To who?
    :return: None
    """
    log.info("Sending email to: ")
    log.info(to)
    for _email in to:
        validators.email_validator(_email)

    if not subject or not body:
        raise err.ValidationError("Subject or body is required parameter")
    email = EmailMessage(subject, body, to=to)
    email.send()
Exemplo n.º 14
0
def date_validator(key, value):
    """
    Verify the given date string. The date string should be of format %Y-%m-%d (ISO).
    Note: string should be only of date type. Cannot accept datetime string.

    Raises error if does not match the format.

    :param key: key value where the value is from
    :param value: value shoudl be of type date string
    :return: None
    """

    try:
        datetime.strptime(value, "%Y-%m-%d")
    except ValueError:
        raise err.ValidationError({
            key:
            "Given date string does not match the format %Y-%m-%d. Should be ISO format"
        })
Exemplo n.º 15
0
def delete_employee(app_context, data_dict):
    """
    Delete an employee given employee_id or unique id. Only admin or hr can delete employee.
    :param app_context:
    :param data_dict:
    :return:
    """
    auth.employee_delete(app_context)
    _id = data_dict.get('id', '')
    log.info("Deleting employee for an id: {}".format(id))

    if not _id:
        raise err.ValidationError({"id": "id parameter is required."})

    _employee = models.Employee.get_employee_by_id(_id)
    _employee.delete()

    return {
        "message":
        "Employee with id: {} has been deleted successfully".format(_id)
    }
Exemplo n.º 16
0
    def generate_api_key(cls, email):
        """
        Generate API key given the user/work email
        :param email: str
        :return: tuple
        """
        try:
            _profile = cls.objects.get(work_email=email)
        except Employee.DoesNotExist:
            raise err.ValidationError(
                {"work_email": "No user found for the given work email"})

        log.info("Generating API key for an email: {}".format(email))
        try:
            APIKey.objects.filter(name=email).delete()
        except Exception as e:
            log.error(e)
            pass

        api_key, key = APIKey.objects.create_key(name=email)
        _profile._api_key = APIKey.objects.get_from_key(key)
        _profile.save()

        return api_key, key
Exemplo n.º 17
0
def send_email_create_employee(to):
    """
    Sends Subject and body to the recently created employee
    :return: tuple
    """
    log.info("Sending an email to the new employee")
    log.info(to)
    if isinstance(to, list) or isinstance(to, tuple):
        if len(to) > 1:
            raise err.ValidationError(
                "This should not happen. On create employee, email is sent to employee only"
            )

    validators.email_validator("work_email", to[0])
    user = u.get_user_given_email(to[0])
    sub = "Admin has created your profile. Please reset your password"
    body = """
    Hi {first_name} {last_name},

    Welcome to {application_name}!!

    Please use this link to reset your password and login to your account to update your profile.

    Password reset link:{reset_link}

    Yours,

    Admin,
    {company_name}
    """.format(first_name=user.first_name,
               last_name=user.last_name,
               application_name=config.get("APPLICATION_TITLE"),
               reset_link="",
               company_name=config.get("COMPANY_NAME"))

    return sub, body
Exemplo n.º 18
0
def update_employee(app_context, data_dict):
    """
    Update employee profile. Parameter should contain id - representing unique id of the employee of id as employee id.
    Only admin/hr can alter employee fields or logged in user can alter their fields.

    Note:
        Access control is given in schema in update attribute - space separated string e.g. admin hr member all

        - admin: Only admin can update
        - admin hr: Only admin and to hr can update
        - admin hr member: admin , hr and member can update (logged in user ==  requested user profile)
        - all: show to every logged in user

    :param app_context: dict
    :param data_dict: dict (containing fields to be updated)
    :return: dict success message or show_employee - api
    """

    auth.is_authenticated(app_context)
    role = app_context.get('role')
    _show_employee = u.core_convert_to_bool(
        data_dict.pop('show_employee', True))
    _id = data_dict.pop('id', None)

    _files = app_context.get('files', '')
    _schema = schemas.get_schema('employee_schema')
    log.info("Updating an employee for an id: {}".format(_id))
    if data_dict.get('skills', ''):
        _skills = data_dict['skills']
        if isinstance(_skills, str):
            # Hack for multipart/form-data?? Dont know if this is the right way
            # TODO: need to create a data insert pre processing pipeline
            data_dict['skills'] = [
                s.strip().title() for s in _skills.split(",")
            ]

    if role == "all":
        err.ValidationError({"InternalError": "This should not occur."})

    if not _id:
        raise err.ValidationError({"id": "id parameter is required."})

    try:
        with model_transaction.atomic():
            _employee = models.Employee.get_employee_by_id(_id)
            # Check authorization
            auth.employee_update({
                "role": app_context.get('role'),
                "user": app_context.get('user'),
                "employee": _employee
            })
            # Internal user only

            _data = _employee._as_dict()

            log.info("Updating the data and validating")
            _data.update(data_dict)
            schemas.validate("employee_schema", _data)

            # Insert operation
            _emp_extras = models.EmployeeExtras.objects.filter(
                employee=_employee)
            _extras = []

            for _key in data_dict:
                if _key in _schema['properties']:
                    try:
                        _property = _schema['properties'][_key]
                        _update = _property.get('update', "").split(" ")

                        if role not in _update:
                            raise err.NotAuthorizedError(
                                {_key: "Not authorized to update the value"})

                        if hasattr(_employee, _key):
                            setattr(_employee, _key, data_dict.get(_key))
                        else:
                            for _emp_ext in _emp_extras:
                                if _emp_ext.key == _key:
                                    _emp_ext.value = data_dict.get(_key)
                                    _extras.append(_emp_ext)
                                    break

                    except KeyError as e:
                        log.warning(e)
                        pass

            if 'upload_avatar' in _files:
                log.info("Found avatar update..")
                _uploaded_avatar = _files['upload_avatar']

                if _uploaded_avatar:
                    validators.validate_avatar_file(_uploaded_avatar)

                if _employee.avatar and os.path.isfile(_employee.avatar.path):
                    os.remove(_employee.avatar.path)
                _employee.avatar = _uploaded_avatar

            _employee.save()
            for _md in _extras:
                _md.save()

    except Exception as e:
        log.error(e)
        raise e

    if _show_employee:
        result = show_employee(app_context, {"id": _employee.employee_id})
    else:
        result = {
            "message":
            "Employee with id: {} has been updated successfully".format(
                _employee.employee_id)
        }

    return result
Exemplo n.º 19
0
    def post(self, request, profile_id=None):
        """

        :param request:
        :param profile_id:
        :return:
        """
        if profile_id == request.user.id or not profile_id:
            raise err.ValidationError({
                "profile":
                "You cannot delete your own profile. Please contact HR or Admin"
            })

        context = {
            "type": "profile",
            "user": request.user,
            "is_superuser": request.user.is_superuser,
            "role": request.user.role
        }

        extra_vars = dict()
        extra_vars['errors'] = dict()
        try:
            auth.employee_create(context)
            api_action.post_actions("delete_employee", context,
                                    {"id": profile_id})
        except err.ValidationError as e:
            extra_vars['errors'].update(e.args[0])
            u.prepare_error_data(extra_vars['errors'])
            log.error(e)
            messages.error(
                request, "<br>".join([
                    "{}: {}".format(key, value)
                    for key, value in extra_vars['errors'].items()
                ]))
            if profile_id:
                return redirect('other_profile', profile_id=profile_id)
            else:
                return redirect('profile')
        except err.NotAuthorizedError:
            messages.error(request,
                           'You are not authorized to perform this action')
            log.info("Logged in user not authorized to edit view")
            return abort(
                request,
                code=401,
                error_message="You are not authorized to see this page",
                error_title="Not Authorized")
        except (err.UserNotFound, err.NotFoundError) as e:
            log.info(e)
            return abort(request,
                         code=404,
                         error_message="User Not found.",
                         error_title="Not Found")
        except Exception as e:
            log.error(e)
            return server_error(request,
                                code=500,
                                error_message="Server Error. Something wrong")

        return redirect('profile_search')