From cb475d7f8840b03ad259c674dff4d0a345ebddfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Tue, 14 Feb 2023 10:50:25 +0100 Subject: [PATCH] remove smtp --- lnbits/extensions/smtp/README.md | 14 - lnbits/extensions/smtp/__init__.py | 34 - lnbits/extensions/smtp/config.json | 6 - lnbits/extensions/smtp/crud.py | 158 ----- lnbits/extensions/smtp/migrations.py | 39 -- lnbits/extensions/smtp/models.py | 47 -- lnbits/extensions/smtp/smtp.py | 110 ---- .../smtp/static/smtp-bitcoin-email.png | Bin 18854 -> 0 bytes lnbits/extensions/smtp/tasks.py | 36 -- .../smtp/templates/smtp/_api_docs.html | 23 - .../smtp/templates/smtp/display.html | 175 ----- .../extensions/smtp/templates/smtp/index.html | 604 ------------------ lnbits/extensions/smtp/views.py | 40 -- lnbits/extensions/smtp/views_api.py | 190 ------ 14 files changed, 1476 deletions(-) delete mode 100644 lnbits/extensions/smtp/README.md delete mode 100644 lnbits/extensions/smtp/__init__.py delete mode 100644 lnbits/extensions/smtp/config.json delete mode 100644 lnbits/extensions/smtp/crud.py delete mode 100644 lnbits/extensions/smtp/migrations.py delete mode 100644 lnbits/extensions/smtp/models.py delete mode 100644 lnbits/extensions/smtp/smtp.py delete mode 100644 lnbits/extensions/smtp/static/smtp-bitcoin-email.png delete mode 100644 lnbits/extensions/smtp/tasks.py delete mode 100644 lnbits/extensions/smtp/templates/smtp/_api_docs.html delete mode 100644 lnbits/extensions/smtp/templates/smtp/display.html delete mode 100644 lnbits/extensions/smtp/templates/smtp/index.html delete mode 100644 lnbits/extensions/smtp/views.py delete mode 100644 lnbits/extensions/smtp/views_api.py diff --git a/lnbits/extensions/smtp/README.md b/lnbits/extensions/smtp/README.md deleted file mode 100644 index 5b7757e2f..000000000 --- a/lnbits/extensions/smtp/README.md +++ /dev/null @@ -1,14 +0,0 @@ -

SMTP Extension

- -This extension allows you to setup a smtp, to offer sending emails with it for a small fee. - -## Requirements - -- SMTP Server - -## Usage - -1. Create new emailaddress -2. Verify if email goes to your testemail. Testmail is sent on create and update -3. Share the link with the email form. - diff --git a/lnbits/extensions/smtp/__init__.py b/lnbits/extensions/smtp/__init__.py deleted file mode 100644 index 9b89a0c46..000000000 --- a/lnbits/extensions/smtp/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -import asyncio - -from fastapi import APIRouter -from fastapi.staticfiles import StaticFiles - -from lnbits.db import Database -from lnbits.helpers import template_renderer -from lnbits.tasks import catch_everything_and_restart - -db = Database("ext_smtp") - -smtp_static_files = [ - { - "path": "/smtp/static", - "app": StaticFiles(directory="lnbits/extensions/smtp/static"), - "name": "smtp_static", - } -] - -smtp_ext: APIRouter = APIRouter(prefix="/smtp", tags=["smtp"]) - - -def smtp_renderer(): - return template_renderer(["lnbits/extensions/smtp/templates"]) - - -from .tasks import wait_for_paid_invoices -from .views import * # noqa: F401,F403 -from .views_api import * # noqa: F401,F403 - - -def smtp_start(): - loop = asyncio.get_event_loop() - loop.create_task(catch_everything_and_restart(wait_for_paid_invoices)) diff --git a/lnbits/extensions/smtp/config.json b/lnbits/extensions/smtp/config.json deleted file mode 100644 index 325ebfa78..000000000 --- a/lnbits/extensions/smtp/config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "SMTP", - "short_description": "Charge sats for sending emails", - "tile": "/smtp/static/smtp-bitcoin-email.png", - "contributors": ["dni"] -} diff --git a/lnbits/extensions/smtp/crud.py b/lnbits/extensions/smtp/crud.py deleted file mode 100644 index bc8d9e1a4..000000000 --- a/lnbits/extensions/smtp/crud.py +++ /dev/null @@ -1,158 +0,0 @@ -from typing import List, Optional, Union - -from lnbits.helpers import urlsafe_short_hash - -from . import db -from .models import CreateEmail, CreateEmailaddress, Email, Emailaddress -from .smtp import send_mail - - -def get_test_mail(email, testemail): - return CreateEmail( - emailaddress_id=email, - subject="LNBits SMTP - Test Email", - message="This is a test email from the LNBits SMTP extension! email is working!", - receiver=testemail, - ) - - -async def create_emailaddress(data: CreateEmailaddress) -> Emailaddress: - - emailaddress_id = urlsafe_short_hash() - - # send test mail for checking connection - email = get_test_mail(data.email, data.testemail) - await send_mail(data, email) - - await db.execute( - """ - INSERT INTO smtp.emailaddress (id, wallet, email, testemail, smtp_server, smtp_user, smtp_password, smtp_port, anonymize, description, cost) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - """, - ( - emailaddress_id, - data.wallet, - data.email, - data.testemail, - data.smtp_server, - data.smtp_user, - data.smtp_password, - data.smtp_port, - data.anonymize, - data.description, - data.cost, - ), - ) - - new_emailaddress = await get_emailaddress(emailaddress_id) - assert new_emailaddress, "Newly created emailaddress couldn't be retrieved" - return new_emailaddress - - -async def update_emailaddress(emailaddress_id: str, **kwargs) -> Emailaddress: - q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) - await db.execute( - f"UPDATE smtp.emailaddress SET {q} WHERE id = ?", - (*kwargs.values(), emailaddress_id), - ) - row = await db.fetchone( - "SELECT * FROM smtp.emailaddress WHERE id = ?", (emailaddress_id,) - ) - - # send test mail for checking connection - email = get_test_mail(row.email, row.testemail) - await send_mail(row, email) - - assert row, "Newly updated emailaddress couldn't be retrieved" - return Emailaddress(**row) - - -async def get_emailaddress(emailaddress_id: str) -> Optional[Emailaddress]: - row = await db.fetchone( - "SELECT * FROM smtp.emailaddress WHERE id = ?", (emailaddress_id,) - ) - return Emailaddress(**row) if row else None - - -async def get_emailaddress_by_email(email: str) -> Optional[Emailaddress]: - row = await db.fetchone("SELECT * FROM smtp.emailaddress WHERE email = ?", (email,)) - return Emailaddress(**row) if row else None - - -async def get_emailaddresses(wallet_ids: Union[str, List[str]]) -> List[Emailaddress]: - if isinstance(wallet_ids, str): - wallet_ids = [wallet_ids] - - q = ",".join(["?"] * len(wallet_ids)) - rows = await db.fetchall( - f"SELECT * FROM smtp.emailaddress WHERE wallet IN ({q})", (*wallet_ids,) - ) - - return [Emailaddress(**row) for row in rows] - - -async def delete_emailaddress(emailaddress_id: str) -> None: - await db.execute("DELETE FROM smtp.emailaddress WHERE id = ?", (emailaddress_id,)) - - -async def create_email(wallet: str, data: CreateEmail, payment_hash: str = "") -> Email: - id = urlsafe_short_hash() - await db.execute( - """ - INSERT INTO smtp.email (id, payment_hash, wallet, emailaddress_id, subject, receiver, message, paid) - VALUES (?, ?, ?, ?, ?, ?, ?, ?) - """, - ( - id, - payment_hash, - wallet, - data.emailaddress_id, - data.subject, - data.receiver, - data.message, - False, - ), - ) - - new_email = await get_email(id) - assert new_email, "Newly created email couldn't be retrieved" - return new_email - - -async def set_email_paid(payment_hash: str) -> bool: - email = await get_email_by_payment_hash(payment_hash) - if email and email.paid is False: - await db.execute( - "UPDATE smtp.email SET paid = true WHERE payment_hash = ?", (payment_hash,) - ) - return True - return False - - -async def get_email_by_payment_hash(payment_hash: str) -> Optional[Email]: - row = await db.fetchone( - "SELECT * FROM smtp.email WHERE payment_hash = ?", (payment_hash,) - ) - return Email(**row) if row else None - - -async def get_email(id: str) -> Optional[Email]: - row = await db.fetchone("SELECT * FROM smtp.email WHERE id = ?", (id,)) - return Email(**row) if row else None - - -async def get_emails(wallet_ids: Union[str, List[str]]) -> List[Email]: - if isinstance(wallet_ids, str): - wallet_ids = [wallet_ids] - - q = ",".join(["?"] * len(wallet_ids)) - rows = await db.fetchall( - f"SELECT s.*, d.email as emailaddress FROM smtp.email s INNER JOIN smtp.emailaddress d ON (s.emailaddress_id = d.id) WHERE s.wallet IN ({q})", - (*wallet_ids,), - ) - - return [Email(**row) for row in rows] - - -async def delete_email(email_id: str) -> None: - await db.execute("DELETE FROM smtp.email WHERE id = ?", (email_id,)) diff --git a/lnbits/extensions/smtp/migrations.py b/lnbits/extensions/smtp/migrations.py deleted file mode 100644 index 22500e106..000000000 --- a/lnbits/extensions/smtp/migrations.py +++ /dev/null @@ -1,39 +0,0 @@ -async def m001_initial(db): - - await db.execute( - f""" - CREATE TABLE smtp.emailaddress ( - id TEXT PRIMARY KEY, - wallet TEXT NOT NULL, - email TEXT NOT NULL, - testemail TEXT NOT NULL, - smtp_server TEXT NOT NULL, - smtp_user TEXT NOT NULL, - smtp_password TEXT NOT NULL, - smtp_port TEXT NOT NULL, - anonymize BOOLEAN NOT NULL, - description TEXT NOT NULL, - cost INTEGER NOT NULL, - time TIMESTAMP NOT NULL DEFAULT {db.timestamp_now} - ); - """ - ) - - await db.execute( - f""" - CREATE TABLE smtp.email ( - id TEXT PRIMARY KEY, - wallet TEXT NOT NULL, - emailaddress_id TEXT NOT NULL, - subject TEXT NOT NULL, - receiver TEXT NOT NULL, - message TEXT NOT NULL, - paid BOOLEAN NOT NULL, - time TIMESTAMP NOT NULL DEFAULT {db.timestamp_now} - ); - """ - ) - - -async def m002_add_payment_hash(db): - await db.execute("ALTER TABLE smtp.email ADD COLUMN payment_hash TEXT;") diff --git a/lnbits/extensions/smtp/models.py b/lnbits/extensions/smtp/models.py deleted file mode 100644 index bb0e1f2cc..000000000 --- a/lnbits/extensions/smtp/models.py +++ /dev/null @@ -1,47 +0,0 @@ -from fastapi import Query -from pydantic import BaseModel - - -class CreateEmailaddress(BaseModel): - wallet: str = Query(...) - email: str = Query(...) - testemail: str = Query(...) - smtp_server: str = Query(...) - smtp_user: str = Query(...) - smtp_password: str = Query(...) - smtp_port: str = Query(...) - description: str = Query(...) - anonymize: bool - cost: int = Query(..., ge=0) - - -class Emailaddress(BaseModel): - id: str - wallet: str - email: str - testemail: str - smtp_server: str - smtp_user: str - smtp_password: str - smtp_port: str - anonymize: bool - description: str - cost: int - - -class CreateEmail(BaseModel): - emailaddress_id: str = Query(...) - subject: str = Query(...) - receiver: str = Query(...) - message: str = Query(...) - - -class Email(BaseModel): - id: str - wallet: str - emailaddress_id: str - subject: str - receiver: str - message: str - paid: bool - time: int diff --git a/lnbits/extensions/smtp/smtp.py b/lnbits/extensions/smtp/smtp.py deleted file mode 100644 index 43253b54f..000000000 --- a/lnbits/extensions/smtp/smtp.py +++ /dev/null @@ -1,110 +0,0 @@ -import re -import socket -import time -from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText -from email.utils import formatdate -from smtplib import SMTP_SSL as SMTP -from typing import Union - -from loguru import logger - -from .models import CreateEmail, CreateEmailaddress, Email, Emailaddress - - -async def send_mail( - emailaddress: Union[Emailaddress, CreateEmailaddress], - email: Union[Email, CreateEmail], -): - smtp_client = SmtpService(emailaddress) - message = smtp_client.create_message(email) - await smtp_client.send_mail(email.receiver, message) - - -def valid_email(s): - # https://regexr.com/2rhq7 - pat = r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?" - if re.match(pat, s): - return True - log = f"SMTP - invalid email: {s}." - logger.error(log) - raise Exception(log) - - -class SmtpService: - def __init__(self, emailaddress: Union[Emailaddress, CreateEmailaddress]) -> None: - self.sender = emailaddress.email - self.smtp_server = emailaddress.smtp_server - self.smtp_port = emailaddress.smtp_port - self.smtp_user = emailaddress.smtp_user - self.smtp_password = emailaddress.smtp_password - - def render_email(self, email: Union[Email, CreateEmail]): - signature: str = "Email sent by LNbits SMTP extension." - text = f"{email.message}\n\n{signature}" - html = ( - """ - - - -

""" - + email.message - + """

-

""" - + signature - + """

- - - """ - ) - return text, html - - def create_message(self, email: Union[Email, CreateEmail]): - ts = time.time() - date = formatdate(ts, True) - - msg = MIMEMultipart("alternative") - msg["Date"] = date - msg["Subject"] = email.subject - msg["From"] = self.sender - msg["To"] = email.receiver - - text, html = self.render_email(email) - - part1 = MIMEText(text, "plain") - part2 = MIMEText(html, "html") - msg.attach(part1) - msg.attach(part2) - return msg - - async def send_mail(self, receiver, msg: MIMEMultipart): - - valid_email(self.sender) - valid_email(receiver) - - try: - conn = SMTP(host=self.smtp_server, port=int(self.smtp_port), timeout=10) - logger.debug("SMTP - connected to smtp server.") - # conn.set_debuglevel(True) - except: - log = f"SMTP - error connecting to smtp server: {self.smtp_server}:{self.smtp_port}." - logger.debug(log) - raise Exception(log) - - try: - conn.login(self.smtp_user, self.smtp_password) - logger.debug("SMTP - successful login to smtp server.") - except: - log = f"SMTP - error login into smtp {self.smtp_user}." - logger.error(log) - raise Exception(log) - - try: - conn.sendmail(self.sender, receiver, msg.as_string()) - logger.debug("SMTP - successfully send email.") - except socket.error as e: - log = f"SMTP - error sending email: {str(e)}." - logger.error(log) - raise Exception(log) - finally: - conn.quit() diff --git a/lnbits/extensions/smtp/static/smtp-bitcoin-email.png b/lnbits/extensions/smtp/static/smtp-bitcoin-email.png deleted file mode 100644 index e80b6c9aeccd0474ba735fdbfc6ea7d46b240d5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18854 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 WO_y@~_~Ru2KuSzrv|898@c#g#4ghQb diff --git a/lnbits/extensions/smtp/tasks.py b/lnbits/extensions/smtp/tasks.py deleted file mode 100644 index 93ed33bad..000000000 --- a/lnbits/extensions/smtp/tasks.py +++ /dev/null @@ -1,36 +0,0 @@ -import asyncio - -from loguru import logger - -from lnbits.core.models import Payment -from lnbits.tasks import register_invoice_listener - -from .crud import get_email_by_payment_hash, get_emailaddress, set_email_paid -from .smtp import send_mail - - -async def wait_for_paid_invoices(): - invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue) - while True: - payment = await invoice_queue.get() - await on_invoice_paid(payment) - - -async def on_invoice_paid(payment: Payment) -> None: - if payment.extra.get("tag") != "smtp": - return - - email = await get_email_by_payment_hash(payment.checking_id) - if not email: - logger.error("SMTP: email can not by fetched") - return - - emailaddress = await get_emailaddress(email.emailaddress_id) - if not emailaddress: - logger.error("SMTP: emailaddress can not by fetched") - return - - await payment.set_pending(False) - await send_mail(emailaddress, email) - await set_email_paid(payment_hash=payment.payment_hash) diff --git a/lnbits/extensions/smtp/templates/smtp/_api_docs.html b/lnbits/extensions/smtp/templates/smtp/_api_docs.html deleted file mode 100644 index cfb811d16..000000000 --- a/lnbits/extensions/smtp/templates/smtp/_api_docs.html +++ /dev/null @@ -1,23 +0,0 @@ - - - -
- LNBits SMTP: Get paid sats to send emails -
-

- Charge people for using sending an email via your smtp server
- More details -
- Created by, dni -

-
-
-
diff --git a/lnbits/extensions/smtp/templates/smtp/display.html b/lnbits/extensions/smtp/templates/smtp/display.html deleted file mode 100644 index f60d22c15..000000000 --- a/lnbits/extensions/smtp/templates/smtp/display.html +++ /dev/null @@ -1,175 +0,0 @@ -{% extends "public.html" %} {% block page %} -
-
- - -

{{ email }}

-
-
{{ desc }}
-
- - - - -

Total cost: {{ cost }} sats

-
- Submit -
-
-
-
-
- - - - - - -
- Copy invoice - Close -
-
-
-
- -{% endblock %} {% block scripts %} - -{% endblock %} diff --git a/lnbits/extensions/smtp/templates/smtp/index.html b/lnbits/extensions/smtp/templates/smtp/index.html deleted file mode 100644 index 4b00cd082..000000000 --- a/lnbits/extensions/smtp/templates/smtp/index.html +++ /dev/null @@ -1,604 +0,0 @@ -{% extends "base.html" %} {% from "macros.jinja" import window_vars with context -%} {% block page %} - -
-
- - - New Emailaddress - - - - - -
-
-
Emailaddresses
-
-
- Export to CSV -
-
- - {% raw %} - - - {% endraw %} - -
-
- - - -
-
-
Emails
-
-
- Export to CSV -
-
- - {% raw %} - - - {% endraw %} - -
-
-
-
- - -
- {{SITE_TITLE}} Sendmail extension -
-
- - - {% include "smtp/_api_docs.html" %} - -
-
- - - - - - - -
- Submit -
-
-
-
- - - - - - - - - - - - - - - -
- -
- - - - -
- Update Form - Create Emailaddress - Cancel -
-
-
-
-
- -{% endblock %} {% block scripts %} {{ window_vars(user) }} - -{% endblock %} diff --git a/lnbits/extensions/smtp/views.py b/lnbits/extensions/smtp/views.py deleted file mode 100644 index df208a77b..000000000 --- a/lnbits/extensions/smtp/views.py +++ /dev/null @@ -1,40 +0,0 @@ -from http import HTTPStatus - -from fastapi import Depends, HTTPException, Request -from fastapi.templating import Jinja2Templates -from starlette.responses import HTMLResponse - -from lnbits.core.models import User -from lnbits.decorators import check_user_exists - -from . import smtp_ext, smtp_renderer -from .crud import get_emailaddress - -templates = Jinja2Templates(directory="templates") - - -@smtp_ext.get("/", response_class=HTMLResponse) -async def index(request: Request, user: User = Depends(check_user_exists)): - return smtp_renderer().TemplateResponse( - "smtp/index.html", {"request": request, "user": user.dict()} - ) - - -@smtp_ext.get("/{emailaddress_id}") -async def display(request: Request, emailaddress_id): - emailaddress = await get_emailaddress(emailaddress_id) - if not emailaddress: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Emailaddress does not exist." - ) - - return smtp_renderer().TemplateResponse( - "smtp/display.html", - { - "request": request, - "emailaddress_id": emailaddress.id, - "email": emailaddress.email, - "desc": emailaddress.description, - "cost": emailaddress.cost, - }, - ) diff --git a/lnbits/extensions/smtp/views_api.py b/lnbits/extensions/smtp/views_api.py deleted file mode 100644 index 66bc49835..000000000 --- a/lnbits/extensions/smtp/views_api.py +++ /dev/null @@ -1,190 +0,0 @@ -from http import HTTPStatus - -from fastapi import Depends, HTTPException, Query - -from lnbits.core.crud import get_user -from lnbits.core.services import check_transaction_status, create_invoice -from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key - -from . import smtp_ext -from .crud import ( - create_email, - create_emailaddress, - delete_email, - delete_emailaddress, - get_email, - get_email_by_payment_hash, - get_emailaddress, - get_emailaddresses, - get_emails, - update_emailaddress, -) -from .models import CreateEmail, CreateEmailaddress -from .smtp import send_mail, valid_email - - -## EMAILS -@smtp_ext.get("/api/v1/email") -async def api_email( - g: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False) -): - wallet_ids = [g.wallet.id] - if all_wallets: - user = await get_user(g.wallet.user) - if user: - wallet_ids = user.wallet_ids - return [email.dict() for email in await get_emails(wallet_ids)] - - -@smtp_ext.get("/api/v1/email/{payment_hash}") -async def api_smtp_send_email(payment_hash): - email = await get_email_by_payment_hash(payment_hash) - if not email: - raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, detail="paymenthash is wrong" - ) - - emailaddress = await get_emailaddress(email.emailaddress_id) - assert emailaddress - - try: - status = await check_transaction_status(email.wallet, payment_hash) - is_paid = not status.pending - except Exception: - return {"paid": False} - if is_paid: - if emailaddress.anonymize: - await delete_email(email.id) - return {"paid": True} - return {"paid": False} - - -@smtp_ext.post("/api/v1/email/{emailaddress_id}") -async def api_smtp_make_email(emailaddress_id, data: CreateEmail): - valid_email(data.receiver) - - emailaddress = await get_emailaddress(emailaddress_id) - if not emailaddress: - raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, - detail="Emailaddress address does not exist.", - ) - try: - memo = f"sent email from {emailaddress.email} to {data.receiver}" - if emailaddress.anonymize: - memo = "sent email" - - payment_hash, payment_request = await create_invoice( - wallet_id=emailaddress.wallet, - amount=emailaddress.cost, - memo=memo, - extra={"tag": "smtp"}, - ) - except Exception as e: - raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e)) - - email = await create_email( - payment_hash=payment_hash, wallet=emailaddress.wallet, data=data - ) - - if not email: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Email could not be fetched." - ) - return {"payment_hash": payment_hash, "payment_request": payment_request} - - -@smtp_ext.post( - "/api/v1/email/{emailaddress_id}/send", dependencies=[Depends(require_admin_key)] -) -async def api_smtp_make_email_send(emailaddress_id, data: CreateEmail): - valid_email(data.receiver) - emailaddress = await get_emailaddress(emailaddress_id) - if not emailaddress: - raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, - detail="Emailaddress address does not exist.", - ) - email = await create_email(wallet=emailaddress.wallet, data=data) - if not email: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Email could not be fetched." - ) - await send_mail(emailaddress, email) - return {"sent": True} - - -@smtp_ext.delete("/api/v1/email/{email_id}") -async def api_email_delete(email_id, g: WalletTypeInfo = Depends(get_key_type)): - email = await get_email(email_id) - - if not email: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="LNsubdomain does not exist." - ) - - if email.wallet != g.wallet.id: - raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your email.") - - await delete_email(email_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) - - -## EMAILADDRESSES -@smtp_ext.get("/api/v1/emailaddress") -async def api_emailaddresses( - g: WalletTypeInfo = Depends(get_key_type), - all_wallets: bool = Query(False), -): - wallet_ids = [g.wallet.id] - if all_wallets: - user = await get_user(g.wallet.user) - if user: - wallet_ids = user.wallet_ids - return [ - emailaddress.dict() for emailaddress in await get_emailaddresses(wallet_ids) - ] - - -@smtp_ext.post("/api/v1/emailaddress") -@smtp_ext.put("/api/v1/emailaddress/{emailaddress_id}") -async def api_emailaddress_create( - data: CreateEmailaddress, - emailaddress_id=None, - g: WalletTypeInfo = Depends(get_key_type), -): - if emailaddress_id: - emailaddress = await get_emailaddress(emailaddress_id) - - if not emailaddress: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Emailadress does not exist." - ) - if emailaddress.wallet != g.wallet.id: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="Not your emailaddress." - ) - - emailaddress = await update_emailaddress(emailaddress_id, **data.dict()) - else: - emailaddress = await create_emailaddress(data=data) - return emailaddress.dict() - - -@smtp_ext.delete("/api/v1/emailaddress/{emailaddress_id}") -async def api_emailaddress_delete( - emailaddress_id, g: WalletTypeInfo = Depends(get_key_type) -): - emailaddress = await get_emailaddress(emailaddress_id) - - if not emailaddress: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Emailaddress does not exist." - ) - if emailaddress.wallet != g.wallet.id: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="Not your Emailaddress." - ) - - await delete_emailaddress(emailaddress_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT)