diff --git a/lnbits/extensions/satspay/config.json b/lnbits/extensions/satspay/config.json
index beb0071cb..fe9e3df49 100644
--- a/lnbits/extensions/satspay/config.json
+++ b/lnbits/extensions/satspay/config.json
@@ -2,7 +2,5 @@
"name": "SatsPay Server",
"short_description": "Create onchain and LN charges",
"icon": "payment",
- "contributors": [
- "arcbtc"
- ]
+ "contributors": ["arcbtc"]
}
diff --git a/lnbits/extensions/satspay/crud.py b/lnbits/extensions/satspay/crud.py
index 6ed324a4c..113b0cb44 100644
--- a/lnbits/extensions/satspay/crud.py
+++ b/lnbits/extensions/satspay/crud.py
@@ -10,7 +10,8 @@ from lnbits.helpers import urlsafe_short_hash
from ..watchonly.crud import get_config, get_fresh_address
from . import db
from .helpers import fetch_onchain_balance
-from .models import Charges, CreateCharge, SatsPaySettings
+from .models import Charges, CreateCharge, SatsPayThemes
+
###############CHARGES##########################
@@ -53,7 +54,8 @@ async def create_charge(user: str, data: CreateCharge) -> Charges:
time,
amount,
balance,
- extra
+ extra,
+ custom_css,
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
@@ -71,6 +73,7 @@ async def create_charge(user: str, data: CreateCharge) -> Charges:
data.completelinktext,
data.time,
data.amount,
+ data.custom_css,
0,
data.extra,
),
@@ -124,41 +127,51 @@ async def check_address_balance(charge_id: str) -> Optional[Charges]:
################## SETTINGS ###################
-async def save_settings(user_id: str, data: SatsPaySettings):
+
+
+async def save_theme(data: SatsPayThemes, css_id: str = None):
# insert or update
- row = await db.fetchone(
- """SELECT user_id FROM satspay.settings WHERE user_id = ?""", (user_id,)
- )
- if row:
+ if css_id:
await db.execute(
"""
- UPDATE satspay.settings SET custom_css = ? WHERE user_id = ?
+ UPDATE satspay.themes SET custom_css = ?, title = ? WHERE css_id = ?
""",
- (data.custom_css, user_id),
+ (data.custom_css, data.title, css_id),
)
else:
+ css_id = urlsafe_short_hash()
await db.execute(
"""
- INSERT INTO satspay.settings (
- user_id,
+ INSERT INTO satspay.themes (
+ css_id,
+ title,
+ user,
custom_css
)
- VALUES (?, ?)
+ VALUES (?, ?, ?, ?)
""",
(
- user_id,
+ css_id,
+ data.title,
+ data.user,
data.custom_css,
),
)
- return True
+ return await get_theme(css_id)
-async def get_settings(user_id: str) -> SatsPaySettings:
- row = await db.fetchone(
- """SELECT * FROM satspay.settings WHERE user_id = ?""",
+async def get_theme(css_id: str) -> SatsPayThemes:
+ row = await db.fetchone("SELECT * FROM satspay.themes WHERE css_id = ?", (css_id,))
+ return SatsPayThemes.from_row(row) if row else None
+
+
+async def get_themes(user_id: str) -> List[SatsPayThemes]:
+ rows = await db.fetchall(
+ """SELECT * FROM satspay.themes WHERE "user" = ? ORDER BY "timestamp" DESC """,
(user_id,),
)
- if row:
- return SatsPaySettings.from_row(row)
- else:
- return None
+ return [SatsPayThemes.from_row(row) for row in rows]
+
+
+async def delete_theme(theme_id: str) -> None:
+ await db.execute("DELETE FROM satspay.themes WHERE css_id = ?", (theme_id,))
diff --git a/lnbits/extensions/satspay/migrations.py b/lnbits/extensions/satspay/migrations.py
index fe0a9d9c6..8787cc8b3 100644
--- a/lnbits/extensions/satspay/migrations.py
+++ b/lnbits/extensions/satspay/migrations.py
@@ -38,16 +38,26 @@ async def m002_add_charge_extra_data(db):
"""
)
-async def m002_add_settings_table(db):
+async def m002_add_themes_table(db):
"""
- Settings table
+ Themes table
"""
await db.execute(
"""
- CREATE TABLE satspay.settings (
- user_id TEXT,
+ CREATE TABLE satspay.themes (
+ css_id TEXT,
+ user TEXT,
+ title TEXT,
custom_css TEXT
);
"""
)
+
+
+async def m003_add_custom_css_to_charges(db):
+ """
+ Add custom css option column to the 'charges' table
+ """
+
+ await db.execute("ALTER TABLE satspay.charges ADD COLUMN custom_css TEXT;")
diff --git a/lnbits/extensions/satspay/models.py b/lnbits/extensions/satspay/models.py
index 94c0938c0..4227cabc3 100644
--- a/lnbits/extensions/satspay/models.py
+++ b/lnbits/extensions/satspay/models.py
@@ -14,6 +14,7 @@ class CreateCharge(BaseModel):
webhook: str = Query(None)
completelink: str = Query(None)
completelinktext: str = Query(None)
+ custom_css: Optional[str]
time: int = Query(..., ge=1)
amount: int = Query(..., ge=1)
extra: str = "{}"
@@ -38,6 +39,7 @@ class Charges(BaseModel):
completelink: Optional[str]
completelinktext: Optional[str] = "Back to Merchant"
extra: str = "{}"
+ custom_css: Optional[str]
time: int
amount: int
balance: int
@@ -73,9 +75,12 @@ class Charges(BaseModel):
def must_call_webhook(self):
return self.webhook and self.paid and self.config.webhook_success == False
-class SatsPaySettings(BaseModel):
+class SatsPayThemes(BaseModel):
+ css_id: str = Query(None)
+ title: str = Query(None)
custom_css: str = Query(None)
+ user: Optional[str]
@classmethod
- def from_row(cls, row: Row) -> "SatsPaySettings":
+ def from_row(cls, row: Row) -> "SatsPayThemes":
return cls(**dict(row))
diff --git a/lnbits/extensions/satspay/static/js/utils.js b/lnbits/extensions/satspay/static/js/utils.js
index 929279554..2b1be8bdc 100644
--- a/lnbits/extensions/satspay/static/js/utils.js
+++ b/lnbits/extensions/satspay/static/js/utils.js
@@ -26,5 +26,10 @@ const mapCharge = (obj, oldObj = {}) => {
return charge
}
+const mapCSS = (obj, oldObj = {}) => {
+ const theme = _.clone(obj)
+ return theme
+}
+
const minutesToTime = min =>
min > 0 ? new Date(min * 1000).toISOString().substring(14, 19) : ''
diff --git a/lnbits/extensions/satspay/templates/satspay/_api_docs.html b/lnbits/extensions/satspay/templates/satspay/_api_docs.html
index ed6587357..6d5ae661e 100644
--- a/lnbits/extensions/satspay/templates/satspay/_api_docs.html
+++ b/lnbits/extensions/satspay/templates/satspay/_api_docs.html
@@ -5,7 +5,13 @@
WatchOnly extension, we highly reccomend using a fresh extended public Key
specifically for SatsPayServer!
- Created by, Ben ArcBen Arc,
+ motorina0
diff --git a/lnbits/extensions/satspay/templates/satspay/display.html b/lnbits/extensions/satspay/templates/satspay/display.html
index 6d34a386f..437f81c7f 100644
--- a/lnbits/extensions/satspay/templates/satspay/display.html
+++ b/lnbits/extensions/satspay/templates/satspay/display.html
@@ -299,7 +299,7 @@
{% endblock %} {% block styles %}
@@ -324,6 +324,7 @@
charge: JSON.parse('{{charge_data | tojson}}'),
mempoolEndpoint: '{{mempool_endpoint}}',
network: '{{network}}',
+ css_id: '{{ charge_data.css_id }}',
pendingFunds: 0,
ws: null,
newProgress: 0.4,
@@ -462,8 +463,10 @@
await this.getCustomCss()
if (this.charge.payment_request) this.payInvoice()
// Remove a user defined theme
- document.body.setAttribute('data-theme', '')
-
+ console.log(this.charge.custom_css)
+ if (this.charge.custom_css) {
+ document.body.setAttribute('data-theme', '')
+ }
if (this.charge.lnbitswallet) this.payInvoice()
else this.payOnchain()
diff --git a/lnbits/extensions/satspay/templates/satspay/index.html b/lnbits/extensions/satspay/templates/satspay/index.html
index fb7c42855..08bf785dc 100644
--- a/lnbits/extensions/satspay/templates/satspay/index.html
+++ b/lnbits/extensions/satspay/templates/satspay/index.html
@@ -12,8 +12,8 @@
SatsPay settings
+ @click="getThemes();formDialogThemes.show = true"
+ >New CSS Theme
@@ -266,6 +266,63 @@
+
+
+
+
+
+ {% raw %}
+
+
+
+ {{ col.label }}
+
+
+
+
+
+
+
+
+ {{ col.value }}
+
+
+
+
+
+
+
+
+
+ {% endraw %}
+
+
+
@@ -384,6 +441,15 @@
label="Wallet *"
>
+
+
-
+
-
+
+
- Custom CSS to apply styles to your SatsPay invoice
- Save Settings
- Update CSS theme
+ Save CSS theme
+ Cancel
@@ -446,7 +525,9 @@
balance: null,
walletLinks: [],
chargeLinks: [],
- onchainwallet: null,
+ themeLinks: [],
+ themeOptions: [],
+ onchainwallet: '',
rescanning: false,
mempool: {
endpoint: '',
@@ -526,7 +607,25 @@
rowsPerPage: 10
}
},
-
+ customCSSTable: {
+ columns: [
+ {
+ name: 'css_id',
+ align: 'left',
+ label: 'ID',
+ field: 'css_id'
+ },
+ {
+ name: 'title',
+ align: 'left',
+ label: 'Title',
+ field: 'title'
+ }
+ ],
+ pagination: {
+ rowsPerPage: 10
+ }
+ },
formDialogCharge: {
show: false,
data: {
@@ -534,11 +633,12 @@
onchainwallet: '',
lnbits: false,
description: '',
+ custom_css: '',
time: null,
amount: null
}
},
- formDialogSettings: {
+ formDialogThemes: {
show: false,
data: {
custom_css: ''
@@ -547,9 +647,9 @@
}
},
methods: {
- cancelSettings: function (data) {
+ cancelThemes: function (data) {
this.formDialogCharge.data.custom_css = ''
- this.formDialogSettings.show = false
+ this.formDialogThemes.show = false
},
cancelCharge: function (data) {
this.formDialogCharge.data.description = ''
@@ -559,6 +659,7 @@
this.formDialogCharge.data.time = null
this.formDialogCharge.data.amount = null
this.formDialogCharge.data.webhook = ''
+ this.formDialogCharge.data.custom_css = ''
this.formDialogCharge.data.completelink = ''
this.formDialogCharge.show = false
},
@@ -623,30 +724,38 @@
}
},
- getSettings: async function () {
+ getThemes: async function () {
try {
const {data} = await LNbits.api.request(
'GET',
- '/satspay/api/v1/settings',
+ '/satspay/api/v1/themes',
this.g.user.wallets[0].inkey
)
- if (data) {
- this.formDialogSettings.data.custom_css = data.custom_css
- }
+ console.log(data)
+ this.themeLinks = data.map(c =>
+ mapCSS(
+ c,
+ this.themeLinks.find(old => old.css_id === c.css_id)
+ )
+ )
+ this.themeOptions = data.map(w => ({
+ id: w.css_id,
+ label: w.title + ' - ' + w.css_id
+ }))
} catch (error) {
LNbits.utils.notifyApiError(error)
}
},
- sendFormDataSettings: function () {
+ sendFormDataThemes: function () {
const wallet = this.g.user.wallets[0].inkey
- const data = this.formDialogSettings.data
- data.custom_css = data.custom_css
- this.saveSettings(wallet, data)
+ const data = this.formDialogThemes.data
+ this.createTheme(wallet, data)
},
sendFormDataCharge: function () {
- const wallet = this.g.user.wallets[0].inkey
+ this.formDialogCharge.data.custom_css = this.formDialogCharge.data.custom_css.id
const data = this.formDialogCharge.data
+ const wallet = this.g.user.wallets[0].inkey
data.amount = parseInt(data.amount)
data.time = parseInt(data.time)
data.lnbitswallet = data.lnbits ? data.lnbitswallet : null
@@ -715,23 +824,68 @@
this.rescanning = false
}
},
- saveSettings: async function (wallet, data) {
+ updateformDialog: function (themeId) {
+ const theme = _.findWhere(this.themeLinks, {css_id: themeId})
+ console.log(theme.css_id)
+ this.formDialogThemes.data.css_id = theme.css_id
+ this.formDialogThemes.data.title = theme.title
+ this.formDialogThemes.data.custom_css = theme.custom_css
+ this.formDialogThemes.show = true
+ },
+ createTheme: async function (wallet, data) {
+ console.log(data.css_id)
try {
- const resp = await LNbits.api.request(
- 'POST',
- '/satspay/api/v1/settings',
- wallet,
- data
- )
-
- this.formDialogSettings.show = false
- this.formDialogSettings.data = {
+ if (data.css_id) {
+ const resp = await LNbits.api.request(
+ 'POST',
+ '/satspay/api/v1/themes/' + data.css_id,
+ wallet,
+ data
+ )
+ this.themeLinks = _.reject(this.themeLinks, function (obj) {
+ return obj.css_id === data.css_id
+ })
+ this.themeLinks.unshift(mapCSS(resp.data))
+ } else {
+ const resp = await LNbits.api.request(
+ 'POST',
+ '/satspay/api/v1/themes',
+ wallet,
+ data
+ )
+ this.themeLinks.unshift(mapCSS(resp.data))
+ }
+ this.formDialogThemes.show = false
+ this.formDialogThemes.data = {
+ title: '',
custom_css: ''
}
} catch (error) {
+ console.log('cun')
LNbits.utils.notifyApiError(error)
}
},
+
+ deleteTheme: function (themeId) {
+ const theme = _.findWhere(this.themeLinks, {id: themeId})
+ LNbits.utils
+ .confirmDialog('Are you sure you want to delete this theme?')
+ .onOk(async () => {
+ try {
+ const response = await LNbits.api.request(
+ 'DELETE',
+ '/satspay/api/v1/themes/' + themeId,
+ this.g.user.wallets[0].adminkey
+ )
+
+ this.themeLinks = _.reject(this.themeLinks, function (obj) {
+ return obj.css_id === themeId
+ })
+ } catch (error) {
+ LNbits.utils.notifyApiError(error)
+ }
+ })
+ },
createCharge: async function (wallet, data) {
try {
const resp = await LNbits.api.request(
@@ -784,7 +938,7 @@
}
},
created: async function () {
- await this.getSettings()
+ await this.getThemes()
await this.getCharges()
await this.getWalletConfig()
await this.getWalletLinks()
diff --git a/lnbits/extensions/satspay/views.py b/lnbits/extensions/satspay/views.py
index 0618ce1bb..72362f862 100644
--- a/lnbits/extensions/satspay/views.py
+++ b/lnbits/extensions/satspay/views.py
@@ -12,7 +12,7 @@ from lnbits.decorators import check_user_exists
from lnbits.extensions.satspay.helpers import public_charge
from . import satspay_ext, satspay_renderer
-from .crud import get_charge, get_charge_config, get_settings
+from .crud import get_charge, get_charge_config, get_themes, get_theme
templates = Jinja2Templates(directory="templates")
@@ -43,16 +43,10 @@ async def display(request: Request, charge_id: str):
)
-@satspay_ext.get("/css/{charge_id}")
-async def display(charge_id: str, response: Response):
- charge = await get_charge(charge_id)
- if not charge:
- raise HTTPException(
- status_code=HTTPStatus.NOT_FOUND, detail="Charge link does not exist."
- )
- wallet = await get_wallet(charge.lnbitswallet)
- settings = await get_settings(wallet.user)
- if settings:
- return Response(content=settings.custom_css, media_type="text/css")
+@satspay_ext.get("/css/{css_id}")
+async def display(css_id: str, response: Response):
+ theme = await get_theme(css_id)
+ if theme:
+ return Response(content=theme.custom_css, media_type="text/css")
return None
diff --git a/lnbits/extensions/satspay/views_api.py b/lnbits/extensions/satspay/views_api.py
index 429453df4..d5b510ab1 100644
--- a/lnbits/extensions/satspay/views_api.py
+++ b/lnbits/extensions/satspay/views_api.py
@@ -21,13 +21,15 @@ from .crud import (
delete_charge,
get_charge,
get_charges,
- get_settings,
- save_settings,
+ get_theme,
+ get_themes,
+ delete_theme,
+ save_theme,
update_charge,
)
from .helpers import call_webhook, public_charge
from .helpers import compact_charge
-from .models import CreateCharge, SatsPaySettings
+from .models import CreateCharge, SatsPayThemes
#############################CHARGES##########################
@@ -145,22 +147,42 @@ async def api_charge_balance(charge_id):
return {**public_charge(charge)}
-#############################CHARGES##########################
+#############################THEMES##########################
-@satspay_ext.post("/api/v1/settings")
-async def api_settings_save(
- data: SatsPaySettings, wallet: WalletTypeInfo = Depends(require_invoice_key)
+@satspay_ext.post("/api/v1/themes")
+@satspay_ext.post("/api/v1/themes/{css_id}")
+async def api_themes_save(
+ data: SatsPayThemes,
+ wallet: WalletTypeInfo = Depends(require_invoice_key),
+ css_id: str = None,
):
- await save_settings(user_id=wallet.wallet.user, data=data)
- return True
+ if css_id:
+ theme = await save_theme(css_id=css_id, data=data)
+ else:
+ data.user = wallet.wallet.user
+ theme = await save_theme(data=data)
+ return theme
-@satspay_ext.get("/api/v1/settings")
-async def api_settings_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
+@satspay_ext.get("/api/v1/themes")
+async def api_themes_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
try:
- return await get_settings(wallet.wallet.user)
+ return await get_themes(wallet.wallet.user)
except HTTPException:
- logger.error("Error loading satspay settings")
+ logger.error("Error loading satspay themes")
logger.error(HTTPException)
return ""
+
+
+@satspay_ext.delete("/api/v1/themes/{theme_id}")
+async def api_charge_delete(theme_id, wallet: WalletTypeInfo = Depends(get_key_type)):
+ theme = await get_theme(theme_id)
+
+ if not theme:
+ raise HTTPException(
+ status_code=HTTPStatus.NOT_FOUND, detail="Theme does not exist."
+ )
+
+ await delete_theme(theme_id)
+ return "", HTTPStatus.NO_CONTENT