def test_import_no_mailboxes(flask_client): # Create user user = login(flask_client) # Check start state assert len(Alias.filter_by(user_id=user.id).all()) == 1 # Onboarding alias # Create domain CustomDomain.create( user_id=user.id, domain="my-domain.com", ownership_verified=True ) Session.commit() alias_data = [ "alias,note", "[email protected],Used on eBay", '[email protected],"Used on Facebook, Instagram."', ] file = File.create(path="/test", commit=True) batch_import = BatchImport.create(user_id=user.id, file_id=file.id) import_from_csv(batch_import, user, alias_data) assert len(Alias.filter_by(user_id=user.id).all()) == 3 # +2
def test_import(flask_client): # Create user user = login(flask_client) # Check start state assert len(Alias.filter_by(user_id=user.id).all()) == 1 # Onboarding alias # Create domains CustomDomain.create( user_id=user.id, domain="my-domain.com", ownership_verified=True ) CustomDomain.create( user_id=user.id, domain="my-destination-domain.com", ownership_verified=True ) Session.commit() # Create mailboxes mailbox1 = Mailbox.create( user_id=user.id, email="*****@*****.**", verified=True ) mailbox2 = Mailbox.create( user_id=user.id, email="*****@*****.**", verified=True ) Session.commit() alias_data = [ "alias,note,mailboxes", "[email protected],Used on eBay,[email protected]", '[email protected],"Used on Facebook, Instagram.",[email protected] [email protected]', ] file = File.create(path="/test", commit=True) batch_import = BatchImport.create(user_id=user.id, file_id=file.id) import_from_csv(batch_import, user, alias_data) aliases = Alias.filter_by(user_id=user.id).order_by(Alias.id).all() assert len(aliases) == 3 # +2 # aliases[0] is the onboarding alias, skip it # eBay alias assert aliases[1].email == "*****@*****.**" assert len(aliases[1].mailboxes) == 1 # First one should be primary assert aliases[1].mailbox_id == mailbox1.id # Others are sorted assert aliases[1].mailboxes[0] == mailbox1 # Facebook alias assert aliases[2].email == "*****@*****.**" assert len(aliases[2].mailboxes) == 2 # First one should be primary assert aliases[2].mailbox_id == mailbox1.id # Others are sorted assert aliases[2].mailboxes[0] == mailbox2 assert aliases[2].mailboxes[1] == mailbox1
def export_data(): """ Get user data Output: Alias, custom domain and app info """ user = g.user data = { "email": user.email, "name": user.name, "aliases": [], "apps": [], "custom_domains": [], } for alias in Alias.filter_by(user_id=user.id).all(): # type: Alias data["aliases"].append(dict(email=alias.email, enabled=alias.enabled)) for custom_domain in CustomDomain.filter_by(user_id=user.id).all(): data["custom_domains"].append(custom_domain.domain) for app in Client.filter_by(user_id=user.id): # type: Client data["apps"].append(dict(name=app.name, home_url=app.home_url)) return jsonify(data)
def export_aliases(): """ Get user aliases as importable CSV file Output: Importable CSV file """ user = g.user data = [["alias", "note", "enabled", "mailboxes"]] for alias in Alias.filter_by(user_id=user.id).all(): # type: Alias # Always put the main mailbox first # It is seen a primary while importing alias_mailboxes = alias.mailboxes alias_mailboxes.insert( 0, alias_mailboxes.pop(alias_mailboxes.index(alias.mailbox)) ) mailboxes = " ".join([mailbox.email for mailbox in alias_mailboxes]) data.append([alias.email, alias.note, alias.enabled, mailboxes]) si = StringIO() cw = csv.writer(si) cw.writerows(data) output = make_response(si.getvalue()) output.headers["Content-Disposition"] = "attachment; filename=aliases.csv" output.headers["Content-type"] = "text/csv" return output
def test_import_no_mailboxes_no_domains(flask_client): # Create user user = login(flask_client) # Check start state assert len(Alias.filter_by(user_id=user.id).all()) == 1 # Onboarding alias alias_data = [ "alias,note", "[email protected],Used on eBay", '[email protected],"Used on Facebook, Instagram."', ] file = File.create(path="/test", commit=True) batch_import = BatchImport.create(user_id=user.id, file_id=file.id, commit=True) import_from_csv(batch_import, user, alias_data) # Should have failed to import anything new because my-domain.com isn't registered assert len(Alias.filter_by(user_id=user.id).all()) == 1 # +0
def test_import_no_domains(flask_client): # Create user user = login(flask_client) # Check start state assert len(Alias.filter_by(user_id=user.id).all()) == 1 # Onboarding alias alias_data = [ "alias,note,mailboxes", "[email protected],Used on eBay,[email protected]", '[email protected],"Used on Facebook, Instagram.",[email protected] [email protected]', ] batch_import = BatchImport.create(user_id=user.id, file_id=0) import_from_csv(batch_import, user, alias_data) # Should have failed to import anything new because my-domain.com isn't registered assert len(Alias.filter_by(user_id=user.id).all()) == 1 # +0
def domain_detail(custom_domain_id): custom_domain = CustomDomain.get(custom_domain_id) if not custom_domain or custom_domain.user_id != current_user.id: flash("You cannot see this page", "warning") return redirect(url_for("dashboard.index")) if request.method == "POST": if request.form.get("form-name") == "switch-catch-all": custom_domain.catch_all = not custom_domain.catch_all db.session.commit() if custom_domain.catch_all: flash( f"The catch-all has been enabled for {custom_domain.domain}", "success", ) else: flash( f"The catch-all has been disabled for {custom_domain.domain}", "warning", ) return redirect( url_for("dashboard.domain_detail", custom_domain_id=custom_domain.id)) elif request.form.get("form-name") == "set-name": custom_domain.name = request.form.get("alias-name") db.session.commit() flash( f"Default alias name for Domain {custom_domain.domain} has been set", "success", ) return redirect( url_for("dashboard.domain_detail", custom_domain_id=custom_domain.id)) elif request.form.get("form-name") == "delete": name = custom_domain.domain CustomDomain.delete(custom_domain_id) db.session.commit() flash(f"Domain {name} has been deleted", "success") return redirect(url_for("dashboard.custom_domain")) nb_alias = Alias.filter_by(custom_domain_id=custom_domain.id).count() return render_template("dashboard/domain_detail/info.html", **locals())
def get_stats(user: User) -> Stats: nb_alias = Alias.filter_by(user_id=user.id).count() nb_forward = (Session.query(EmailLog).filter_by(user_id=user.id, is_reply=False, blocked=False, bounced=False).count()) nb_reply = (Session.query(EmailLog).filter_by(user_id=user.id, is_reply=True, blocked=False, bounced=False).count()) nb_block = (Session.query(EmailLog).filter_by(user_id=user.id, is_reply=False, blocked=True, bounced=False).count()) return Stats(nb_alias=nb_alias, nb_forward=nb_forward, nb_reply=nb_reply, nb_block=nb_block)
def setting(): form = SettingForm() promo_form = PromoCodeForm() change_email_form = ChangeEmailForm() email_change = EmailChange.get_by(user_id=current_user.id) if email_change: pending_email = email_change.new_email else: pending_email = None if request.method == "POST": if request.form.get("form-name") == "update-email": if change_email_form.validate(): # whether user can proceed with the email update new_email_valid = True if (change_email_form.email.data.lower().strip() != current_user.email and not pending_email): new_email = change_email_form.email.data.strip().lower() # check if this email is not already used if personal_email_already_used(new_email) or Alias.get_by( email=new_email): flash(f"Email {new_email} already used", "error") new_email_valid = False elif not email_can_be_used_as_mailbox(new_email): flash( "You cannot use this email address as your personal inbox.", "error", ) new_email_valid = False # a pending email change with the same email exists from another user elif EmailChange.get_by(new_email=new_email): other_email_change: EmailChange = EmailChange.get_by( new_email=new_email) LOG.warning( "Another user has a pending %s with the same email address. Current user:%s", other_email_change, current_user, ) if other_email_change.is_expired(): LOG.d("delete the expired email change %s", other_email_change) EmailChange.delete(other_email_change.id) db.session.commit() else: flash( "You cannot use this email address as your personal inbox.", "error", ) new_email_valid = False if new_email_valid: email_change = EmailChange.create( user_id=current_user.id, code=random_string( 60), # todo: make sure the code is unique new_email=new_email, ) db.session.commit() send_change_email_confirmation(current_user, email_change) flash( "A confirmation email is on the way, please check your inbox", "success", ) return redirect(url_for("dashboard.setting")) if request.form.get("form-name") == "update-profile": if form.validate(): profile_updated = False # update user info if form.name.data != current_user.name: current_user.name = form.name.data db.session.commit() profile_updated = True if form.profile_picture.data: file_path = random_string(30) file = File.create(user_id=current_user.id, path=file_path) s3.upload_from_bytesio( file_path, BytesIO(form.profile_picture.data.read())) db.session.flush() LOG.d("upload file %s to s3", file) current_user.profile_picture_id = file.id db.session.commit() profile_updated = True if profile_updated: flash(f"Your profile has been updated", "success") return redirect(url_for("dashboard.setting")) elif request.form.get("form-name") == "change-password": flash( "You are going to receive an email containing instructions to change your password", "success", ) send_reset_password_email(current_user) return redirect(url_for("dashboard.setting")) elif request.form.get("form-name") == "notification-preference": choose = request.form.get("notification") if choose == "on": current_user.notification = True else: current_user.notification = False db.session.commit() flash("Your notification preference has been updated", "success") return redirect(url_for("dashboard.setting")) elif request.form.get("form-name") == "delete-account": LOG.warning("Delete account %s", current_user) User.delete(current_user.id) db.session.commit() flash("Your account has been deleted", "success") logout_user() return redirect(url_for("auth.register")) elif request.form.get("form-name") == "change-alias-generator": scheme = int(request.form.get("alias-generator-scheme")) if AliasGeneratorEnum.has_value(scheme): current_user.alias_generator = scheme db.session.commit() flash("Your preference has been updated", "success") return redirect(url_for("dashboard.setting")) elif request.form.get( "form-name") == "change-random-alias-default-domain": default_domain = request.form.get("random-alias-default-domain") if default_domain: sl_domain: SLDomain = SLDomain.get_by(domain=default_domain) if sl_domain: if sl_domain.premium_only and not current_user.is_premium( ): flash("You cannot use this domain", "error") return redirect(url_for("dashboard.setting")) # make sure only default_random_alias_domain_id or default_random_alias_public_domain_id is set current_user.default_random_alias_public_domain_id = sl_domain.id current_user.default_random_alias_domain_id = None else: custom_domain = CustomDomain.get_by(domain=default_domain) if custom_domain: # sanity check if (custom_domain.user_id != current_user.id or not custom_domain.verified): LOG.exception("%s cannot use domain %s", current_user, default_domain) else: # make sure only default_random_alias_domain_id or # default_random_alias_public_domain_id is set current_user.default_random_alias_domain_id = ( custom_domain.id) current_user.default_random_alias_public_domain_id = None else: current_user.default_random_alias_domain_id = None current_user.default_random_alias_public_domain_id = None db.session.commit() flash("Your preference has been updated", "success") return redirect(url_for("dashboard.setting")) elif request.form.get("form-name") == "change-sender-format": sender_format = int(request.form.get("sender-format")) if SenderFormatEnum.has_value(sender_format): current_user.sender_format = sender_format db.session.commit() flash("Your sender format preference has been updated", "success") db.session.commit() return redirect(url_for("dashboard.setting")) elif request.form.get("form-name") == "replace-ra": choose = request.form.get("replace-ra") if choose == "on": current_user.replace_reverse_alias = True else: current_user.replace_reverse_alias = False db.session.commit() flash("Your preference has been updated", "success") return redirect(url_for("dashboard.setting")) elif request.form.get("form-name") == "export-data": data = { "email": current_user.email, "name": current_user.name, "aliases": [], "apps": [], "custom_domains": [], } for alias in Alias.filter_by( user_id=current_user.id).all(): # type: Alias data["aliases"].append( dict(email=alias.email, enabled=alias.enabled)) for custom_domain in CustomDomain.filter_by( user_id=current_user.id).all(): data["custom_domains"].append(custom_domain.domain) for app in Client.filter_by( user_id=current_user.id): # type: Client data["apps"].append( dict(name=app.name, home_url=app.home_url, published=app.published)) return Response( json.dumps(data), mimetype="text/json", headers={ "Content-Disposition": "attachment;filename=data.json" }, ) elif request.form.get("form-name") == "export-alias": data = [["alias", "note", "enabled"]] for alias in Alias.filter_by( user_id=current_user.id).all(): # type: Alias data.append([alias.email, alias.note, alias.enabled]) si = StringIO() cw = csv.writer(si) cw.writerows(data) output = make_response(si.getvalue()) output.headers[ "Content-Disposition"] = "attachment; filename=aliases.csv" output.headers["Content-type"] = "text/csv" return output manual_sub = ManualSubscription.get_by(user_id=current_user.id) return render_template( "dashboard/setting.html", form=form, PlanEnum=PlanEnum, SenderFormatEnum=SenderFormatEnum, promo_form=promo_form, change_email_form=change_email_form, pending_email=pending_email, AliasGeneratorEnum=AliasGeneratorEnum, manual_sub=manual_sub, FIRST_ALIAS_DOMAIN=FIRST_ALIAS_DOMAIN, )
def domain_detail(custom_domain_id): custom_domain = CustomDomain.get(custom_domain_id) if not custom_domain or custom_domain.user_id != current_user.id: flash("You cannot see this page", "warning") return redirect(url_for("dashboard.index")) if request.method == "POST": if request.form.get("form-name") == "switch-catch-all": custom_domain.catch_all = not custom_domain.catch_all db.session.commit() if custom_domain.catch_all: flash( f"The catch-all has been enabled for {custom_domain.domain}", "success", ) else: flash( f"The catch-all has been disabled for {custom_domain.domain}", "warning", ) return redirect( url_for("dashboard.domain_detail", custom_domain_id=custom_domain.id)) elif request.form.get("form-name") == "set-name": custom_domain.name = request.form.get("alias-name") db.session.commit() flash( f"Default alias name for Domain {custom_domain.domain} has been set", "success", ) return redirect( url_for("dashboard.domain_detail", custom_domain_id=custom_domain.id)) elif request.form.get( "form-name") == "switch-random-prefix-generation": custom_domain.random_prefix_generation = ( not custom_domain.random_prefix_generation) db.session.commit() if custom_domain.random_prefix_generation: flash( f"Random prefix generation has been enabled for {custom_domain.domain}", "success", ) else: flash( f"Random prefix generation has been disabled for {custom_domain.domain}", "warning", ) return redirect( url_for("dashboard.domain_detail", custom_domain_id=custom_domain.id)) elif request.form.get("form-name") == "delete": name = custom_domain.domain LOG.d("Schedule deleting %s", custom_domain) Thread(target=delete_domain, args=(custom_domain_id, )).start() flash( f"{name} scheduled for deletion." f"You will receive a confirmation email when the deletion is finished", "success", ) return redirect(url_for("dashboard.custom_domain")) nb_alias = Alias.filter_by(custom_domain_id=custom_domain.id).count() return render_template("dashboard/domain_detail/info.html", **locals())
def test_export(flask_client): # Create users user1 = login(flask_client) user2 = User.create( email="[email protected]", password="******", name="Wrong user", activated=True ) Session.commit() # Remove onboarding aliases for alias in Alias.filter_by(user_id=user1.id).all(): alias_utils.delete_alias(alias, user1) for alias in Alias.filter_by(user_id=user2.id).all(): alias_utils.delete_alias(alias, user2) Session.commit() # Create domains CustomDomain.create( user_id=user1.id, domain="my-destination-domain.com", verified=True ) CustomDomain.create( user_id=user2.id, domain="bad-destionation-domain.com", verified=True ) Session.commit() # Create mailboxes mailbox1 = Mailbox.create( user_id=user1.id, email="*****@*****.**", verified=True ) mailbox2 = Mailbox.create( user_id=user1.id, email="*****@*****.**", verified=True ) badmailbox1 = Mailbox.create( user_id=user2.id, email="*****@*****.**", verified=True, ) Session.commit() # Create aliases Alias.create( user_id=user1.id, email="*****@*****.**", note="Used on eBay", mailbox_id=mailbox1.id, ) alias2 = Alias.create( user_id=user1.id, email="*****@*****.**", note="Used on Facebook, Instagram.", mailbox_id=mailbox1.id, ) Alias.create( user_id=user2.id, email="*****@*****.**", note="Should not appear", mailbox_id=badmailbox1.id, ) Session.commit() # Add second mailbox to an alias AliasMailbox.create( alias_id=alias2.id, mailbox_id=mailbox2.id, ) Session.commit() # Export r = flask_client.get(url_for("api.export_aliases")) assert r.status_code == 200 assert r.mimetype == "text/csv" assert ( r.data == """alias,note,enabled,mailboxes [email protected],Used on eBay,True,[email protected] [email protected],"Used on Facebook, Instagram.",True,[email protected] [email protected] """.replace( "\n", "\r\n" ).encode() )
def setting(): form = SettingForm() promo_form = PromoCodeForm() change_email_form = ChangeEmailForm() email_change = EmailChange.get_by(user_id=current_user.id) if email_change: pending_email = email_change.new_email else: pending_email = None if request.method == "POST": if request.form.get("form-name") == "update-email": if change_email_form.validate(): if (change_email_form.email.data.lower().strip() != current_user.email and not pending_email): new_email = change_email_form.email.data.strip().lower() # check if this email is not already used if personal_email_already_used(new_email) or Alias.get_by( email=new_email): flash(f"Email {new_email} already used", "error") elif not email_domain_can_be_used_as_mailbox(new_email): flash( "You cannot use this email address as your personal inbox.", "error", ) else: email_change = EmailChange.create( user_id=current_user.id, code=random_string( 60), # todo: make sure the code is unique new_email=new_email, ) db.session.commit() send_change_email_confirmation(current_user, email_change) flash( "A confirmation email is on the way, please check your inbox", "success", ) return redirect(url_for("dashboard.setting")) if request.form.get("form-name") == "update-profile": if form.validate(): profile_updated = False # update user info if form.name.data != current_user.name: current_user.name = form.name.data db.session.commit() profile_updated = True if form.profile_picture.data: file_path = random_string(30) file = File.create(user_id=current_user.id, path=file_path) s3.upload_from_bytesio( file_path, BytesIO(form.profile_picture.data.read())) db.session.flush() LOG.d("upload file %s to s3", file) current_user.profile_picture_id = file.id db.session.commit() profile_updated = True if profile_updated: flash(f"Your profile has been updated", "success") return redirect(url_for("dashboard.setting")) elif request.form.get("form-name") == "change-password": flash( "You are going to receive an email containing instructions to change your password", "success", ) send_reset_password_email(current_user) return redirect(url_for("dashboard.setting")) elif request.form.get("form-name") == "notification-preference": choose = request.form.get("notification") if choose == "on": current_user.notification = True else: current_user.notification = False db.session.commit() flash("Your notification preference has been updated", "success") return redirect(url_for("dashboard.setting")) elif request.form.get("form-name") == "delete-account": LOG.warning("Delete account %s", current_user) User.delete(current_user.id) db.session.commit() flash("Your account has been deleted", "success") logout_user() return redirect(url_for("auth.register")) elif request.form.get("form-name") == "change-alias-generator": scheme = int(request.form.get("alias-generator-scheme")) if AliasGeneratorEnum.has_value(scheme): current_user.alias_generator = scheme db.session.commit() flash("Your preference has been updated", "success") return redirect(url_for("dashboard.setting")) elif request.form.get( "form-name") == "change-random-alias-default-domain": default_domain = request.form.get("random-alias-default-domain") if default_domain: default_domain_id = int(default_domain) # sanity check domain = CustomDomain.get(default_domain_id) if (not domain or domain.user_id != current_user.id or not domain.verified): flash( "Something went wrong, sorry for the inconvenience. Please retry. ", "error", ) return redirect(url_for("dashboard.setting")) current_user.default_random_alias_domain_id = default_domain_id else: current_user.default_random_alias_domain_id = None db.session.commit() flash("Your preference has been updated", "success") return redirect(url_for("dashboard.setting")) elif request.form.get("form-name") == "change-sender-format": sender_format = int(request.form.get("sender-format")) if SenderFormatEnum.has_value(sender_format): current_user.sender_format = sender_format db.session.commit() flash("Your sender format preference has been updated", "success") db.session.commit() return redirect(url_for("dashboard.setting")) elif request.form.get("form-name") == "replace-ra": choose = request.form.get("replace-ra") if choose == "on": current_user.replace_reverse_alias = True else: current_user.replace_reverse_alias = False db.session.commit() flash("Your preference has been updated", "success") return redirect(url_for("dashboard.setting")) elif request.form.get("form-name") == "export-data": data = { "email": current_user.email, "name": current_user.name, "aliases": [], "apps": [], "custom_domains": [], } for alias in Alias.filter_by( user_id=current_user.id).all(): # type: Alias data["aliases"].append( dict(email=alias.email, enabled=alias.enabled)) for custom_domain in CustomDomain.filter_by( user_id=current_user.id).all(): data["custom_domains"].append(custom_domain.domain) for app in Client.filter_by( user_id=current_user.id): # type: Client data["apps"].append( dict(name=app.name, home_url=app.home_url, published=app.published)) return Response( json.dumps(data), mimetype="text/json", headers={ "Content-Disposition": "attachment;filename=data.json" }, ) manual_sub = ManualSubscription.get_by(user_id=current_user.id) return render_template( "dashboard/setting.html", form=form, PlanEnum=PlanEnum, SenderFormatEnum=SenderFormatEnum, promo_form=promo_form, change_email_form=change_email_form, pending_email=pending_email, AliasGeneratorEnum=AliasGeneratorEnum, manual_sub=manual_sub, FIRST_ALIAS_DOMAIN=FIRST_ALIAS_DOMAIN, )
def domain_detail(custom_domain_id): custom_domain: CustomDomain = CustomDomain.get(custom_domain_id) mailboxes = current_user.mailboxes() if not custom_domain or custom_domain.user_id != current_user.id: flash("You cannot see this page", "warning") return redirect(url_for("dashboard.index")) if request.method == "POST": if request.form.get("form-name") == "switch-catch-all": custom_domain.catch_all = not custom_domain.catch_all Session.commit() if custom_domain.catch_all: flash( f"The catch-all has been enabled for {custom_domain.domain}", "success", ) else: flash( f"The catch-all has been disabled for {custom_domain.domain}", "warning", ) return redirect( url_for("dashboard.domain_detail", custom_domain_id=custom_domain.id) ) elif request.form.get("form-name") == "set-name": if request.form.get("action") == "save": custom_domain.name = request.form.get("alias-name").replace("\n", "") Session.commit() flash( f"Default alias name for Domain {custom_domain.domain} has been set", "success", ) else: custom_domain.name = None Session.commit() flash( f"Default alias name for Domain {custom_domain.domain} has been removed", "info", ) return redirect( url_for("dashboard.domain_detail", custom_domain_id=custom_domain.id) ) elif request.form.get("form-name") == "switch-random-prefix-generation": custom_domain.random_prefix_generation = ( not custom_domain.random_prefix_generation ) Session.commit() if custom_domain.random_prefix_generation: flash( f"Random prefix generation has been enabled for {custom_domain.domain}", "success", ) else: flash( f"Random prefix generation has been disabled for {custom_domain.domain}", "warning", ) return redirect( url_for("dashboard.domain_detail", custom_domain_id=custom_domain.id) ) elif request.form.get("form-name") == "update": mailbox_ids = request.form.getlist("mailbox_ids") # check if mailbox is not tempered with mailboxes = [] for mailbox_id in mailbox_ids: mailbox = Mailbox.get(mailbox_id) if ( not mailbox or mailbox.user_id != current_user.id or not mailbox.verified ): flash("Something went wrong, please retry", "warning") return redirect( url_for( "dashboard.domain_detail", custom_domain_id=custom_domain.id ) ) mailboxes.append(mailbox) if not mailboxes: flash("You must select at least 1 mailbox", "warning") return redirect( url_for( "dashboard.domain_detail", custom_domain_id=custom_domain.id ) ) # first remove all existing domain-mailboxes links DomainMailbox.filter_by(domain_id=custom_domain.id).delete() Session.flush() for mailbox in mailboxes: DomainMailbox.create(domain_id=custom_domain.id, mailbox_id=mailbox.id) Session.commit() flash(f"{custom_domain.domain} mailboxes has been updated", "success") return redirect( url_for("dashboard.domain_detail", custom_domain_id=custom_domain.id) ) elif request.form.get("form-name") == "delete": name = custom_domain.domain LOG.d("Schedule deleting %s", custom_domain) # Schedule delete domain job LOG.w("schedule delete domain job for %s", custom_domain) Job.create( name=JOB_DELETE_DOMAIN, payload={"custom_domain_id": custom_domain.id}, run_at=arrow.now(), commit=True, ) flash( f"{name} scheduled for deletion." f"You will receive a confirmation email when the deletion is finished", "success", ) if custom_domain.is_sl_subdomain: return redirect(url_for("dashboard.subdomain_route")) else: return redirect(url_for("dashboard.custom_domain")) nb_alias = Alias.filter_by(custom_domain_id=custom_domain.id).count() return render_template("dashboard/domain_detail/info.html", **locals())