def get(self): """ Parameters: - location (str) - query (str) - results_per_page (int) - page (int) - sort_criteria (str - "relevance", "date", "salary") Returns a JSON object: { jobs: [ { company, title, locations, url, date, description, salary, salary_type, salary_currency_code, salary_min, salary_max, site, }, ... ] } """ # Run `pydoc careerjet_api` to see documentation. printColoured(" * Getting a list of jobs") request_params = dict(request.args) pretty_print_dict(request_params) # TODO: Checking if all mandatory requests parameters have been sent through if not all( param in request_params and request_params for param in ["location", "query", "results_per_page", "page", "sort_criteria" ]): printColoured(" * Missing mandatory fields", colour="red") raise InvalidUserInput( description="Request parameter is missing mandatory fields") try: return get_job_postings(request.args.get("location"), request.args.get("query"), request.args.get("results_per_page"), request.args.get("page"), request.args.get("sort_criteria")) except Exception as err: printColoured( " * CareerJet API Client failed to fetch jobs. Error: {}". format(err), colour="red") raise InvalidUserInput( description="Couldn't find any jobs. Try a different query")
def fetch_stats(user_id: str, board_id: str): """ Fetches all stats associated with the given board """ target_board = db.boards.find_one({"_id": ObjectId(board_id)}) if target_board["user_id"] != user_id: raise InvalidUserInput(description="That board doesn't belong to you") if not target_board: raise InvalidUserInput( description="Board {} wasn't found".format(board_id)) return target_board["statistics"]
def update_job(user_id, board_id, job_id, updated_job): """ Updates an existing tracked job for a given user's board """ target_board = db.boards.find_one({ "_id": ObjectId(board_id), "user_id": user_id }) new_jobs = target_board["tracked_jobs"].copy() # Find the target job target_index = -1 for job in new_jobs: target_index += 1 if job["job_id"] == job_id: break if target_index == -1: raise InvalidUserInput( description="Failed to find job with ID: {}".format(job_id)) new_jobs[target_index] = updated_job db.boards.update_one({ "_id": ObjectId(board_id), "user_id": user_id }, {"$set": { "tracked_jobs": new_jobs.copy() }}) return updated_job
def add_job(board_id: str, user_id: str, job_to_track: dict) -> dict: """ Adds a job to be tracked Parameters: - board_id - user_id - job_to_track """ # TODO: What happens on failure? # Additional fields job_to_track["current_status"] = "application" job_to_track["notes"] = "" job_to_track["priority"] = 5 job_to_track["events"] = [] # Assign a random ID. TODO: not robust job_to_track["job_id"] = "{}-{}".format(board_id, str(uuid.uuid4())) if job_already_tracked(user_id, board_id, job_to_track): raise InvalidUserInput(description="You're already tracking that job") # Push the new job into the board's tracked_jobs list db.boards.update_one({ "_id": ObjectId(board_id), "user_id": user_id }, {"$push": { "tracked_jobs": job_to_track }}) return job_to_track["job_id"]
def get_board(user_id: str, board_id: str): board = db.boards.find_one({"user_id": user_id, "_id": ObjectId(board_id)}) if not board: raise InvalidUserInput( description="Couldn't find the board with id: {}".format(board_id)) board["_id"] = str(board["_id"]) return board
def add_user(username: str, email: str, password: str, image_url="") -> str: """ Registers a new user and commits them to the database. Parameters: - username - email - password Returns: - token - user_id """ if user_exists(email): raise InvalidUserInput( description="A user with that email already exists") inserted_user = db.users.insert_one({ "username": username, "email": email, "password": password, "image_url": image_url, "experience": "", "title": "Job seeker", "phone": "", "skills": [], "resume": {}, "favourited_companies": [], "resume_fields": {}, "starred_by": [], "tracking": [], "tracked_by": [] }) return str(inserted_user.inserted_id)
def post(self): """ Pushes a new job to be tracked under a specific board owned by a user Parameters: - user_id - board_id - job_to_track """ printColoured(" * Tracking a new job", colour="yellow") request_params = dict(request.get_json()) try: board_id = request_params["board_id"] user_id = request_params["user_id"] job_to_track = request_params["job_to_track"] except KeyError as err: raise InvalidUserInput( description="Missing mandatory fields: {}".format(err)) job_id = add_job(board_id, user_id, job_to_track) push_stat( board_id, { "timestamp": int(time.time() - OFFSET), "activity": "application", "job_id": job_id }) return job_to_track
def login_user(email: str, password: str) -> str: """ Retrieves a user matching the supplied fields. Parameters: - email - password Returns: - token - user_id """ target_user = db.users.find_one({"email": email}) if not target_user: raise InvalidUserInput( description="An account with that email doesn't exist") if not target_user["password"] == password: raise InvalidUserInput(description="Password incorrect") return str(target_user["_id"])
def get_favourite_company(user_id: str): # Find the user, then get and return the favourited companies name array user = db.users.find_one({"_id": ObjectId(user_id)}) if not user: raise InvalidUserInput( description="Couldn't find the user with id: {}".format(user_id)) return user["favourited_companies"]
def get_user_profile(user_id: str): """ Get the user's profile fields. """ user = db.users.find_one({"_id": ObjectId(user_id)}) if not user: raise InvalidUserInput( description="Couldn't find user of ID: {}".format(user_id)) user["_id"] = str(user["_id"]) return user
def get_job_postings(location, query, results_per_page, page, sort_criteria): """ Gets job postings """ cj = CareerjetAPIClient("en_AU") jobs_json = cj.search({ "location": location, "keywords": query, "affid": "213e213hd12344552", "pagesize": results_per_page, "page": page, "sort": sort_criteria, "user_ip": "11.22.33.44", "url": "http://www.example.com/jobsearch", "user_agent": "Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Firefox/31.0" }) try: for each_job in jobs_json["jobs"]: # Strip all leading non-alphanumeric characters each_job["description"] = re.sub( "^[^A-Za-z0-9]*", "", each_job["description"]).capitalize() # Truncate duplicate whitespaces each_job["description"] = re.sub("\s+", " ", each_job["description"]) each_job["description"] = re.sub("<b>", "", each_job["description"]) each_job["description"] = re.sub("</b>", "", each_job["description"]) # Capitalise all words occurring after punctuation such as . or ! p = re.compile(r'(?<=[\.\?!]\s)(\w+)') each_job["description"] = p.sub( lambda match: match.group().capitalize(), each_job["description"]) except Exception as err: printColoured("Failed to fetch jobs '{}'. Error: {}".format( query, err), colour="red") raise InvalidUserInput( description="Failed to find jobs for '{}'".format(query)) return dict(jobs_json)
def save_favourite_company(user_id: str, company_name: str): # check quantity fav_companies = get_favourite_company(user_id) if len(fav_companies) > 10: raise InvalidUserInput( description="You can't have more than 10 favourite companies") # Find the user, then push the company_name into the favourited_companies field db.users.update_one({ "_id": ObjectId(user_id), }, {"$push": { "favourited_companies": company_name }}) return company_name
def vote_comment(voter_id: str, comment_id: str, increment_amount: int): """ Increases the vote by the amount specified. Negative values denote downvoting """ comment = db.comments.find_one({"_id": ObjectId(comment_id)}) if voter_id in [voter["voter_id"] for voter in comment["voters"]]: raise InvalidUserInput(description="You have already voted") db.comments.update_one({"_id": ObjectId(comment_id)}, { "$inc": { "vote": increment_amount }, "$addToSet": { "voters": { "voter_id": voter_id, "vote_amount": increment_amount } } })
def clear_vote(voter_id: str, comment_id: str): comment = db.comments.find_one({"_id": ObjectId(comment_id)}) voter = [ voter for voter in comment["voters"] if voter["voter_id"] == voter_id ][0] if not voter: raise InvalidUserInput( description="Can't clear a vote that doesn't exist") vote_amount = voter["vote_amount"] db.comments.update_one({"_id": ObjectId(comment_id)}, { "$pull": { "voters": { "voter_id": voter_id } }, "$inc": { "vote": -vote_amount } })
def get_content(url): try: web_page = requests.get(url, allow_redirects=True, timeout=5) except requests.exceptions.Timeout as err: raise ServerException( description= "Failed to fetch web page in time! Skipping preprocessing") soup = BeautifulSoup(web_page.content, "html.parser") content = str(soup.section) try: for field in soup.find('ul', attrs={"class": "details"}).children: field_str = str(field) field_str = field_str.replace("\n", "") print(field_str) if "#icon-contract" in field_str: m = findall(r"svg>(\w|\s)+<\/li>", field_str) # print(field.string) sanitiser = Sanitizer() content = sanitiser.sanitize(content) return {"post_details": content, "fields": {}} except: raise InvalidUserInput( description="Couldn't find details for that job")
def get_company_details(company): """ Params: - company (str) Returns: - company_description (str) """ wiki_wiki = Wikipedia('en') try: # try different methods for searching for the company until something good is returned page = wiki_wiki.page(company + " (company)") if not page.exists(): page = wiki_wiki.page(company) except Exception as err: printColoured(err, colour="red") raise InvalidUserInput( description="Connection timed out. Please try again later") company_data = page.text company_description = company_data.split("\n")[0] return company_description
def get(self): """ Fetches user activity data for each date. Preprocesses it so that each date has a list of activities the user did. This makes it easy for the frontend to render graphically Parameters: - user_id - board_id - start time - end time """ printColoured(" * Getting user activity stats", colour="yellow") request_params = dict(request.args) user_id = request_params["user_id"] board_id = request_params["board_id"] stats = fetch_stats(user_id, board_id) # Sort timestamps into ascending order stats.sort(key=lambda x: x["timestamp"]) start_date = datetime.fromtimestamp(int(request_params["start_time"])) end_date = datetime.fromtimestamp(int(request_params["end_time"])) delta = end_date - start_date if (delta.days < 0): raise InvalidUserInput( description= "Invalid time range. Check that the start time is after end time" ) date_list = {} # METHOD 1 - iterating through the entire stats array for each day # takes longer but more confident that it is more accurate for i in range(delta.days + 2): day = start_date + timedelta(days=i) day = day.strftime('%d/%m/%Y') date_list[day] = [] for j in range(len(stats)): curr_day = datetime.fromtimestamp( stats[j]['timestamp']).strftime('%d/%m/%Y') if curr_day != day: continue date_list[day].append((stats[j]['activity'])) date_list[day].sort() # METHOD 2 - stop iterating through the stats array when dates no longer match # keeps track of last position in stats array so no need to iterate through days that have already been matched # takes shorter time but might be less accurate '''for i in range(delta.days + 2): day = (start_date + timedelta(days = i)).strftime('%d/%m/%Y') k = 0 for j in range(k, len(stats)): curr_day = datetime.fromtimestamp(stats[j]['timestamp']).strftime('%d/%m/%Y') if curr_day < day: continue elif curr_day > day: k = j break if day not in date_list.keys(): activity_list = [] activity_list.append((stats[j]['activity'])) activity_list.sort() date_list[day] = activity_list''' # For each day between start time and end time, return date_list