diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..f3f9b0c8e7 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Django", + "type": "python", + "request": "launch", + "program": "main.py", + "django": true, + "justMyCode": true, + "pythonPath": "/opt/homebrew/bin/python3.10" + } + ] +} diff --git a/database/db_models.py b/database/db_models.py index 7a353cb663..1053c8cf38 100644 --- a/database/db_models.py +++ b/database/db_models.py @@ -13,6 +13,7 @@ class EmailList(db.Model): __tablename__ = 'email_list' email = db.Column(db.String(255), primary_key=True, autoincrement=False) + source = db.Column(db.String(255), index=True) unsubscribed = db.Column(db.Boolean()) created_at = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) ip_addr = db.Column(db.String(100)) diff --git a/logic/emails/mailing_list.py b/logic/emails/mailing_list.py index ee0c02c6cf..d7320f1da2 100644 --- a/logic/emails/mailing_list.py +++ b/logic/emails/mailing_list.py @@ -73,7 +73,7 @@ def mass_unsubscribe_sendgrid_contact(emails): # Inserts or updates an entry in the email_list table. # Returns True if a new entry was added, False if the entry already existed. # Raises an exception in case of an error. -def add_contact(email, first_name, last_name, ip_addr, country_code): +def add_contact(email, first_name, last_name, ip_addr, country_code, source=None): if not re.match(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)", email): raise Exception('Invalid email') @@ -89,6 +89,7 @@ def add_contact(email, first_name, last_name, ip_addr, country_code): row.last_name = last_name row.ip_addr = ip_addr row.country_code = country_code + row.source = source else: # Insert a new entry. new_contact = True @@ -99,6 +100,7 @@ def add_contact(email, first_name, last_name, ip_addr, country_code): row.unsubscribed = False row.ip_addr = ip_addr row.country_code = country_code + row.source = source db.session.add(row) db.session.commit() except Exception as e: diff --git a/migrations/versions/17de7a1bad16_.py b/migrations/versions/17de7a1bad16_.py new file mode 100644 index 0000000000..92744dcaac --- /dev/null +++ b/migrations/versions/17de7a1bad16_.py @@ -0,0 +1,29 @@ +"""empty message + +Revision ID: 17de7a1bad16 +Revises: bbf13d065442 +Create Date: 2023-04-21 00:18:06.044764 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '17de7a1bad16' +down_revision = 'bbf13d065442' +branch_labels = None +depends_on = None + + +def upgrade(): + op.add_column('email_list', sa.Column('source', sa.String(length=255), nullable=True)) + op.create_index(op.f('ix_email_list_source'), 'email_list', ['source'], unique=False) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index(op.f('ix_email_list_source'), table_name='email_list') + op.drop_column('email_list', 'source') + # ### end Alembic commands ### diff --git a/views/web_views.py b/views/web_views.py index 9b68d7ec75..6f4a3130a2 100644 --- a/views/web_views.py +++ b/views/web_views.py @@ -2,9 +2,6 @@ from datetime import datetime import os import re -import sys -import calendar -import random from flask_cors import CORS, cross_origin from app import app @@ -247,7 +244,7 @@ def join_mailing_list(): # Add an entry to the email_list table. log("Adding to mailing list") new_contact = mailing_list.add_contact( - email, first_name, last_name, ip_addr, country_code + email, first_name, last_name, ip_addr, country_code, "originprotocol.com" ) # If it is a new contact and not a backfill, send a welcome email. @@ -275,6 +272,50 @@ def join_mailing_list(): return jsonify(success=True, message=gettext("Thanks for signing up!")) +@cross_origin() +@app.route("/oeth-subscribe", methods=["POST"], strict_slashes=False) +def oeth_subscribe(): + if not "email" in request.form: + return jsonify(success=False, message=gettext("Missing email")) + email = request.form["email"] + if not re.match(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)", email): + return jsonify(success=False, message=gettext("Invalid email")) + + # optional fields + source = request.form.get("source") or None + eth_address = request.form.get("eth_address") or None + first_name = request.form.get("first_name") or None + last_name = request.form.get("last_name") or None + full_name = request.form.get("name") or None + if not full_name and (first_name or last_name): + full_name = " ".join(filter(None, (first_name, last_name))) + ip_addr = request.form.get("ip_addr") or get_real_ip() + country_code = request.form.get("country_code") or get_country(ip_addr) + + new_user = False + + log("Updating mailing list for", email, eth_address) + try: + # Add an entry to the email_list table. + log("Adding to mailing list") + new_contact = mailing_list.add_contact( + email, first_name, last_name, ip_addr, country_code, source + ) + + # Add the entry to the Sendgrid contact list. + if new_contact: + new_user = True + + except Exception as err: + log("Failure: %s" % err) + return jsonify(success=False, message=str(err)) + + if not new_user: + return jsonify(success=True, message=gettext("You're already registered!")) + + return jsonify(success=True, message=gettext("Thanks for signing up!")) + + @app.route("/mailing-list/unsubscribe", methods=["GET"], strict_slashes=False) def unsubscribe(): email = request.args.get("email")