def get_alias_contacts_route(alias_id): """ Get alias contacts Input: page_id: in query Output: - contacts: list of contacts: - creation_date - creation_timestamp - last_email_sent_date - last_email_sent_timestamp - contact - reverse_alias """ user = g.user try: page_id = int(request.args.get("page_id")) except (ValueError, TypeError): return jsonify(error="page_id must be provided in request query"), 400 gen_email: GenEmail = GenEmail.get(alias_id) if gen_email.user_id != user.id: return jsonify(error="Forbidden"), 403 contacts = get_alias_contacts(gen_email, page_id) return jsonify(contacts=contacts), 200
def alias_log(alias_id, page_id): gen_email = GenEmail.get(alias_id) # sanity check if not gen_email: flash("You do not have access to this page", "warning") return redirect(url_for("dashboard.index")) if gen_email.user_id != current_user.id: flash("You do not have access to this page", "warning") return redirect(url_for("dashboard.index")) logs = get_alias_log(gen_email, page_id) base = (db.session.query(ForwardEmail, ForwardEmailLog).filter( ForwardEmail.id == ForwardEmailLog.forward_id).filter( ForwardEmail.gen_email_id == gen_email.id)) total = base.count() email_forwarded = (base.filter(ForwardEmailLog.is_reply == False).filter( ForwardEmailLog.blocked == False).count()) email_replied = base.filter(ForwardEmailLog.is_reply == True).count() email_blocked = base.filter(ForwardEmailLog.blocked == True).count() last_page = (len(logs) < PAGE_LIMIT ) # lightweight pagination without counting all objects return render_template("dashboard/alias_log.html", **locals())
def update_alias(alias_id): """ Update alias note Input: alias_id: in url note: in body Output: 200 """ data = request.get_json() if not data: return jsonify(error="request body cannot be empty"), 400 user = g.user gen_email: GenEmail = GenEmail.get(alias_id) if gen_email.user_id != user.id: return jsonify(error="Forbidden"), 403 new_note = data.get("note") gen_email.note = new_note db.session.commit() return jsonify(note=new_note), 200
def create_contact_route(alias_id): """ Create contact for an alias Input: alias_id: in url contact: in body Output: 201 if success 409 if contact already added """ data = request.get_json() if not data: return jsonify(error="request body cannot be empty"), 400 user = g.user gen_email: GenEmail = GenEmail.get(alias_id) if gen_email.user_id != user.id: return jsonify(error="Forbidden"), 403 contact_email = data.get("contact") # generate a reply_email, make sure it is unique # not use while to avoid infinite loop reply_email = f"ra+{random_string(25)}@{EMAIL_DOMAIN}" for _ in range(1000): reply_email = f"ra+{random_string(25)}@{EMAIL_DOMAIN}" if not ForwardEmail.get_by(reply_email=reply_email): break website_email = get_email_part(contact_email) # already been added if ForwardEmail.get_by(gen_email_id=gen_email.id, website_email=website_email): return jsonify(error="Contact already added"), 409 forward_email = ForwardEmail.create( gen_email_id=gen_email.id, website_email=website_email, website_from=contact_email, reply_email=reply_email, ) LOG.d("create reverse-alias for %s %s", contact_email, gen_email) db.session.commit() return jsonify(**serialize_forward_email(forward_email)), 201
def get_alias_activities(alias_id): """ Get aliases Input: page_id: in query Output: - activities: list of activity: - from - to - timestamp - action: forward|reply|block """ user = g.user try: page_id = int(request.args.get("page_id")) except (ValueError, TypeError): return jsonify(error="page_id must be provided in request query"), 400 gen_email: GenEmail = GenEmail.get(alias_id) if gen_email.user_id != user.id: return jsonify(error="Forbidden"), 403 alias_logs = get_alias_log(gen_email, page_id) activities = [] for alias_log in alias_logs: activity = {"timestamp": alias_log.when.timestamp} if alias_log.is_reply: activity["from"] = alias_log.alias activity["to"] = alias_log.website_from or alias_log.website_email activity["action"] = "reply" else: activity["to"] = alias_log.alias activity[ "from"] = alias_log.website_from or alias_log.website_email if alias_log.bounced: activity["action"] = "bounced" elif alias_log.blocked: activity["action"] = "block" else: activity["action"] = "forward" activities.append(activity) return jsonify(activities=activities), 200
def delete_alias(alias_id): """ Delete alias Input: alias_id: in url Output: 200 if deleted successfully """ user = g.user gen_email = GenEmail.get(alias_id) if gen_email.user_id != user.id: return jsonify(error="Forbidden"), 403 GenEmail.delete(alias_id) db.session.commit() return jsonify(deleted=True), 200
def toggle_alias(alias_id): """ Enable/disable alias Input: alias_id: in url Output: 200 along with new status: - enabled """ user = g.user gen_email: GenEmail = GenEmail.get(alias_id) if gen_email.user_id != user.id: return jsonify(error="Forbidden"), 403 gen_email.enabled = not gen_email.enabled db.session.commit() return jsonify(enabled=gen_email.enabled), 200
def unsubscribe(gen_email_id): gen_email = GenEmail.get(gen_email_id) if not gen_email: flash("Incorrect link. Redirect you to the home page", "warning") return redirect(url_for("dashboard.index")) if gen_email.user_id != current_user.id: flash( "You don't have access to this page. Redirect you to the home page", "warning", ) return redirect(url_for("dashboard.index")) # automatic unsubscribe, according to https://tools.ietf.org/html/rfc8058 if request.method == "POST": gen_email.enabled = False flash(f"Alias {gen_email.email} has been blocked", "success") db.session.commit() return redirect(url_for("dashboard.index")) else: # ask user confirmation return render_template("dashboard/unsubscribe.html", alias=gen_email.email)
def index(): # after creating a gen email, it's helpful to highlight it highlight_gen_email_id = session.get(HIGHLIGHT_GEN_EMAIL_ID) # reset as it should not persist if highlight_gen_email_id: del session[HIGHLIGHT_GEN_EMAIL_ID] query = request.args.get("query") or "" # User generates a new email if request.method == "POST": if request.form.get("form-name") == "trigger-email": gen_email_id = request.form.get("gen-email-id") gen_email = GenEmail.get(gen_email_id) LOG.d("trigger an email to %s", gen_email) email_utils.send_test_email_alias(gen_email.email, gen_email.user.name) flash( f"An email sent to {gen_email.email} is on its way, please check your inbox/spam folder", "success", ) elif request.form.get("form-name") == "create-custom-email": if current_user.can_create_new_alias(): return redirect(url_for("dashboard.custom_alias")) else: flash(f"You need to upgrade your plan to create new alias.", "warning") elif request.form.get("form-name") == "create-random-email": if current_user.can_create_new_alias(): scheme = int( request.form.get("generator_scheme") or current_user.alias_generator ) if not scheme or not AliasGeneratorEnum.has_value(scheme): scheme = current_user.alias_generator gen_email = GenEmail.create_new_random( user_id=current_user.id, scheme=scheme ) db.session.commit() LOG.d("generate new email %s for user %s", gen_email, current_user) flash(f"Alias {gen_email.email} has been created", "success") session[HIGHLIGHT_GEN_EMAIL_ID] = gen_email.id else: flash(f"You need to upgrade your plan to create new alias.", "warning") elif request.form.get("form-name") == "switch-email-forwarding": gen_email_id = request.form.get("gen-email-id") gen_email: GenEmail = GenEmail.get(gen_email_id) LOG.d("switch email forwarding for %s", gen_email) gen_email.enabled = not gen_email.enabled if gen_email.enabled: flash(f"Alias {gen_email.email} is enabled", "success") else: flash(f"Alias {gen_email.email} is disabled", "warning") session[HIGHLIGHT_GEN_EMAIL_ID] = gen_email.id db.session.commit() elif request.form.get("form-name") == "delete-email": gen_email_id = request.form.get("gen-email-id") gen_email: GenEmail = GenEmail.get(gen_email_id) LOG.d("delete gen email %s", gen_email) email = gen_email.email GenEmail.delete(gen_email.id) # save deleted alias DeletedAlias.create(user_id=current_user.id, email=gen_email.email) db.session.commit() flash(f"Alias {email} has been deleted", "success") return redirect(url_for("dashboard.index", query=query)) client_users = ( ClientUser.filter_by(user_id=current_user.id) .options(joinedload(ClientUser.client)) .options(joinedload(ClientUser.gen_email)) .all() ) sorted(client_users, key=lambda cu: cu.client.name) return render_template( "dashboard/index.html", client_users=client_users, aliases=get_alias_info(current_user.id, query, highlight_gen_email_id), highlight_gen_email_id=highlight_gen_email_id, query=query, AliasGeneratorEnum=AliasGeneratorEnum, )
def alias_contact_manager(alias_id, forward_email_id=None): gen_email = GenEmail.get(alias_id) # sanity check if not gen_email: flash("You do not have access to this page", "warning") return redirect(url_for("dashboard.index")) if gen_email.user_id != current_user.id: flash("You do not have access to this page", "warning") return redirect(url_for("dashboard.index")) new_contact_form = NewContactForm() if request.method == "POST": if request.form.get("form-name") == "create": if new_contact_form.validate(): contact_email = new_contact_form.email.data # generate a reply_email, make sure it is unique # not use while to avoid infinite loop for _ in range(1000): reply_email = f"ra+{random_string(25)}@{EMAIL_DOMAIN}" if not ForwardEmail.get_by(reply_email=reply_email): break website_email = get_email_part(contact_email) # already been added if ForwardEmail.get_by(gen_email_id=gen_email.id, website_email=website_email): flash(f"{website_email} is already added", "error") return redirect( url_for("dashboard.alias_contact_manager", alias_id=alias_id)) forward_email = ForwardEmail.create( gen_email_id=gen_email.id, website_email=website_email, website_from=contact_email, reply_email=reply_email, ) LOG.d("create reverse-alias for %s", contact_email) db.session.commit() flash(f"Reverse alias for {contact_email} is created", "success") return redirect( url_for( "dashboard.alias_contact_manager", alias_id=alias_id, forward_email_id=forward_email.id, )) elif request.form.get("form-name") == "delete": forward_email_id = request.form.get("forward-email-id") forward_email = ForwardEmail.get(forward_email_id) if not forward_email: flash("Unknown error. Refresh the page", "warning") return redirect( url_for("dashboard.alias_contact_manager", alias_id=alias_id)) elif forward_email.gen_email_id != gen_email.id: flash("You cannot delete reverse-alias", "warning") return redirect( url_for("dashboard.alias_contact_manager", alias_id=alias_id)) contact_name = forward_email.website_from ForwardEmail.delete(forward_email_id) db.session.commit() flash(f"Reverse-alias for {contact_name} has been deleted", "success") return redirect( url_for("dashboard.alias_contact_manager", alias_id=alias_id)) # make sure highlighted forward_email is at array start forward_emails = gen_email.forward_emails if forward_email_id: forward_emails = sorted(forward_emails, key=lambda fe: fe.id == forward_email_id, reverse=True) return render_template( "dashboard/alias_contact_manager.html", forward_emails=forward_emails, alias=gen_email.email, new_contact_form=new_contact_form, forward_email_id=forward_email_id, )
def index(): query = request.args.get("query") or "" highlight_gen_email_id = None if request.args.get("highlight_gen_email_id"): highlight_gen_email_id = int( request.args.get("highlight_gen_email_id")) # User generates a new email if request.method == "POST": if request.form.get("form-name") == "trigger-email": gen_email_id = request.form.get("gen-email-id") gen_email = GenEmail.get(gen_email_id) LOG.d("trigger an email to %s", gen_email) email_utils.send_test_email_alias(gen_email.email, gen_email.user.name) flash( f"An email sent to {gen_email.email} is on its way, please check your inbox/spam folder", "success", ) elif request.form.get("form-name") == "create-custom-email": if current_user.can_create_new_alias(): return redirect(url_for("dashboard.custom_alias")) else: flash(f"You need to upgrade your plan to create new alias.", "warning") elif request.form.get("form-name") == "create-random-email": if current_user.can_create_new_alias(): scheme = int( request.form.get("generator_scheme") or current_user.alias_generator) if not scheme or not AliasGeneratorEnum.has_value(scheme): scheme = current_user.alias_generator gen_email = GenEmail.create_new_random(user_id=current_user.id, scheme=scheme) db.session.commit() LOG.d("generate new email %s for user %s", gen_email, current_user) flash(f"Alias {gen_email.email} has been created", "success") return redirect( url_for( "dashboard.index", highlight_gen_email_id=gen_email.id, query=query, )) else: flash(f"You need to upgrade your plan to create new alias.", "warning") elif request.form.get("form-name") == "switch-email-forwarding": gen_email_id = request.form.get("gen-email-id") gen_email: GenEmail = GenEmail.get(gen_email_id) LOG.d("switch email forwarding for %s", gen_email) gen_email.enabled = not gen_email.enabled if gen_email.enabled: flash(f"Alias {gen_email.email} is enabled", "success") else: flash(f"Alias {gen_email.email} is disabled", "warning") db.session.commit() return redirect( url_for("dashboard.index", highlight_gen_email_id=gen_email.id, query=query)) elif request.form.get("form-name") == "delete-email": gen_email_id = request.form.get("gen-email-id") gen_email: GenEmail = GenEmail.get(gen_email_id) LOG.d("delete gen email %s", gen_email) email = gen_email.email GenEmail.delete(gen_email.id) db.session.commit() flash(f"Alias {email} has been deleted", "success") # try to save deleted alias try: DeletedAlias.create(user_id=current_user.id, email=email) db.session.commit() # this can happen when a previously deleted alias is re-created via catch-all or directory feature except IntegrityError: LOG.error("alias %s has been added before to DeletedAlias", email) db.session.rollback() return redirect(url_for("dashboard.index", query=query)) client_users = (ClientUser.filter_by(user_id=current_user.id).options( joinedload(ClientUser.client)).options(joinedload( ClientUser.gen_email)).all()) sorted(client_users, key=lambda cu: cu.client.name) return render_template( "dashboard/index.html", client_users=client_users, aliases=get_alias_info(current_user.id, query, highlight_gen_email_id), highlight_gen_email_id=highlight_gen_email_id, query=query, AliasGeneratorEnum=AliasGeneratorEnum, )