# Copyright Sage Vaillancourt 2021 import json import os import subprocess import threading import urllib.parse from flask import (Blueprint, render_template, request, make_response, session, redirect, jsonify) from wtforms import Form, SelectField, StringField, TextAreaField, validators from email_validator import validate_email, EmailNotValidError import undercover.db as db import undercover.email as email from undercover.pdf_builder import CLData writing_blueprint = Blueprint('writing', __name__,) class CLForm(Form): letterName = SelectField( 'Letter Name:', [validators.optional()], choices=[(1, 'LETTER TITLE')] ) username = StringField( 'Username:', [validators.Length(min=4, max=99)], default="Sage" ) company = StringField( 'Company:', [validators.Length(min=2, max=99)], default="BananaCorp" ) jobAndPronoun = StringField( 'Job and Pronoun (a/an):', [validators.Length(min=4, max=99)], default="a banana stocker" ) skillTypes = StringField( 'Skill Type:', [validators.Length(min=2, max=99)], default="practical" ) mySkills = StringField( 'My Skills:', [validators.Length(min=2, max=99)], default="stocking bananas" ) closingText = TextAreaField( 'Closing Text:', [validators.Length(min=2, max=99)], default="I look forward to hearing from you" ) body = TextAreaField( 'Body:', [validators.Length(min=4, max=9999)], default=( "My name is {\\username}. I'm excited for the opportunity to work as " "{\\jobAndPronoun} with your company. I think my {\\skillTypes} knowledge " "of {\\mySkills} could contribute well to your team.\n\n" "I am passionate about what I do, and I think we would work well together.\n\n" "Thank you for your consideration." ) ) def render_index(form=CLForm(), error=None, status=200, letter_errors=None): return make_response( render_template( 'writing.jinja2', form=form, username=session.get('username'), error=error, letter_errors=letter_errors, ), status) @writing_blueprint.route('/login', methods=['POST', 'GET']) def login(): if request.method == 'POST': username = request.form['login'] if db.login(username, request.form['password']): session['username'] = username return redirect('/') return render_index(error="Invalid username or password", status=401) return '''

''' @writing_blueprint.route('/logout', methods=['POST', 'GET']) def logout(): session.pop('username', None) return redirect('/') @writing_blueprint.route('/', methods=['GET']) def index_get(): email_address = session.get('username') if not email_address: return render_index() form = CLForm() user = db.get_user(email_address) letters = db.get_user_letters(user.id) if len(letters) == 0: return render_index() letter_names = [(i + 1, letter.title) for i, letter in enumerate(letters)] form.letterName.choices = letter_names form.letterName.data = 1 selected_letter = request.args.get('letter_name') if selected_letter: for i, letter in enumerate(letters): if letter.title == selected_letter: form.letterName.data = i + 1 break # TODO: Load this data more dynamically # I.e. use a dictionary instead of explicitly-defined fields data = json.loads(letters[form.letterName.data - 1].contents) # Ensures default value is set form.letterName.process_data(form.letterName.data) form.company.data = data['company'] form.body.data = data['body'] form.closingText.data = data['closingText'] form.jobAndPronoun.data = data['jobAndPronoun'] form.mySkills.data = data['mySkills'] form.skillTypes.data = data['skillTypes'] form.username.data = data['username'] return render_index(form=form) @writing_blueprint.route('/create_account', methods=['GET']) def create_account_page(): return render_template('create_account.jinja2') @writing_blueprint.route('/create_account', methods=['POST']) def create_account(): email_address = request.form['login'] try: validate_email(email_address, check_deliverability=True) except EmailNotValidError as e: return render_index(error=str(e), status=401) if db.get_user(email_address): return render_index(error="A user with that email already exists!", status=401) db.add_user(email_address, request.form['password']) session['username'] = email_address return redirect('/') @writing_blueprint.route('/reset', methods=['POST', 'GET']) def reset_password(): if request.method == 'POST': email_address = request.form.get('login') existing_reset_id = request.form.get('reset_id') if email_address: reset_id = db.initiate_password_reset(email_address) if reset_id: if not email.send_password_reset(email_address, 'https://undercover.cafe/reset?id=' + str(reset_id)): return render_index(error="Failed to send reset email. Please try again later.", status=500) elif existing_reset_id: new_password = request.form['password'] if not db.complete_reset(existing_reset_id, new_password): return render_index(error="Password reset failed. Your reset link may have expired.", status=500) # TODO: Log in? return redirect('/') query_reset_id = request.args.get('id') # TODO: Add password validation return f'''

''' @writing_blueprint.route('/dbtest', methods=['GET']) def db_test_get(): response = make_response(db.get_user_letters(1)[0].contents, 200) response.mimetype = "text/plain" return response @writing_blueprint.route('/update', methods=['POST']) def update_get(): expected_token = os.environ['GITLAB_HOOK_TOKEN'] given_token = request.headers['X-Gitlab-Token'] event_type = request.headers['X-Gitlab-Event'] if expected_token == given_token and event_type == "Push Hook": print("Update notification received.") response = make_response("", 200) response.mimetype = "text/plain" threading.Timer(5, git_update, []).start() return response else: return make_response("", 404) def git_update(): script = os.environ['UPDATE_SCRIPT_PATH'] if not script: return subprocess.run(['bash', '-c', "test -f " + script + " && " + script]) @writing_blueprint.route('/', methods=['POST']) def generate_pdf(): form = CLForm(request.form) if form.validate(): selected_letter = form.letterName.data or '1' data = CLData( selectedLetter=int(selected_letter) - 1, username=form.username.data, company=form.company.data, jobAndPronoun=form.jobAndPronoun.data, skillTypes=form.skillTypes.data, mySkills=form.mySkills.data, closingText=form.closingText.data, body=form.body.data, ) email_address = session.get('username') if email_address: user = db.get_user(email_address) letters = db.get_user_letters(user.id) letter_json = jsonify(data).get_data(True) if len(letters) == 0: db.add_letter(user.id, 'My Cover Letter', letter_json) else: letter = letters[data.selectedLetter] # TODO: Support title editing db.edit_letter(letter.id, letter.title, letter_json) try: resp = data.generate_pdf() except ValueError as e: resp = render_index(form=form, letter_errors=e.args[0]) # Save entered data as cookies on user's machine for pair in data.get_pairs(): resp.set_cookie(pair[0], urllib.parse.quote(pair[1])) return resp return render_index(form=form)