def get(self, **kwargs): """ GET /talent-pools/<id>/talent-pipelines Fetch all talent-pipelines of a Talent-Pool :return A dictionary containing all talent-pipelines of a Talent Pool :rtype: dict """ talent_pool_id = kwargs.get('id') talent_pool = TalentPool.query.get(talent_pool_id) if not talent_pool: raise NotFoundError( "Talent pool with id {} doesn't exist in database".format( talent_pool_id)) if request.user.role.name != 'TALENT_ADMIN' and talent_pool.domain_id != request.user.domain_id: raise ForbiddenError( "Talent pool and logged in user belong to different domains") talent_pool_group = TalentPoolGroup.query.filter_by( user_group_id=request.user.user_group_id, talent_pool_id=talent_pool_id).first() if request.user.role.name == 'USER' and not talent_pool_group: raise ForbiddenError( "User {} doesn't have appropriate permissions to " "get talent-pipelines".format(request.user.id)) page = request.args.get('page', DEFAULT_PAGE) per_page = request.args.get('per_page', DEFAULT_PAGE_SIZE) if not is_number(page) or not is_number( per_page) or int(page) < 1 or int(per_page) < 1: raise InvalidUsage("page and per_page should be positive integers") page = int(page) per_page = int(per_page) talent_pipelines_query = TalentPipeline.query.filter_by( talent_pool_id=talent_pool_id) talent_pipelines = talent_pipelines_query.paginate( page, per_page, False) talent_pipelines = talent_pipelines.items headers = generate_pagination_headers(talent_pipelines_query.count(), per_page, page) response = { 'talent_pipelines': [ talent_pipeline.to_dict(True, get_stats_generic_function) for talent_pipeline in talent_pipelines ] } return ApiResponse(response=response, headers=headers, status=200)
def delete(self, **kwargs): """ DELETE /groups/<group_id>/talent_pools Remove given input of talent-pool ids from user group input: {'talent_pools': [talent_pool_id1, talent_pool_id2, talent_pool_id3, ... ]} :return A dictionary containing talent-pool ids which have been removed successfully :rtype: dict """ user_group_id = kwargs.get('group_id') posted_data = request.get_json(silent=True) if not posted_data or 'talent_pools' not in posted_data: raise InvalidUsage("Request body is empty or not provided") # Save user object(s) talent_pool_ids = posted_data['talent_pools'] # Talent_pool object(s) must be in a list if not isinstance(talent_pool_ids, list): raise InvalidUsage("Request body is not properly formatted") user_group = UserGroup.query.get(user_group_id) if not user_group: raise NotFoundError( "User group with id {} doesn't exist".format(user_group_id)) if request.user.role.name != 'TALENT_ADMIN' and request.user.domain_id != user_group.domain_id: raise ForbiddenError( "Logged-in user and given user-group belong to different domains" ) for talent_pool_id in talent_pool_ids: if not is_number(talent_pool_id): raise InvalidUsage( 'Talent pool id {} should be an integer'.format( talent_pool_id)) else: talent_pool_id = int(talent_pool_id) talent_pool_group = TalentPoolGroup.query.filter_by( user_group_id=user_group_id, talent_pool_id=talent_pool_id).first() if not talent_pool_group: raise NotFoundError( "Talent pool {} doesn't belong to group {}".format( talent_pool_id, user_group_id)) else: db.session.delete(talent_pool_group) db.session.commit() return { 'talent_pools': [int(talent_pool_id) for talent_pool_id in talent_pool_ids] }
def patch(self, **kwargs): """ PATCH list with search params or with list of candidate ids Input data: json body having following keys "name": Name with which smart list will be created "search_params": search parameters for smart list in dictionary format or "candidate_ids": if not search_params then candidate_ids should be present :return: smartlist id """ auth_user = request.user list_id = kwargs.get('id') data = request.get_json(silent=True) if not data: raise InvalidUsage("Received empty request body") if not list_id or not is_number(list_id): raise InvalidUsage( "Either List ID is not provided or It's not an integer") smart_list = Smartlist.query.get(list_id) if not smart_list: raise InvalidUsage("No SmartList exists with id: %s" % list_id) # request data must pass through this function, as this will create data in desired format data = validate_and_format_smartlist_patch_data(data, auth_user) if data.get('name'): smart_list.name = data.get('name') if data.get('talent_pipeline_id'): smart_list.talent_pipeline_id = data.get('talent_pipeline_id') if data.get('search_params'): smart_list.search_params = data.get('search_params') elif data.get('remove_candidate_ids'): SmartlistCandidate.query.filter( SmartlistCandidate.smartlist_id == smart_list.id, SmartlistCandidate.candidate_id.in_( data.get('remove_candidate_ids'))).delete() elif data.get('add_candidate_ids'): for candidate_id in data.get('add_candidate_ids'): row = SmartlistCandidate(smartlist_id=smart_list.id, candidate_id=candidate_id) db.session.add(row) db.session.commit() candidate_ids = data.get('remove_candidate_ids', []) + data.get( 'add_candidate_ids', []) update_candidates_on_cloudsearch(request.oauth_token, candidate_ids) return {'smartlist': {'id': smart_list.id}}, 201
def get(self, **kwargs): """ GET /talent-pipeline/<id>/smart_lists Fetch all smartlists of a talent_pipeline :return A dictionary containing smartlist objects of a talent_pipeline :rtype: dict """ talent_pipeline_id = kwargs.get('id') talent_pipeline = TalentPipeline.query.get(talent_pipeline_id) if not talent_pipeline: raise NotFoundError("Talent pipeline with id {} doesn't exist in database".format(talent_pipeline_id)) if request.user.role.name != 'TALENT_ADMIN' and talent_pipeline.user.domain_id != request.user.domain_id: raise ForbiddenError("Logged-in user and talent_pipeline belong to different domain") page = request.args.get('page', DEFAULT_PAGE) per_page = request.args.get('per_page', DEFAULT_PAGE_SIZE) if not is_number(page) or not is_number(per_page) or int(page) < 1 or int(per_page) < 1: raise InvalidUsage("page and per_page should be positive integers") page = int(page) per_page = int(per_page) total_number_of_smartlists = Smartlist.query.filter_by(talent_pipeline_id=talent_pipeline_id).count() smartlists = Smartlist.query.filter_by(talent_pipeline_id=talent_pipeline_id).order_by( Smartlist.added_time.desc()).paginate(page, per_page, False) smartlists = smartlists.items headers = generate_pagination_headers(total_number_of_smartlists, per_page, page) response = { 'page_number': page, 'smartlists_per_page': per_page, 'total_number_of_smartlists': total_number_of_smartlists, 'smartlists': [smartlist.to_dict() for smartlist in smartlists] } return ApiResponse(response=response, headers=headers, status=200)
def delete(self, **kwargs): """ DELETE /talent-pipeline/<id>/smartlists Remove smartlists from a talent_pipeline Take a JSON dictionary containing smartlist_ids :return A dictionary containing smartlist_ids successfully removed from a talent_pipeline :rtype: dict """ talent_pipeline_id = kwargs.get('id') talent_pipeline = TalentPipeline.query.get(talent_pipeline_id) if not talent_pipeline: raise NotFoundError("Talent pipeline with id {} doesn't exist in database".format(talent_pipeline_id)) posted_data = request.get_json(silent=True) if not posted_data or 'smartlist_ids' not in posted_data: raise InvalidUsage("Request body is empty or not provided") # Save user object(s) smartlist_ids = posted_data['smartlist_ids'] # Talent_pool object(s) must be in a list if not isinstance(smartlist_ids, list): raise InvalidUsage("Request body is not properly formatted") if request.user.role.name == 'USER' and talent_pipeline.user.id != request.user.id: raise ForbiddenError("Logged-in user doesn't have appropriate permissions to edit this talent-pipeline") if request.user.role.name != 'TALENT_ADMIN' and talent_pipeline.user.domain_id != request.user.domain_id: raise ForbiddenError("Logged-in user and talent_pipeline belong to different domain") for smartlist_id in smartlist_ids: if not is_number(smartlist_id): raise InvalidUsage('Smart List id {} should be an integer'.format(smartlist_id)) else: smartlist_id = int(smartlist_id) smartlist = Smartlist.query.get(smartlist_id) if smartlist.talent_pipeline_id != talent_pipeline_id: raise ForbiddenError("smartlist {} doesn't belong to talent_pipeline {}".format( smartlist.name, talent_pipeline_id)) smartlist.talent_pipeline_id = None db.session.commit() return { 'smartlist_ids': [int(smartlist_id) for smartlist_id in smartlist_ids] }
def get(self, **kwargs): """ GET /talent-pipelines/<id>/campaigns?fields=id,subject&page=1&per_page=20 Fetch all campaigns of a talent-pipeline. :return A dictionary containing list of campaigns belonging to a talent-pipeline :rtype: dict """ # Valid talent pipeline talent_pipeline_id = kwargs.get('id') talent_pipeline = TalentPipeline.query.get(talent_pipeline_id) if not talent_pipeline: raise NotFoundError("Talent pipeline with id {} doesn't exist in database".format(talent_pipeline_id)) if request.user.role.name != 'TALENT_ADMIN' and talent_pipeline.user.domain_id != request.user.domain_id: raise ForbiddenError("Logged-in user and talent_pipeline belong to different domain") page = request.args.get('page', DEFAULT_PAGE) per_page = request.args.get('per_page', 20) if not is_number(page) or not is_number(per_page) or int(page) < 1 or int(per_page) < 1: raise InvalidUsage("page and per_page should be positive integers") page = int(page) per_page = int(per_page) # Get the email campaigns include_fields = request.values['fields'].split(',') if request.values.get('fields') else None email_campaigns = talent_pipeline.get_email_campaigns(page=page, per_page=per_page) headers = generate_pagination_headers(talent_pipeline.get_email_campaigns_count(), per_page, page) response = { 'page_number': page, 'email_campaigns_per_page': per_page, 'total_number_of_email_campaigns': talent_pipeline.get_email_campaigns_count(), 'email_campaigns': [email_campaign.to_dict(include_fields) for email_campaign in email_campaigns] } return ApiResponse(response=response, headers=headers, status=200)
def get(self, **kwargs): """ GET /talent-pipelines/<id>/candidates/engagement?limit=5 Fetch candidates of a talent-pipeline :return A dictionary containing list of most engaged candidates belonging to a talent-pipeline :rtype: dict """ talent_pipeline_id = kwargs.get('id') limit = request.args.get('limit', 5) if not is_number(limit) or int(limit) < 1: raise InvalidUsage("Limit should be a positive integer") talent_pipeline = TalentPipeline.query.get(talent_pipeline_id) if not talent_pipeline: raise NotFoundError("Talent pipeline with id {} doesn't exist in database".format(talent_pipeline_id)) if request.user.role.name != 'TALENT_ADMIN' and talent_pipeline.user.domain_id != request.user.domain_id: raise ForbiddenError("Logged-in user and talent_pipeline belong to different domain") return {'candidates': top_most_engaged_candidates_of_pipeline(talent_pipeline_id, int(limit))}
def get(self, **kwargs): """ GET /candidates/<candidate_id>/talent-pipelines?limit=5 Fetch Engagement score of a candidate in each pipeline :return A dictionary containing list of most engaged candidates belonging to a talent-pipeline :rtype: dict """ candidate_id = kwargs.get('id') limit = request.args.get('limit', 5) if not is_number(limit) or int(limit) < 1: raise InvalidUsage("Limit should be a positive integer") candidate = Candidate.query.get(candidate_id) if not candidate: raise NotFoundError(error_message="Candidate with id {} doesn't exist in database".format(candidate_id)) if request.user.role.name != 'TALENT_ADMIN' and candidate.user.domain_id != request.user.domain_id: raise ForbiddenError("Logged-in user and candidate belong to different domain") return {'talent_pipelines': top_most_engaged_pipelines_of_candidate(candidate_id, int(limit))}
def get_stats_generic_function(container_object, container_name, user=None, from_date_string='', to_date_string='', interval=1, is_update=False, offset=0): """ This method will be used to get stats for talent-pools, talent-pipelines or smartlists. :param container_object: TalentPipeline, TalentPool or SmartList Object :param container_name: :param user: Logged-in user :param from_date_string: From Date String (In Client's Local TimeZone) :param to_date_string: To Date String (In Client's Local TimeZone) :param interval: Interval in days :param is_update: Either stats update process is in progress :param offset: Timezone offset from utc i.e. if client's lagging 4 hours behind utc, offset value should be -4 :return: """ if not container_object: raise NotFoundError("%s doesn't exist in database" % container_name) if user and container_object.user.domain_id != user.domain_id: raise ForbiddenError( "Logged-in user %s is unauthorized to get stats of %s: %s" % (user.id, container_name, container_object.id)) if not is_number(offset) or math.ceil(abs(float(offset))) > 12: raise InvalidUsage( "Value of offset should be an integer and less than or equal to 12" ) offset = int(math.ceil(float(offset))) current_date_time = datetime.utcnow() ninety_days_old_date_time = current_date_time - timedelta(days=90) try: # To convert UTC time to any other time zone we can use `offset_date_time` with inverted value of offset from_date = parse(from_date_string).replace(tzinfo=None) if from_date_string \ else offset_date_time(ninety_days_old_date_time, -1 * offset) to_date = parse(to_date_string).replace(tzinfo=None) if to_date_string else \ offset_date_time(current_date_time, -1 * offset) except Exception as e: raise InvalidUsage( "Either 'from_date' or 'to_date' is invalid because: %s" % e.message) if offset_date_time(from_date, offset) < container_object.added_time: from_date = offset_date_time(container_object.added_time, -1 * offset) if offset_date_time(from_date, offset) < ninety_days_old_date_time: raise InvalidUsage( "`Stats data older than 90 days cannot be retrieved`") if from_date > to_date: raise InvalidUsage("`to_date` cannot come before `from_date`") if offset_date_time(to_date, offset) > current_date_time: raise InvalidUsage("`to_date` cannot be in future") if not is_number(interval): raise InvalidUsage("Interval '%s' should be integer" % interval) interval = int(interval) if interval < 1: raise InvalidUsage( "Interval's value should be greater than or equal to 1 day") if container_name == 'TalentPipeline': get_stats_for_given_day = get_talent_pipeline_stat_for_given_day elif container_name == 'TalentPool': get_stats_for_given_day = get_talent_pool_stat_for_a_given_day elif container_name == 'SmartList': get_stats_for_given_day = get_smartlist_stat_for_a_given_day else: raise Exception("Container %s is not supported for this method" % container_name) list_of_stats_dicts = [] to_date = to_date.replace(hour=23, minute=59, second=59) from_date = from_date.replace(hour=23, minute=59, second=59) if is_update: to_date -= timedelta(days=interval) while to_date.date() >= from_date.date(): list_of_stats_dicts.append({ 'total_number_of_candidates': get_stats_for_given_day(container_object, offset_date_time(to_date, offset)), 'added_datetime': to_date.date().isoformat(), }) to_date -= timedelta(days=interval) reference_stat = get_stats_for_given_day(container_object, offset_date_time(to_date, offset)) for index, stat_dict in enumerate(list_of_stats_dicts): stat_dict['number_of_candidates_added'] = stat_dict[ 'total_number_of_candidates'] - ( list_of_stats_dicts[index + 1]['total_number_of_candidates'] if index + 1 < len(list_of_stats_dicts) else reference_stat) return list_of_stats_dicts
def get(self, **kwargs): """Retrieve list information List must belong to auth user's domain Call this resource from url: /v1/smartlists?page=1&page_size=10 :: to retrieve all the smartlists in user's domain /v1/smartlists/<int:id> :: to get single smartlist example: http://localhost:8008/v1/smartlists/2 Returns: List in following json format { "smartlist": { "total_found": 3, "user_id": 1, "id": 1, "name": "my list" "search_params": {"location": "San Jose, CA"} } } """ list_id = kwargs.get('id') candidate_count = request.args.get('candidate-count', False) if not is_number(candidate_count) or int(candidate_count) not in ( True, False): raise InvalidUsage("`candidate_count` field value can be 0 or 1") auth_user = request.user if list_id: smartlist = Smartlist.query.get(list_id) if not smartlist or smartlist.is_hidden: raise NotFoundError("List id does not exists") # check whether smartlist belongs to user's domain if request.user.role.name != 'TALENT_ADMIN' and smartlist.user.domain_id != auth_user.domain_id: raise ForbiddenError("List does not belong to user's domain") return { 'smartlist': create_smartlist_dict(smartlist, request.oauth_token, int(candidate_count)) } else: # Return all smartlists from user's domain page = request.args.get('page', DEFAULT_PAGE) per_page = request.args.get('per_page', DEFAULT_PAGE_SIZE) total_number_of_smartlists = Smartlist.query.join( Smartlist.user).filter(User.domain_id == auth_user.domain_id, Smartlist.is_hidden == 0).count() if not is_number(page) or not is_number( per_page) or int(page) < 1 or int(per_page) < 1: raise InvalidUsage( "page and per_page should be positive integers") page = int(page) per_page = int(per_page) headers = generate_pagination_headers(total_number_of_smartlists, per_page, page) response = { 'smartlists': get_all_smartlists(auth_user, request.oauth_token, int(page), int(per_page), candidate_count), 'page_number': page, 'smartlists_per_page': per_page, 'total_number_of_smartlists': total_number_of_smartlists } return ApiResponse(response=response, headers=headers, status=200)
def get(self, **kwargs): """ GET /talent-pipelines/<id> Fetch talent-pipeline object GET /talent-pipelines Fetch all talent-pipelines objects of domain of logged-in user :return A dictionary containing talent-pipeline's basic info or a dictionary containing all talent-pipelines of a domain :rtype: dict """ talent_pipeline_id = kwargs.get('id') interval_in_days = request.args.get('interval', 30) candidate_count = request.args.get('candidate-count', False) email_campaign_count = request.args.get('email-campaign-count', False) if not is_number(candidate_count) or int(candidate_count) not in (True, False): raise InvalidUsage("`candidate_count` field value can be 0 or 1") if not is_number(email_campaign_count) or int(email_campaign_count) not in (True, False): raise InvalidUsage("`email_campaign_count` field value can be 0 or 1") if not is_number(interval_in_days) or int(interval_in_days) < 0: raise InvalidUsage("Value of interval should be positive integer") if talent_pipeline_id: talent_pipeline = TalentPipeline.query.get(talent_pipeline_id) if not talent_pipeline: raise NotFoundError("Talent pipeline with id {} doesn't exist in database".format(talent_pipeline_id)) if request.user.role.name != 'TALENT_ADMIN' and talent_pipeline.user.domain_id != request.user.domain_id: raise ForbiddenError("Logged-in user and talent_pipeline belong to different domain") if not candidate_count: talent_pipeline_dict = talent_pipeline.to_dict(email_campaign_count=email_campaign_count) else: talent_pipeline_dict = talent_pipeline.to_dict(email_campaign_count=email_campaign_count, include_candidate_count=True, get_candidate_count=get_talent_pipeline_stat_for_given_day) talent_pipeline_dict.update({'engagement_score': get_pipeline_engagement_score(talent_pipeline_id)}) return {'talent_pipeline': talent_pipeline_dict} else: sort_by = request.args.get('sort_by', 'added_time') sort_type = request.args.get('sort_type', 'DESC') search_keyword = request.args.get('search', '').strip() owner_user_id = request.args.get('user_id', '') is_hidden = request.args.get('is_hidden', 0) from_date = request.args.get('from_date', EPOCH_TIME_STRING) to_date = request.args.get('to_date', datetime.utcnow().isoformat()) page = request.args.get('page', DEFAULT_PAGE) per_page = request.args.get('per_page', DEFAULT_PAGE_SIZE) if not is_number(is_hidden) or int(is_hidden) not in (0, 1): raise InvalidUsage('`is_hidden` can be either 0 or 1') if not is_number(page) or not is_number(per_page) or int(page) < 1 or int(per_page) < 1: raise InvalidUsage("page and per_page should be positive integers") page = int(page) per_page = int(per_page) if owner_user_id and is_number(owner_user_id) and not User.query.get(int(owner_user_id)): raise InvalidUsage("User: (%s) doesn't exist in system") if sort_by not in ('added_time', 'name', 'engagement_score', 'candidate_count'): raise InvalidUsage('Value of sort parameter is not valid') try: from_date = parser.parse(from_date).replace(tzinfo=None) to_date = parser.parse(to_date).replace(tzinfo=None) except Exception as e: raise InvalidUsage("from_date or to_date is not properly formatted: %s" % e) talent_pipelines_query = TalentPipeline.query.join(User).filter( TalentPipeline.is_hidden == is_hidden, User.domain_id == request.user.domain_id, from_date <= TalentPipeline.added_time, TalentPipeline.added_time <= to_date, or_( TalentPipeline.name.ilike('%' + search_keyword + '%'), TalentPipeline.description.ilike('%' + search_keyword + '%'))) if owner_user_id: talent_pipelines_query = talent_pipelines_query.filter(User.id == int(owner_user_id)) total_number_of_talent_pipelines = talent_pipelines_query.count() if sort_by not in ("engagement_score", "candidate_count"): if sort_by == 'added_time': sort_attribute = TalentPipeline.added_time else: sort_attribute = TalentPipeline.name talent_pipelines = talent_pipelines_query.order_by( sort_attribute.asc() if sort_type == 'ASC' else sort_attribute.desc()).paginate(page, per_page, False) talent_pipelines = talent_pipelines.items else: talent_pipelines = talent_pipelines_query.all() if candidate_count or sort_by == "candidate_count": talent_pipelines_data = [ talent_pipeline.to_dict(include_cached_candidate_count=True, email_campaign_count=email_campaign_count, get_candidate_count=get_talent_pipeline_stat_for_given_day) for talent_pipeline in talent_pipelines] else: talent_pipelines_data = [ talent_pipeline.to_dict(email_campaign_count=email_campaign_count) for talent_pipeline in talent_pipelines] for talent_pipeline_data in talent_pipelines_data: talent_pipeline_data['engagement_score'] = get_pipeline_engagement_score(talent_pipeline_data['id']) if sort_by in ("engagement_score", "candidate_count"): sort_by = 'total_candidates' if sort_by == "candidate_count" else "engagement_score" talent_pipelines_data = sorted( talent_pipelines_data, key=lambda talent_pipeline_data: talent_pipeline_data[sort_by], reverse=(False if sort_type == 'ASC' else True)) talent_pipelines_data = talent_pipelines_data[(page - 1) * per_page:page * per_page] headers = generate_pagination_headers(total_number_of_talent_pipelines, per_page, page) response = dict( talent_pipelines=talent_pipelines_data, page_number=page, talent_pipelines_per_page=per_page, total_number_of_talent_pipelines=total_number_of_talent_pipelines ) return ApiResponse(response=response, headers=headers, status=200)
def put(self, **kwargs): """ PUT /talent-pipelines/<id> Edit existing talent-pipeline Take a JSON dictionary containing TalentPipeline dictionary :return A dictionary containing id of edited talent-pipeline :rtype: dict """ talent_pipeline_id = kwargs.get('id') if not talent_pipeline_id: raise InvalidUsage("A valid talent_pipeline_id should be provided") talent_pipeline = TalentPipeline.query.get(talent_pipeline_id) if not talent_pipeline: raise NotFoundError("Talent pipeline with id {} doesn't exist in database".format(talent_pipeline_id)) if request.user.role.name == 'USER' and talent_pipeline.user.id != request.user.id: raise ForbiddenError("Logged-in user doesn't have appropriate permissions to edit this talent-pipeline") if request.user.role.name != 'TALENT_ADMIN' and talent_pipeline.user.domain_id != request.user.domain_id: raise ForbiddenError("Logged-in user and talent_pipeline belong to different domain") posted_data = request.get_json(silent=True) if not posted_data or 'talent_pipeline' not in posted_data: raise InvalidUsage("Request body is empty or not provided") posted_data = posted_data['talent_pipeline'] name = posted_data.get('name') description = posted_data.get('description', '') positions = posted_data.get('positions', '') date_needed = posted_data.get('date_needed', '') talent_pool_id = posted_data.get('talent_pool_id', '') is_hidden = posted_data.get('is_hidden', 0) search_params = posted_data.get('search_params', dict()) if name is not None: if name: if TalentPipeline.query.join(TalentPipeline.user).filter( and_(TalentPipeline.name == name, User.domain_id == request.user.domain_id)).first(): raise InvalidUsage("Talent pipeline with name {} already exists in domain {}".format( name, request.user.domain_id)) talent_pipeline.name = name else: raise InvalidUsage("Name cannot be an empty string") if date_needed: try: parser.parse(date_needed) except Exception as e: raise InvalidUsage("Date_needed is not valid as: {}".format(e.message)) if parser.parse(date_needed) < datetime.utcnow(): raise InvalidUsage("Date_needed {} cannot be before current date".format(date_needed)) talent_pipeline.date_needed = date_needed if positions: if not is_number(positions) or not int(positions) > 0: raise InvalidUsage("Number of positions should be integer and greater than zero") talent_pipeline.positions = positions if description: talent_pipeline.description = description if talent_pool_id: if not is_number(talent_pool_id): raise InvalidUsage("talent_pool_id should be an integer") talent_pool_id = int(talent_pool_id) talent_pool = TalentPool.query.get(talent_pool_id) if not talent_pool: raise NotFoundError("Talent pool with id {} doesn't exist in database".format(talent_pool_id)) if talent_pool.domain_id != request.user.domain_id: raise ForbiddenError("Logged-in user and given talent-pool belong to different domain") talent_pipeline.talent_pool_id = talent_pool_id if search_params: if not isinstance(search_params, dict): raise InvalidUsage("search_params is not provided in valid format") # Put into params dict for key in search_params: if key not in TALENT_PIPELINE_SEARCH_PARAMS and not key.startswith('cf-'): raise NotFoundError("Key[{}] is invalid".format(key)) talent_pipeline.search_params = json.dumps(search_params) if not is_number(is_hidden) or (int(is_hidden) not in (0, 1)): raise InvalidUsage("Possible vaues of `is_hidden` are 0 and 1") talent_pipeline.is_hidden = int(is_hidden) for smartlist in Smartlist.query.filter(Smartlist.talent_pipeline_id == talent_pipeline_id): smartlist.is_hidden = int(is_hidden) db.session.commit() return { 'talent_pipeline': {'id': talent_pipeline.id} }
def post(self, **kwargs): """ POST /talent-pipelines Add new talent-pipelines to Database input: {'talent_pipelines': [talent_pipeline_dict1, talent_pipeline_dict2, talent_pipeline_dict3, ... ]} Take a JSON dictionary containing array of TalentPipeline dictionaries A single talent-pipelines dict must contain pipelines's name, date_needed, talent_pool_id :return A dictionary containing ids of added talent-pipelines :rtype: dict """ posted_data = request.get_json(silent=True) if not posted_data or 'talent_pipelines' not in posted_data: raise InvalidUsage("Request body is empty or not provided") # Save user object(s) talent_pipelines = posted_data['talent_pipelines'] # TalentPipeline object(s) must be in a list if not isinstance(talent_pipelines, list): raise InvalidUsage("Request body is not properly formatted") talent_pipeline_objects = [] for talent_pipeline in talent_pipelines: name = talent_pipeline.get('name', '') description = talent_pipeline.get('description', '') positions = talent_pipeline.get('positions', 1) date_needed = talent_pipeline.get('date_needed', '') talent_pool_id = talent_pipeline.get('talent_pool_id', '') search_params = talent_pipeline.get('search_params', dict()) if not name or not date_needed or not talent_pool_id: raise InvalidUsage("A valid name, date_needed, talent_pool_id should be provided to " "create a new talent-pipeline") if TalentPipeline.query.join(TalentPipeline.user).filter(and_( TalentPipeline.name == name, User.domain_id == request.user.domain_id)).first(): raise InvalidUsage( "Talent pipeline with name {} already exists in domain {}".format(name, request.user.domain_id)) try: date_needed = parser.parse(date_needed) except Exception as e: raise InvalidUsage("Date_needed is not valid as: {}".format(e.message)) if not is_number(positions) or not int(positions) > 0: raise InvalidUsage("Number of positions should be integer and greater than zero") if not is_number(talent_pool_id): raise InvalidUsage("talent_pool_id should be an integer") talent_pool_id = int(talent_pool_id) talent_pool = TalentPool.query.get(talent_pool_id) if not talent_pool: raise NotFoundError("Talent pool with id {} doesn't exist in database".format(talent_pool_id)) if talent_pool.domain_id != request.user.domain_id: raise ForbiddenError("Logged-in user and given talent-pool belong to different domain") if search_params: if not isinstance(search_params, dict): raise InvalidUsage("search_params is not provided in valid format") # Put into params dict for key in search_params: if key not in TALENT_PIPELINE_SEARCH_PARAMS and not key.startswith('cf-'): raise NotFoundError("Key[{}] is invalid".format(key)) search_params = json.dumps(search_params) if search_params else None talent_pipeline = TalentPipeline(name=name, description=description, positions=positions, date_needed=date_needed, user_id=request.user.id, talent_pool_id=talent_pool_id, search_params=search_params) db.session.add(talent_pipeline) talent_pipeline_objects.append(talent_pipeline) db.session.commit() return { 'talent_pipelines': [talent_pipeline_object.id for talent_pipeline_object in talent_pipeline_objects] }
def delete(self, **kwargs): """ DELETE /talent-pools/<id>/candidates Remove input candidates from talent-pool input: {'talent_pool_candidates': [talent_pool_candidate_id1, talent_pool_candidate_id2, ... ]} :return A dictionary containing candidate_ids which have been removed successfully :rtype: dict """ talent_pool_id = kwargs.get('id') posted_data = request.get_json(silent=True) if not posted_data or 'talent_pool_candidates' not in posted_data: raise InvalidUsage("Request body is empty or not provided") # Save user object(s) talent_pool_candidate_ids = posted_data['talent_pool_candidates'] # Talent_pool object(s) must be in a list if not isinstance(talent_pool_candidate_ids, list): raise InvalidUsage("Request body is not properly formatted") talent_pool = TalentPool.query.get(talent_pool_id) if not talent_pool: raise NotFoundError( "Talent pool with id {} doesn't exist in database".format( talent_pool_id)) if request.user.role.name != 'TALENT_ADMIN' and talent_pool.domain_id != request.user.domain_id: raise ForbiddenError( "Talent pool and logged in user belong to different domains") talent_pool_group = TalentPoolGroup.query.filter_by( user_group_id=request.user.user_group_id, talent_pool_id=talent_pool_id).first() if request.user.role.name == 'USER' and not talent_pool_group: raise ForbiddenError( "User {} doesn't have appropriate permissions to " "remove candidates".format(request.user.id)) for talent_pool_candidate_id in talent_pool_candidate_ids: if not is_number(talent_pool_candidate_id): raise InvalidUsage( 'Candidate id {} should be an integer'.format( talent_pool_candidate_id)) else: talent_pool_candidate_id = int(talent_pool_candidate_id) talent_pool_candidate = TalentPoolCandidate.query.filter_by( candidate_id=talent_pool_candidate_id, talent_pool_id=talent_pool_id).first() if not talent_pool_candidate: raise NotFoundError( "Candidate {} doesn't belong to talent-pool {}".format( talent_pool_candidate_id, talent_pool_id)) else: db.session.delete(talent_pool_candidate) db.session.commit() try: # Update Candidate Documents in Amazon Cloud Search headers = { 'Authorization': request.oauth_token, 'Content-Type': 'application/json' } response = requests.post( CandidateApiUrl.CANDIDATES_DOCUMENTS_URI, headers=headers, data=json.dumps({'candidate_ids': talent_pool_candidate_ids})) if response.status_code != 204: raise Exception("Status Code: {} Response: {}".format( response.status_code, response.json())) except Exception as e: raise InvalidUsage( "Couldn't update Candidate Documents in Amazon Cloud Search. Because: {}" .format(e.message)) return { 'talent_pool_candidates': [ int(talent_pool_candidate_id) for talent_pool_candidate_id in talent_pool_candidate_ids ] }
def get(self, **kwargs): """ GET /talent-pools/<id> Fetch talent-pool object GET /talent-pools?domain_id=1 Fetch all talent-pool objects of domain of logged-in user :return A dictionary containing talent-pool basic info or a dictionary containing all talent-pools of a domain :rtype: dict """ talent_pool_id = kwargs.get('id') # Getting a single talent-pool if talent_pool_id: talent_pool = TalentPool.query.get(talent_pool_id) if not talent_pool: raise NotFoundError( "Talent pool with id {} doesn't exist in database".format( talent_pool_id)) if request.user.role.name != 'TALENT_ADMIN' and talent_pool.domain_id != request.user.domain_id: raise ForbiddenError( "User {} is not authorized to get talent-pool's info". format(request.user.id)) talent_pool_group = TalentPoolGroup.query.filter_by( user_group_id=request.user.user_group_id, talent_pool_id=talent_pool_id).all() if request.user.role.name == 'USER' and not talent_pool_group: raise ForbiddenError( "User {} doesn't have appropriate permissions to get " "talent-pools's info".format(request.user.id)) return { 'talent_pool': { 'id': talent_pool.id, 'name': talent_pool.name, 'description': talent_pool.description, 'domain_id': talent_pool.domain_id, 'user_id': talent_pool.user_id, 'added_time': talent_pool.added_time.isoformat(), 'updated_time': talent_pool.updated_time.isoformat() } } # Getting all talent-pools of logged-in user's domain else: domain_id = request.user.domain_id # Get all Talent Pools of any domain if user is `TALENT_ADMIN` if request.user.role.name == 'TALENT_ADMIN' and request.args.get( 'domain_id'): domain_id = request.args.get('domain_id') if not is_number(domain_id) or not Domain.query.get( int(domain_id)): raise InvalidUsage("Invalid Domain Id is provided") talent_pools = TalentPool.query.filter_by( domain_id=int(domain_id)).all() return { 'talent_pools': [{ 'id': talent_pool.id, 'name': talent_pool.name, 'description': talent_pool.description, 'user_id': talent_pool.user_id, 'added_time': talent_pool.added_time.isoformat(), 'updated_time': talent_pool.updated_time.isoformat(), 'accessible_to_user_group_ids': [ talent_pool_group.user_group_id for talent_pool_group in TalentPoolGroup.query. filter_by(talent_pool_id=talent_pool.id).all() ] } for talent_pool in talent_pools] }