Esempio n. 1
0
    def delete(self, **kwargs):
        """
        Function will delete all of candidate's notes if note ID is not provided,
        otherwise it will delete specified candidate note
        Endpoints:
             i. DELETE /v1/candidates/:candidate_id/notes
            ii. DELETE /v1/candidates/:candidate_id/notes/:id
        """
        # Get authenticated user & candidate ID
        authed_user, candidate_id, note_id = request.user, kwargs['candidate_id'], kwargs.get('id')

        # Check if candidate exists & is not web-hidden
        candidate = get_candidate_if_exists(candidate_id)

        # Candidate must belong to user's domain
        if not does_candidate_belong_to_users_domain(authed_user, candidate_id):
            raise ForbiddenError('Not authorized', custom_error.CANDIDATE_FORBIDDEN)

        # Delete candidate's note if note ID is provided, otherwise delete all of candidate's notes
        if note_id:

            # Delete note from DB & update cloud search
            delete_note(candidate_id, note_id)
            upload_candidate_documents.delay([candidate_id])

            return {'candidate_note': {'id': note_id}}
        else:
            # Delete notes from DB & update cloud search
            deleted_notes = delete_notes(candidate)
            upload_candidate_documents.delay([candidate_id])

            return {'candidate_notes': deleted_notes}
Esempio n. 2
0
    def patch(self, **kwargs):
        """
        Function will update candidate's tag(s)
        Endpoints:
             i. PATCH /v1/candidates/:candidate_id/tags
            ii. PATCH /v1/candidates/:candidate_id/tags/:id
        Example:
            >>> url = 'host/v1/candidates/4/tags' or 'host/v1/candidates/4/tags/57'
            >>> headers = {'Authorization': 'Bearer edo9rdSKN8hYuc1zBWMfLXpXFd4ZbE'}
            >>> data = {"tags": [{"description": "minority"}, {"description": "remote"}]}
            >>> requests.patch(url=url, headers=headers, data=json.dumps(data))
        """
        # Get json data if exists and validate its schema
        body_dict = get_json_data_if_validated(request, tag_schema, False)

        # Description is a required field (must not be empty)
        tags, tag = body_dict.get('tags'), body_dict.get('tag')
        for tag in tags:
            tag['name'] = tag['name'].strip().lower(
            )  # remove whitespaces while validating
            if not tag['name']:
                raise InvalidUsage('Tag name is a required field',
                                   custom_error.MISSING_INPUT)

        # Authenticated user, candidate ID, and tag ID
        authed_user, candidate_id, tag_id = request.user, kwargs[
            'candidate_id'], kwargs.get('id')

        # If tag_id is provided in the url, it is assumed that only one candidate-tag needs to be updated
        if tag_id and len(tags) > 1:
            raise InvalidUsage(
                "Updating multiple Tags via this resource is not permitted.",
                custom_error.INVALID_USAGE)

        # Check for candidate's existence and web-hidden status
        get_candidate_if_validated(authed_user, candidate_id)

        # If tag_id is provided in the url, update only one record
        if tag_id:
            return {
                'updated_tag':
                update_candidate_tag(candidate_id, tag_id, tag['name'].strip())
            }

        # Update tag(s)
        updated_tag_ids = update_candidate_tags(candidate_id=candidate_id,
                                                tags=tags)

        # Update cloud search
        upload_candidate_documents.delay([candidate_id])

        return {'updated_tags': [{'id': tag_id} for tag_id in updated_tag_ids]}
Esempio n. 3
0
    def post(self):
        """
        Upload Candidate Documents to Amazon Cloud Search
        """

        requested_data = request.get_json(silent=True)
        if not requested_data or 'candidate_ids' not in requested_data:
            raise InvalidUsage(
                error_message="Request body is empty or invalid")

        upload_candidate_documents.delay(requested_data.get('candidate_ids'))

        return '', 204
Esempio n. 4
0
    def post(self, **kwargs):
        """
        Function will create tags
        Note: "description" is a required field
        Endpoint:  POST /v1/candidates/:candidate_id/tags
        Docs: http://docs.candidatetags.apiary.io/#reference/tags/tags-collections-resource/create-tags
        Example:
            >>> url = 'host/v1/candidates/4/tags'
            >>> headers = {'Authorization': 'Bearer edo9rdSKN8hYuc1zBWMfLXpXFd4ZbE'}
            >>> data = {"tags": [{"description": "python"}]}
            >>> requests.post(url=url, headers=headers, data=json.dumps(data))
        :return:  {'tags': [{'id': int}, {'id': int}, ...]}
        """
        # Get json data if exists and validate its schema
        body_dict = get_json_data_if_validated(request, tag_schema, False)

        # Description is a required field (must not be empty)
        for tag in body_dict['tags']:
            tag['name'] = tag['name'].strip().lower(
            )  # remove whitespaces while validating
            if not tag['name']:
                raise InvalidUsage('Tag name is a required field',
                                   custom_error.MISSING_INPUT)

        # Authenticated user & candidate ID
        authed_user, candidate_id = request.user, kwargs['candidate_id']

        # Check for candidate's existence and web-hidden status
        get_candidate_if_validated(authed_user, candidate_id)

        # Create tags
        created_tag_ids = create_tags(candidate_id=candidate_id,
                                      tags=body_dict['tags'])

        # Update cloud search
        upload_candidate_documents.delay([candidate_id])

        return {'tags': [{'id': tag_id} for tag_id in created_tag_ids]}, 201
Esempio n. 5
0
    def delete(self, **kwargs):
        """
        Function will delete candidate's tag(s)
        Endpoints:
             i. DELETE /v1/candidates/:candidate_id/tags
            ii. DELETE /v1/candidates/:candidate_id/tags/:id
        Example:
            >>> url = 'host/v1/candidates/4/tags' or 'host/v1/candidates/4/tags/57'
            >>> headers = {'Authorization': 'Bearer edo9rdSKN8hYuc1zBWMfLXpXFd4ZbE'}
            >>> requests.delete(url=url, headers=headers)
        """
        # Authenticated user, candidate ID, and tag ID
        authed_user, candidate_id, tag_id = request.user, kwargs[
            'candidate_id'], kwargs.get('id')

        # Check for candidate's existence and web-hidden status
        get_candidate_if_validated(authed_user, candidate_id)

        # Delete specified tag
        if tag_id:

            # Delete
            deleted_tag_id = delete_tag(candidate_id=candidate_id,
                                        tag_id=tag_id)

            # Update cloud search
            upload_candidate_documents([candidate_id])

            return {'deleted_tag': deleted_tag_id}

        # Delete all of candidate's tags
        deleted_tag_ids = delete_tags(candidate_id)

        # Update cloud search
        upload_candidate_documents.delay([candidate_id])

        # Delete all of candidate's tags
        return {'deleted_tags': deleted_tag_ids}
Esempio n. 6
0
    def post(self, **kwargs):
        """
        Endpoint:  POST /v1/candidates/:candidate_id/notes
        Function will add candidate's note(s) to database
        """
        # Validate and retrieve json data
        body_dict = get_json_data_if_validated(request, notes_schema)

        # Get authenticated user & Candidate ID
        authed_user, candidate_id = request.user, kwargs['candidate_id']

        # Check if candidate exists & is not web-hidden
        get_candidate_if_exists(candidate_id)

        # Candidate must belong to user's domain
        if not does_candidate_belong_to_users_domain(authed_user, candidate_id):
            raise ForbiddenError('Not authorized', custom_error.CANDIDATE_FORBIDDEN)

        note_ids = add_notes(candidate_id=candidate_id, user_id=authed_user.id, data=body_dict['notes'])

        # Update cloud search
        upload_candidate_documents.delay([candidate_id])

        return {'candidate_notes': [{'id': note_id} for note_id in note_ids]}, requests.codes.CREATED
Esempio n. 7
0
    def post(self, **kwargs):
        """
        Endpoints:  POST /v1/candidates/:candidate_id/custom_fields
        Usage:
            >>> headers = {"Authorization": "Bearer access_token", "content-type": "application/json"}
            >>> data = {"candidate_custom_fields": [{"custom_field_id": 547, "value": "scripted"}]}
            >>> requests.post(url="hots/v1/candidates/4/custom_fields", headers=headers, data=json.dumps(data))
            <Response [201]>
        :return  {'candidate_custom_fields': [{'id': int}, {'id': int}, ...]}
        """
        # Validate data
        body_dict = get_json_data_if_validated(request, ccf_schema)

        # Get authenticated user and candidate ID
        authed_user, candidate_id = request.user, kwargs['candidate_id']

        # Candidate must exists and must belong to user's domain
        candidate = get_candidate_if_validated(authed_user, candidate_id)

        created_candidate_custom_field_ids = [
        ]  # aggregate created CandidateCustomField IDs
        candidate_custom_fields = body_dict['candidate_custom_fields']

        for candidate_custom_field in candidate_custom_fields:

            # Custom field value(s) must not be empty
            values = filter(None, [value.strip() for value in (candidate_custom_field.get('values') or []) if value]) \
                     or [candidate_custom_field['value'].strip()]
            if not values:
                raise InvalidUsage("Custom field value must be provided.",
                                   custom_error.INVALID_USAGE)

            # Custom Field must be recognized
            custom_field_id = candidate_custom_field['custom_field_id']
            custom_field = CustomField.get_by_id(custom_field_id)
            if not custom_field:
                raise NotFoundError(
                    "Custom field ID ({}) not recognized".format(
                        custom_field_id), custom_error.CUSTOM_FIELD_NOT_FOUND)

            # Custom Field must belong to user's domain
            if custom_field.domain_id != candidate.user.domain_id:
                raise ForbiddenError(
                    "Custom field ID ({}) does not belong to user ({})".format(
                        custom_field_id, authed_user.id),
                    custom_error.CUSTOM_FIELD_FORBIDDEN)

            custom_field_dict = dict(values=values,
                                     custom_field_id=custom_field_id)

            for value in custom_field_dict.get('values'):

                custom_field_id = candidate_custom_field.get('custom_field_id')

                # Prevent duplicate insertions
                if not does_candidate_cf_exist(candidate, custom_field_id,
                                               value):

                    added_time = datetime.datetime.utcnow()

                    candidate_custom_field = CandidateCustomField(
                        candidate_id=candidate_id,
                        custom_field_id=custom_field_id,
                        value=value,
                        added_time=added_time)
                    db.session.add(candidate_custom_field)
                    db.session.flush()

                    created_candidate_custom_field_ids.append(
                        candidate_custom_field.id)

        db.session.commit()
        upload_candidate_documents.delay([candidate_id])
        return {
            'candidate_custom_fields': [{
                'id': custom_field_id
            } for custom_field_id in created_candidate_custom_field_ids]
        }, http_status_codes.CREATED
Esempio n. 8
0
    def delete(self, **kwargs):
        """
        Endpoints:
             i. DELETE /v1/candidates/:candidate_id/custom_fields
            ii. DELETE /v1/candidates/:candidate_id/custom_fields/:id
        Depending on the endpoint requested, function will delete all of Candidate's
        custom fields or just a single one.
        """
        # Get authenticated user, candidate_id, and can_cf_id (CandidateCustomField.id)
        authed_user, candidate_id, can_cf_id = request.user, kwargs[
            'candidate_id'], kwargs.get('id')

        # Candidate must exists and must belong to user's domain
        get_candidate_if_validated(authed_user, candidate_id)

        if can_cf_id:  # Delete specified custom field
            candidate_custom_field = CandidateCustomField.get_by_id(can_cf_id)
            if not candidate_custom_field:
                raise NotFoundError(
                    'Candidate custom field not found: {}'.format(can_cf_id),
                    custom_error.CUSTOM_FIELD_NOT_FOUND)

            # Custom fields must belong to user's domain
            custom_field_id = candidate_custom_field.custom_field_id
            if not is_custom_field_authorized(authed_user.domain_id,
                                              [custom_field_id]):
                raise ForbiddenError('Not authorized',
                                     custom_error.CUSTOM_FIELD_FORBIDDEN)

            # Custom Field must belong to candidate
            if candidate_custom_field.candidate_id != candidate_id:
                raise ForbiddenError(
                    "Candidate custom field ({}) does not belong to candidate ({})"
                    .format(can_cf_id,
                            candidate_id), custom_error.CUSTOM_FIELD_FORBIDDEN)

            db.session.delete(candidate_custom_field)

            # Track change
            db.session.add(
                CandidateEdit(
                    user_id=authed_user.id,
                    candidate_id=candidate_id,
                    field_id=CandidateEdit.field_dict['candidate_custom_field']
                    ['value'],
                    old_value=candidate_custom_field.value,
                    new_value=None,
                    edit_datetime=datetime.datetime.utcnow(),
                    is_custom_field=True))

        else:  # Delete all of Candidate's custom fields
            for ccf in CandidateCustomField.get_candidate_custom_fields(
                    candidate_id):  # type: CandidateCustomField
                db.session.delete(ccf)

                # Track change
                db.session.add(
                    CandidateEdit(
                        user_id=authed_user.id,
                        candidate_id=candidate_id,
                        field_id=CandidateEdit.
                        field_dict['candidate_custom_field']['value'],
                        old_value=ccf.value,
                        new_value=None,
                        edit_datetime=datetime.datetime.utcnow(),
                        is_custom_field=True))

        db.session.commit()

        # Update cloud search
        upload_candidate_documents.delay([candidate_id])
        return '', 204