Example #1
0
File: alias.py Project: dttr278/app
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
Example #2
0
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())
Example #3
0
File: alias.py Project: dttr278/app
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
Example #4
0
File: alias.py Project: dttr278/app
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
Example #5
0
File: alias.py Project: dttr278/app
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
Example #6
0
File: alias.py Project: dttr278/app
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
Example #7
0
File: alias.py Project: dttr278/app
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
Example #8
0
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)
Example #9
0
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,
    )
Example #10
0
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,
    )
Example #11
0
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,
    )