From 967f46f82af770e1e7373670894a15042ded1308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Fri, 17 Feb 2023 15:18:39 +0100 Subject: [PATCH] remove paywall (#1518) --- lnbits/extensions/paywall/README.md | 22 -- lnbits/extensions/paywall/__init__.py | 25 -- lnbits/extensions/paywall/config.json | 6 - lnbits/extensions/paywall/crud.py | 52 --- lnbits/extensions/paywall/migrations.py | 63 ---- lnbits/extensions/paywall/models.py | 41 --- .../paywall/static/image/paywall.png | Bin 16793 -> 0 bytes .../paywall/templates/paywall/_api_docs.html | 148 --------- .../paywall/templates/paywall/display.html | 168 ---------- .../paywall/templates/paywall/index.html | 312 ------------------ lnbits/extensions/paywall/views.py | 30 -- lnbits/extensions/paywall/views_api.py | 105 ------ 12 files changed, 972 deletions(-) delete mode 100644 lnbits/extensions/paywall/README.md delete mode 100644 lnbits/extensions/paywall/__init__.py delete mode 100644 lnbits/extensions/paywall/config.json delete mode 100644 lnbits/extensions/paywall/crud.py delete mode 100644 lnbits/extensions/paywall/migrations.py delete mode 100644 lnbits/extensions/paywall/models.py delete mode 100644 lnbits/extensions/paywall/static/image/paywall.png delete mode 100644 lnbits/extensions/paywall/templates/paywall/_api_docs.html delete mode 100644 lnbits/extensions/paywall/templates/paywall/display.html delete mode 100644 lnbits/extensions/paywall/templates/paywall/index.html delete mode 100644 lnbits/extensions/paywall/views.py delete mode 100644 lnbits/extensions/paywall/views_api.py diff --git a/lnbits/extensions/paywall/README.md b/lnbits/extensions/paywall/README.md deleted file mode 100644 index 738485e28..000000000 --- a/lnbits/extensions/paywall/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Paywall - -## Hide content behind a paywall, a user has to pay some amount to access your hidden content - -A Paywall is a way of restricting to content via a purchase or paid subscription. For example to read a determined blog post, or to continue reading further, to access a downloads area, etc... - -## Usage - -1. Create a paywall by clicking "NEW PAYWALL"\ - ![create new paywall](https://i.imgur.com/q0ZIekC.png) -2. Fill the options for your PAYWALL - - select the wallet - - set the link that will be unlocked after a successful payment - - give your paywall a _Title_ - - an optional small description - - and set an amount a user must pay to access the hidden content. Note this is the minimum amount, a user can over pay if they wish - - if _Remember payments_ is checked, a returning paying user won't have to pay again for the same content.\ - ![paywall config](https://i.imgur.com/CBW48F6.png) -3. You can then use your paywall link to secure your awesome content\ - ![paywall link](https://i.imgur.com/hDQmCDf.png) -4. When a user wants to access your hidden content, he can use the minimum amount or increase and click the "_Check icon_" to generate an invoice, user will then be redirected to the content page\ - ![user paywall view](https://i.imgur.com/3pLywkZ.png) diff --git a/lnbits/extensions/paywall/__init__.py b/lnbits/extensions/paywall/__init__.py deleted file mode 100644 index 5565a9349..000000000 --- a/lnbits/extensions/paywall/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -from fastapi import APIRouter -from starlette.staticfiles import StaticFiles - -from lnbits.db import Database -from lnbits.helpers import template_renderer - -db = Database("ext_paywall") - -paywall_ext: APIRouter = APIRouter(prefix="/paywall", tags=["Paywall"]) - -paywall_static_files = [ - { - "path": "/paywall/static", - "app": StaticFiles(directory="lnbits/extensions/paywall/static"), - "name": "paywall_static", - } -] - - -def paywall_renderer(): - return template_renderer(["lnbits/extensions/paywall/templates"]) - - -from .views import * # noqa: F401,F403 -from .views_api import * # noqa: F401,F403 diff --git a/lnbits/extensions/paywall/config.json b/lnbits/extensions/paywall/config.json deleted file mode 100644 index 749d19891..000000000 --- a/lnbits/extensions/paywall/config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "Paywall", - "short_description": "Create paywalls for content", - "tile": "/paywall/static/image/paywall.png", - "contributors": ["eillarra"] -} diff --git a/lnbits/extensions/paywall/crud.py b/lnbits/extensions/paywall/crud.py deleted file mode 100644 index cb9e210d5..000000000 --- a/lnbits/extensions/paywall/crud.py +++ /dev/null @@ -1,52 +0,0 @@ -from typing import List, Optional, Union - -from lnbits.helpers import urlsafe_short_hash - -from . import db -from .models import CreatePaywall, Paywall - - -async def create_paywall(wallet_id: str, data: CreatePaywall) -> Paywall: - paywall_id = urlsafe_short_hash() - await db.execute( - """ - INSERT INTO paywall.paywalls (id, wallet, url, memo, description, amount, remembers) - VALUES (?, ?, ?, ?, ?, ?, ?) - """, - ( - paywall_id, - wallet_id, - data.url, - data.memo, - data.description, - data.amount, - int(data.remembers), - ), - ) - - paywall = await get_paywall(paywall_id) - assert paywall, "Newly created paywall couldn't be retrieved" - return paywall - - -async def get_paywall(paywall_id: str) -> Optional[Paywall]: - row = await db.fetchone( - "SELECT * FROM paywall.paywalls WHERE id = ?", (paywall_id,) - ) - return Paywall.from_row(row) if row else None - - -async def get_paywalls(wallet_ids: Union[str, List[str]]) -> List[Paywall]: - if isinstance(wallet_ids, str): - wallet_ids = [wallet_ids] - - q = ",".join(["?"] * len(wallet_ids)) - rows = await db.fetchall( - f"SELECT * FROM paywall.paywalls WHERE wallet IN ({q})", (*wallet_ids,) - ) - - return [Paywall.from_row(row) for row in rows] - - -async def delete_paywall(paywall_id: str) -> None: - await db.execute("DELETE FROM paywall.paywalls WHERE id = ?", (paywall_id,)) diff --git a/lnbits/extensions/paywall/migrations.py b/lnbits/extensions/paywall/migrations.py deleted file mode 100644 index 9b3341fd4..000000000 --- a/lnbits/extensions/paywall/migrations.py +++ /dev/null @@ -1,63 +0,0 @@ -async def m001_initial(db): - """ - Initial paywalls table. - """ - await db.execute( - f""" - CREATE TABLE paywall.paywalls ( - id TEXT PRIMARY KEY, - wallet TEXT NOT NULL, - secret TEXT NOT NULL, - url TEXT NOT NULL, - memo TEXT NOT NULL, - amount {db.big_int} NOT NULL, - time TIMESTAMP NOT NULL DEFAULT """ - + db.timestamp_now - + """ - ); - """ - ) - - -async def m002_redux(db): - """ - Creates an improved paywalls table and migrates the existing data. - """ - await db.execute("ALTER TABLE paywall.paywalls RENAME TO paywalls_old") - await db.execute( - f""" - CREATE TABLE paywall.paywalls ( - id TEXT PRIMARY KEY, - wallet TEXT NOT NULL, - url TEXT NOT NULL, - memo TEXT NOT NULL, - description TEXT NULL, - amount {db.big_int} DEFAULT 0, - time TIMESTAMP NOT NULL DEFAULT """ - + db.timestamp_now - + """, - remembers INTEGER DEFAULT 0, - extras TEXT NULL - ); - """ - ) - - for row in [ - list(row) for row in await db.fetchall("SELECT * FROM paywall.paywalls_old") - ]: - await db.execute( - """ - INSERT INTO paywall.paywalls ( - id, - wallet, - url, - memo, - amount, - time - ) - VALUES (?, ?, ?, ?, ?, ?) - """, - (row[0], row[1], row[3], row[4], row[5], row[6]), - ) - - await db.execute("DROP TABLE paywall.paywalls_old") diff --git a/lnbits/extensions/paywall/models.py b/lnbits/extensions/paywall/models.py deleted file mode 100644 index 7082c5412..000000000 --- a/lnbits/extensions/paywall/models.py +++ /dev/null @@ -1,41 +0,0 @@ -import json -from sqlite3 import Row -from typing import Optional - -from fastapi import Query -from pydantic import BaseModel - - -class CreatePaywall(BaseModel): - url: str = Query(...) - memo: str = Query(...) - description: str = Query(None) - amount: int = Query(..., ge=0) - remembers: bool = Query(...) - - -class CreatePaywallInvoice(BaseModel): - amount: int = Query(..., ge=1) - - -class CheckPaywallInvoice(BaseModel): - payment_hash: str = Query(...) - - -class Paywall(BaseModel): - id: str - wallet: str - url: str - memo: str - description: Optional[str] - amount: int - time: int - remembers: bool - extras: Optional[dict] - - @classmethod - def from_row(cls, row: Row) -> "Paywall": - data = dict(row) - data["remembers"] = bool(data["remembers"]) - data["extras"] = json.loads(data["extras"]) if data["extras"] else None - return cls(**data) diff --git a/lnbits/extensions/paywall/static/image/paywall.png b/lnbits/extensions/paywall/static/image/paywall.png deleted file mode 100644 index 0331a953c9d6ebd914706e3bffaba804ff5f1dc4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16793 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 - - - - - GET /paywall/api/v1/paywalls -
Headers
- {"X-Api-Key": <invoice_key>}
-
Body (application/json)
-
- Returns 200 OK (application/json) -
- [<paywall_object>, ...] -
Curl example
- curl -X GET {{ request.base_url }}paywall/api/v1/paywalls -H - "X-Api-Key: {{ user.wallets[0].inkey }}" - -
-
-
- - - - POST /paywall/api/v1/paywalls -
Headers
- {"X-Api-Key": <admin_key>}
-
Body (application/json)
- {"amount": <integer>, "description": <string>, "memo": - <string>, "remembers": <boolean>, "url": - <string>} -
- Returns 201 CREATED (application/json) -
- {"amount": <integer>, "description": <string>, "id": - <string>, "memo": <string>, "remembers": <boolean>, - "time": <int>, "url": <string>, "wallet": - <string>} -
Curl example
- curl -X POST {{ request.base_url }}paywall/api/v1/paywalls -d - '{"url": <string>, "memo": <string>, "description": - <string>, "amount": <integer>, "remembers": - <boolean>}' -H "Content-type: application/json" -H "X-Api-Key: - {{ user.wallets[0].adminkey }}" - -
-
-
- - - - POST - /paywall/api/v1/paywalls/<paywall_id>/invoice -
Body (application/json)
- {"amount": <integer>} -
- Returns 201 CREATED (application/json) -
- {"payment_hash": <string>, "payment_request": - <string>} -
Curl example
- curl -X POST {{ request.base_url - }}paywall/api/v1/paywalls/<paywall_id>/invoice -d '{"amount": - <integer>}' -H "Content-type: application/json" - -
-
-
- - - - POST - /paywall/api/v1/paywalls/<paywall_id>/check_invoice -
Body (application/json)
- {"payment_hash": <string>} -
- Returns 200 OK (application/json) -
- {"paid": false}
- {"paid": true, "url": <string>, "remembers": - <boolean>} -
Curl example
- curl -X POST {{ request.base_url - }}paywall/api/v1/paywalls/<paywall_id>/check_invoice -d - '{"payment_hash": <string>}' -H "Content-type: application/json" - -
-
-
- - - - DELETE - /paywall/api/v1/paywalls/<paywall_id> -
Headers
- {"X-Api-Key": <admin_key>}
-
Returns 204 NO CONTENT
- -
Curl example
- curl -X DELETE {{ request.base_url - }}paywall/api/v1/paywalls/<paywall_id> -H "X-Api-Key: {{ - user.wallets[0].adminkey }}" - -
-
-
- diff --git a/lnbits/extensions/paywall/templates/paywall/display.html b/lnbits/extensions/paywall/templates/paywall/display.html deleted file mode 100644 index a5edd1025..000000000 --- a/lnbits/extensions/paywall/templates/paywall/display.html +++ /dev/null @@ -1,168 +0,0 @@ -{% extends "public.html" %} {% block page %} -
-
- - -
{{ paywall.memo }}
- {% if paywall.description %} -

{{ paywall.description }}

- {% endif %} -
- - - -
- Send -
-
-
- - - - - -
- Copy invoice - Cancel -
-
-
-
- -

- You can access the URL behind this paywall:
- {% raw %}{{ redirectUrl }}{% endraw %} -

-
- Open URL -
-
-
-
-
-
-{% endblock %} {% block scripts %} - -{% endblock %} diff --git a/lnbits/extensions/paywall/templates/paywall/index.html b/lnbits/extensions/paywall/templates/paywall/index.html deleted file mode 100644 index 482d1465e..000000000 --- a/lnbits/extensions/paywall/templates/paywall/index.html +++ /dev/null @@ -1,312 +0,0 @@ -{% extends "base.html" %} {% from "macros.jinja" import window_vars with context -%} {% block page %} -
-
- - - New paywall - - - - - -
-
-
Paywalls
-
-
- Export to CSV -
-
- - {% raw %} - - - {% endraw %} - -
-
-
- -
- - -
- {{SITE_TITLE}} paywall extension -
-
- - - {% include "paywall/_api_docs.html" %} - -
-
- - - - - - - - - - - - - - - - - Remember payments - A succesful payment will be registered in the browser's - storage, so the user doesn't need to pay again to access the - URL. - - - -
- Create paywall - Cancel -
-
-
-
-
-{% endblock %} {% block scripts %} {{ window_vars(user) }} - -{% endblock %} diff --git a/lnbits/extensions/paywall/views.py b/lnbits/extensions/paywall/views.py deleted file mode 100644 index 340f23c39..000000000 --- a/lnbits/extensions/paywall/views.py +++ /dev/null @@ -1,30 +0,0 @@ -from http import HTTPStatus - -from fastapi import Depends -from starlette.exceptions import HTTPException -from starlette.requests import Request - -from lnbits.core.models import User -from lnbits.decorators import check_user_exists - -from . import paywall_ext, paywall_renderer -from .crud import get_paywall - - -@paywall_ext.get("/") -async def index(request: Request, user: User = Depends(check_user_exists)): - return paywall_renderer().TemplateResponse( - "paywall/index.html", {"request": request, "user": user.dict()} - ) - - -@paywall_ext.get("/{paywall_id}") -async def display(request: Request, paywall_id): - paywall = await get_paywall(paywall_id) - if not paywall: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Paywall does not exist." - ) - return paywall_renderer().TemplateResponse( - "paywall/display.html", {"request": request, "paywall": paywall} - ) diff --git a/lnbits/extensions/paywall/views_api.py b/lnbits/extensions/paywall/views_api.py deleted file mode 100644 index 26480e016..000000000 --- a/lnbits/extensions/paywall/views_api.py +++ /dev/null @@ -1,105 +0,0 @@ -from http import HTTPStatus - -from fastapi import Depends, Query -from starlette.exceptions import HTTPException - -from lnbits.core.crud import get_user, get_wallet -from lnbits.core.services import check_transaction_status, create_invoice -from lnbits.decorators import WalletTypeInfo, get_key_type - -from . import paywall_ext -from .crud import create_paywall, delete_paywall, get_paywall, get_paywalls -from .models import CheckPaywallInvoice, CreatePaywall, CreatePaywallInvoice - - -@paywall_ext.get("/api/v1/paywalls") -async def api_paywalls( - wallet: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False) -): - wallet_ids = [wallet.wallet.id] - - if all_wallets: - user = await get_user(wallet.wallet.user) - wallet_ids = user.wallet_ids if user else [] - - return [paywall.dict() for paywall in await get_paywalls(wallet_ids)] - - -@paywall_ext.post("/api/v1/paywalls") -async def api_paywall_create( - data: CreatePaywall, wallet: WalletTypeInfo = Depends(get_key_type) -): - paywall = await create_paywall(wallet_id=wallet.wallet.id, data=data) - return paywall.dict() - - -@paywall_ext.delete("/api/v1/paywalls/{paywall_id}") -async def api_paywall_delete( - paywall_id, wallet: WalletTypeInfo = Depends(get_key_type) -): - paywall = await get_paywall(paywall_id) - - if not paywall: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Paywall does not exist." - ) - - if paywall.wallet != wallet.wallet.id: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="Not your paywall." - ) - - await delete_paywall(paywall_id) - return "", HTTPStatus.NO_CONTENT - - -@paywall_ext.post("/api/v1/paywalls/invoice/{paywall_id}") -async def api_paywall_create_invoice( - data: CreatePaywallInvoice, paywall_id: str = Query(None) -): - paywall = await get_paywall(paywall_id) - assert paywall - if data.amount < paywall.amount: - raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, - detail=f"Minimum amount is {paywall.amount} sat.", - ) - try: - amount = data.amount if data.amount > paywall.amount else paywall.amount - payment_hash, payment_request = await create_invoice( - wallet_id=paywall.wallet, - amount=amount, - memo=f"{paywall.memo}", - extra={"tag": "paywall"}, - ) - except Exception as e: - raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e)) - - return {"payment_hash": payment_hash, "payment_request": payment_request} - - -@paywall_ext.post("/api/v1/paywalls/check_invoice/{paywall_id}") -async def api_paywal_check_invoice( - data: CheckPaywallInvoice, paywall_id: str = Query(None) -): - paywall = await get_paywall(paywall_id) - payment_hash = data.payment_hash - if not paywall: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Paywall does not exist." - ) - try: - status = await check_transaction_status(paywall.wallet, payment_hash) - is_paid = not status.pending - except Exception: - return {"paid": False} - - if is_paid: - wallet = await get_wallet(paywall.wallet) - assert wallet - payment = await wallet.get_payment(payment_hash) - assert payment - await payment.set_pending(False) - - return {"paid": True, "url": paywall.url, "remembers": paywall.remembers} - return {"paid": False}