mirror of
https://github.com/lnbits/lnbits.git
synced 2025-09-20 13:04:23 +02:00
black/prettier
This commit is contained in:
@@ -5,7 +5,6 @@ The TwitchAlerts extension allows you to integrate Bitcoin Lightning (and on-cha
|
|||||||
Try to include an image
|
Try to include an image
|
||||||
<img src="https://i.imgur.com/9i4xcQB.png">
|
<img src="https://i.imgur.com/9i4xcQB.png">
|
||||||
|
|
||||||
|
|
||||||
<h2>If your extension has API endpoints, include useful ones here</h2>
|
<h2>If your extension has API endpoints, include useful ones here</h2>
|
||||||
|
|
||||||
<code>curl -H "Content-type: application/json" -X POST https://YOUR-LNBITS/YOUR-EXTENSION/api/v1/EXAMPLE -d '{"amount":"100","memo":"TwitchAlerts"}' -H "X-Api-Key: YOUR_WALLET-ADMIN/INVOICE-KEY"</code>
|
<code>curl -H "Content-type: application/json" -X POST https://YOUR-LNBITS/YOUR-EXTENSION/api/v1/EXAMPLE -d '{"amount":"100","memo":"TwitchAlerts"}' -H "X-Api-Key: YOUR_WALLET-ADMIN/INVOICE-KEY"</code>
|
||||||
|
@@ -3,10 +3,9 @@ from lnbits.db import Database
|
|||||||
|
|
||||||
db = Database("ext_twitchalerts")
|
db = Database("ext_twitchalerts")
|
||||||
|
|
||||||
twitchalerts_ext: Blueprint = Blueprint("twitchalerts",
|
twitchalerts_ext: Blueprint = Blueprint(
|
||||||
__name__,
|
"twitchalerts", __name__, static_folder="static", template_folder="templates"
|
||||||
static_folder="static",
|
)
|
||||||
template_folder="templates")
|
|
||||||
|
|
||||||
from .views_api import * # noqa
|
from .views_api import * # noqa
|
||||||
from .views import * # noqa
|
from .views import * # noqa
|
||||||
|
@@ -79,11 +79,12 @@ async def post_donation(donation_id: str) -> tuple:
|
|||||||
"""
|
"""
|
||||||
donation = await get_donation(donation_id)
|
donation = await get_donation(donation_id)
|
||||||
if not donation:
|
if not donation:
|
||||||
return (jsonify({"message":
|
return (jsonify({"message": "Donation not found!"}), HTTPStatus.BAD_REQUEST)
|
||||||
"Donation not found!"}), HTTPStatus.BAD_REQUEST)
|
|
||||||
if donation.posted:
|
if donation.posted:
|
||||||
return (jsonify({"message": "Donation has already been posted!"}),
|
return (
|
||||||
HTTPStatus.BAD_REQUEST)
|
jsonify({"message": "Donation has already been posted!"}),
|
||||||
|
HTTPStatus.BAD_REQUEST,
|
||||||
|
)
|
||||||
service = await get_service(donation.service)
|
service = await get_service(donation.service)
|
||||||
if service.servicename == "Streamlabs":
|
if service.servicename == "Streamlabs":
|
||||||
url = "https://streamlabs.com/api/v1.0/donations"
|
url = "https://streamlabs.com/api/v1.0/donations"
|
||||||
@@ -100,13 +101,13 @@ async def post_donation(donation_id: str) -> tuple:
|
|||||||
print(response.json())
|
print(response.json())
|
||||||
status = [s for s in list(HTTPStatus) if s == response.status_code][0]
|
status = [s for s in list(HTTPStatus) if s == response.status_code][0]
|
||||||
elif service.servicename == "StreamElements":
|
elif service.servicename == "StreamElements":
|
||||||
return (jsonify({"message": "StreamElements not yet supported!"}),
|
return (
|
||||||
HTTPStatus.BAD_REQUEST)
|
jsonify({"message": "StreamElements not yet supported!"}),
|
||||||
|
HTTPStatus.BAD_REQUEST,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return (jsonify({"message":
|
return (jsonify({"message": "Unsopported servicename"}), HTTPStatus.BAD_REQUEST)
|
||||||
"Unsopported servicename"}), HTTPStatus.BAD_REQUEST)
|
await db.execute("UPDATE Donations SET posted = 1 WHERE id = ?", (donation_id,))
|
||||||
await db.execute("UPDATE Donations SET posted = 1 WHERE id = ?",
|
|
||||||
(donation_id, ))
|
|
||||||
return (jsonify(response.json()), status)
|
return (jsonify(response.json()), status)
|
||||||
|
|
||||||
|
|
||||||
@@ -150,8 +151,7 @@ async def create_service(
|
|||||||
return service
|
return service
|
||||||
|
|
||||||
|
|
||||||
async def get_service(service_id: int,
|
async def get_service(service_id: int, by_state: str = None) -> Optional[Service]:
|
||||||
by_state: str = None) -> Optional[Service]:
|
|
||||||
"""Return a service either by ID or, available, by state
|
"""Return a service either by ID or, available, by state
|
||||||
|
|
||||||
Each Service's donation page is reached through its "state" hash
|
Each Service's donation page is reached through its "state" hash
|
||||||
@@ -159,18 +159,15 @@ async def get_service(service_id: int,
|
|||||||
streamer via typos like 2 -> 3.
|
streamer via typos like 2 -> 3.
|
||||||
"""
|
"""
|
||||||
if by_state:
|
if by_state:
|
||||||
row = await db.fetchone("SELECT * FROM Services WHERE state = ?",
|
row = await db.fetchone("SELECT * FROM Services WHERE state = ?", (by_state,))
|
||||||
(by_state, ))
|
|
||||||
else:
|
else:
|
||||||
row = await db.fetchone("SELECT * FROM Services WHERE id = ?",
|
row = await db.fetchone("SELECT * FROM Services WHERE id = ?", (service_id,))
|
||||||
(service_id, ))
|
|
||||||
return Service.from_row(row) if row else None
|
return Service.from_row(row) if row else None
|
||||||
|
|
||||||
|
|
||||||
async def get_services(wallet_id: str) -> Optional[list]:
|
async def get_services(wallet_id: str) -> Optional[list]:
|
||||||
"""Return all services belonging assigned to the wallet_id"""
|
"""Return all services belonging assigned to the wallet_id"""
|
||||||
rows = await db.fetchall("SELECT * FROM Services WHERE wallet = ?",
|
rows = await db.fetchall("SELECT * FROM Services WHERE wallet = ?", (wallet_id,))
|
||||||
(wallet_id, ))
|
|
||||||
return [Service.from_row(row) for row in rows] if rows else None
|
return [Service.from_row(row) for row in rows] if rows else None
|
||||||
|
|
||||||
|
|
||||||
@@ -192,7 +189,7 @@ async def authenticate_service(service_id, code, redirect_uri):
|
|||||||
async with httpx.AsyncClient() as client:
|
async with httpx.AsyncClient() as client:
|
||||||
response = (await client.post(url, data=data)).json()
|
response = (await client.post(url, data=data)).json()
|
||||||
print(response)
|
print(response)
|
||||||
token = response['access_token']
|
token = response["access_token"]
|
||||||
success = await service_add_token(service_id, token)
|
success = await service_add_token(service_id, token)
|
||||||
return f"/twitchalerts/?usr={user}", success
|
return f"/twitchalerts/?usr={user}", success
|
||||||
|
|
||||||
@@ -218,40 +215,37 @@ async def service_add_token(service_id, token):
|
|||||||
|
|
||||||
async def delete_service(service_id: int) -> None:
|
async def delete_service(service_id: int) -> None:
|
||||||
"""Delete a Service and all corresponding Donations"""
|
"""Delete a Service and all corresponding Donations"""
|
||||||
await db.execute("DELETE FROM Services WHERE id = ?", (service_id, ))
|
await db.execute("DELETE FROM Services WHERE id = ?", (service_id,))
|
||||||
rows = await db.fetchall("SELECT * FROM Donations WHERE service = ?",
|
rows = await db.fetchall("SELECT * FROM Donations WHERE service = ?", (service_id,))
|
||||||
(service_id, ))
|
|
||||||
for row in rows:
|
for row in rows:
|
||||||
await delete_donation(row["id"])
|
await delete_donation(row["id"])
|
||||||
|
|
||||||
|
|
||||||
async def get_donation(donation_id: str) -> Optional[Donation]:
|
async def get_donation(donation_id: str) -> Optional[Donation]:
|
||||||
"""Return a Donation"""
|
"""Return a Donation"""
|
||||||
row = await db.fetchone("SELECT * FROM Donations WHERE id = ?",
|
row = await db.fetchone("SELECT * FROM Donations WHERE id = ?", (donation_id,))
|
||||||
(donation_id, ))
|
|
||||||
return Donation.from_row(row) if row else None
|
return Donation.from_row(row) if row else None
|
||||||
|
|
||||||
|
|
||||||
async def get_donations(wallet_id: str) -> Optional[list]:
|
async def get_donations(wallet_id: str) -> Optional[list]:
|
||||||
"""Return all Donations assigned to wallet_id"""
|
"""Return all Donations assigned to wallet_id"""
|
||||||
rows = await db.fetchall("SELECT * FROM Donations WHERE wallet = ?",
|
rows = await db.fetchall("SELECT * FROM Donations WHERE wallet = ?", (wallet_id,))
|
||||||
(wallet_id, ))
|
|
||||||
return [Donation.from_row(row) for row in rows] if rows else None
|
return [Donation.from_row(row) for row in rows] if rows else None
|
||||||
|
|
||||||
|
|
||||||
async def delete_donation(donation_id: str) -> None:
|
async def delete_donation(donation_id: str) -> None:
|
||||||
"""Delete a Donation and its corresponding statspay charge"""
|
"""Delete a Donation and its corresponding statspay charge"""
|
||||||
await db.execute("DELETE FROM Donations WHERE id = ?", (donation_id, ))
|
await db.execute("DELETE FROM Donations WHERE id = ?", (donation_id,))
|
||||||
await delete_charge(donation_id)
|
await delete_charge(donation_id)
|
||||||
|
|
||||||
|
|
||||||
async def update_donation(donation_id: str, **kwargs) -> Donation:
|
async def update_donation(donation_id: str, **kwargs) -> Donation:
|
||||||
"""Update a Donation"""
|
"""Update a Donation"""
|
||||||
q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
|
q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
|
||||||
await db.execute(f"UPDATE Donations SET {q} WHERE id = ?",
|
await db.execute(
|
||||||
(*kwargs.values(), donation_id))
|
f"UPDATE Donations SET {q} WHERE id = ?", (*kwargs.values(), donation_id)
|
||||||
row = await db.fetchone("SELECT * FROM Donations WHERE id = ?",
|
)
|
||||||
(donation_id, ))
|
row = await db.fetchone("SELECT * FROM Donations WHERE id = ?", (donation_id,))
|
||||||
assert row, "Newly updated donation couldn't be retrieved"
|
assert row, "Newly updated donation couldn't be retrieved"
|
||||||
return Donation(**row)
|
return Donation(**row)
|
||||||
|
|
||||||
@@ -259,9 +253,9 @@ async def update_donation(donation_id: str, **kwargs) -> Donation:
|
|||||||
async def update_service(service_id: str, **kwargs) -> Donation:
|
async def update_service(service_id: str, **kwargs) -> Donation:
|
||||||
"""Update a service"""
|
"""Update a service"""
|
||||||
q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
|
q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
|
||||||
await db.execute(f"UPDATE Services SET {q} WHERE id = ?",
|
await db.execute(
|
||||||
(*kwargs.values(), service_id))
|
f"UPDATE Services SET {q} WHERE id = ?", (*kwargs.values(), service_id)
|
||||||
row = await db.fetchone("SELECT * FROM Services WHERE id = ?",
|
)
|
||||||
(service_id, ))
|
row = await db.fetchone("SELECT * FROM Services WHERE id = ?", (service_id,))
|
||||||
assert row, "Newly updated service couldn't be retrieved"
|
assert row, "Newly updated service couldn't be retrieved"
|
||||||
return Service(**row)
|
return Service(**row)
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
async def m001_initial(db):
|
async def m001_initial(db):
|
||||||
|
|
||||||
await db.execute("""
|
await db.execute(
|
||||||
|
"""
|
||||||
CREATE TABLE IF NOT EXISTS Services (
|
CREATE TABLE IF NOT EXISTS Services (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
state TEXT NOT NULL,
|
state TEXT NOT NULL,
|
||||||
@@ -13,9 +14,11 @@ async def m001_initial(db):
|
|||||||
authenticated BOOLEAN NOT NULL,
|
authenticated BOOLEAN NOT NULL,
|
||||||
token TEXT
|
token TEXT
|
||||||
);
|
);
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
await db.execute("""
|
await db.execute(
|
||||||
|
"""
|
||||||
CREATE TABLE IF NOT EXISTS Donations (
|
CREATE TABLE IF NOT EXISTS Donations (
|
||||||
id TEXT PRIMARY KEY,
|
id TEXT PRIMARY KEY,
|
||||||
wallet TEXT NOT NULL,
|
wallet TEXT NOT NULL,
|
||||||
@@ -28,4 +31,5 @@ async def m001_initial(db):
|
|||||||
posted BOOLEAN NOT NULL,
|
posted BOOLEAN NOT NULL,
|
||||||
FOREIGN KEY(service) REFERENCES Services(id)
|
FOREIGN KEY(service) REFERENCES Services(id)
|
||||||
);
|
);
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
|
@@ -6,6 +6,7 @@ class Donation(NamedTuple):
|
|||||||
"""A Donation simply contains all the necessary information about a
|
"""A Donation simply contains all the necessary information about a
|
||||||
user's donation to a streamer
|
user's donation to a streamer
|
||||||
"""
|
"""
|
||||||
|
|
||||||
id: str # This ID always corresponds to a satspay charge ID
|
id: str # This ID always corresponds to a satspay charge ID
|
||||||
wallet: str
|
wallet: str
|
||||||
name: str # Name of the donor
|
name: str # Name of the donor
|
||||||
@@ -26,6 +27,7 @@ class Service(NamedTuple):
|
|||||||
|
|
||||||
Currently, Streamlabs is the only supported Service.
|
Currently, Streamlabs is the only supported Service.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
id: int
|
id: int
|
||||||
state: str # A random hash used during authentication
|
state: str # A random hash used during authentication
|
||||||
twitchuser: str # The Twitch streamer's username
|
twitchuser: str # The Twitch streamer's username
|
||||||
|
@@ -7,8 +7,9 @@
|
|||||||
Accept Bitcoin donations on Twitch, and integrate them into your alerts.
|
Accept Bitcoin donations on Twitch, and integrate them into your alerts.
|
||||||
Present your viewers with a simple donation page, and add those donations
|
Present your viewers with a simple donation page, and add those donations
|
||||||
to Streamlabs to play alerts on your stream!<br />
|
to Streamlabs to play alerts on your stream!<br />
|
||||||
For detailed setup instructions, check out <a href="https://github.com/Fittiboy/bitcoin-on-twitch">
|
For detailed setup instructions, check out
|
||||||
this guide!</a><br />
|
<a href="https://github.com/Fittiboy/bitcoin-on-twitch"> this guide!</a
|
||||||
|
><br />
|
||||||
<small>
|
<small>
|
||||||
Created by, <a href="https://github.com/Fittiboy">Fitti</a></small
|
Created by, <a href="https://github.com/Fittiboy">Fitti</a></small
|
||||||
>
|
>
|
||||||
|
@@ -18,8 +18,8 @@
|
|||||||
dense
|
dense
|
||||||
v-model.number="donationDialog.data.sats"
|
v-model.number="donationDialog.data.sats"
|
||||||
type="number"
|
type="number"
|
||||||
min=1
|
min="1"
|
||||||
suffix=sats
|
suffix="sats"
|
||||||
:rules="[val => val > 0 || 'Choose a positive number of sats!']"
|
:rules="[val => val > 0 || 'Choose a positive number of sats!']"
|
||||||
label="Amount of sats"
|
label="Amount of sats"
|
||||||
></q-input>
|
></q-input>
|
||||||
|
@@ -151,9 +151,7 @@
|
|||||||
<div class="col-12 col-md-4 col-lg-5 q-gutter-y-md">
|
<div class="col-12 col-md-4 col-lg-5 q-gutter-y-md">
|
||||||
<q-card>
|
<q-card>
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<h6 class="text-subtitle1 q-my-none">
|
<h6 class="text-subtitle1 q-my-none">LNbits Twitch Alerts extension</h6>
|
||||||
LNbits Twitch Alerts extension
|
|
||||||
</h6>
|
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section class="q-pa-none">
|
<q-card-section class="q-pa-none">
|
||||||
<q-separator></q-separator>
|
<q-separator></q-separator>
|
||||||
@@ -231,21 +229,21 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endblock %} {% block scripts %} {{ window_vars(user) }}
|
{% endblock %} {% block scripts %} {{ window_vars(user) }}
|
||||||
<script>
|
<script>
|
||||||
var mapTwitchAlerts = function(obj) {
|
var mapTwitchAlerts = function (obj) {
|
||||||
obj.date = Quasar.utils.date.formatDate(
|
obj.date = Quasar.utils.date.formatDate(
|
||||||
new Date(obj.time * 1000),
|
new Date(obj.time * 1000),
|
||||||
'YYYY-MM-DD HH:mm'
|
'YYYY-MM-DD HH:mm'
|
||||||
)
|
)
|
||||||
obj.fsat = new Intl.NumberFormat(LOCALE).format(obj.amount)
|
obj.fsat = new Intl.NumberFormat(LOCALE).format(obj.amount)
|
||||||
obj.authUrl = ['/twitchalerts/api/v1/getaccess/', obj.id].join('')
|
obj.authUrl = ['/twitchalerts/api/v1/getaccess/', obj.id].join('')
|
||||||
obj.displayUrl = ['/twitchalerts/', obj.state].join('')
|
obj.displayUrl = ['/twitchalerts/', obj.state].join('')
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#vue',
|
el: '#vue',
|
||||||
mixins: [windowMixin],
|
mixins: [windowMixin],
|
||||||
data: function() {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
servicenames: ['Streamlabs'],
|
servicenames: ['Streamlabs'],
|
||||||
services: [],
|
services: [],
|
||||||
@@ -253,7 +251,12 @@
|
|||||||
servicesTable: {
|
servicesTable: {
|
||||||
columns: [
|
columns: [
|
||||||
{name: 'id', align: 'left', label: 'ID', field: 'id'},
|
{name: 'id', align: 'left', label: 'ID', field: 'id'},
|
||||||
{name: 'twitchuser', align: 'left', label: 'Twitch Username', field: 'twitchuser'},
|
{
|
||||||
|
name: 'twitchuser',
|
||||||
|
align: 'left',
|
||||||
|
label: 'Twitch Username',
|
||||||
|
field: 'twitchuser'
|
||||||
|
},
|
||||||
{name: 'wallet', align: 'left', label: 'Wallet', field: 'wallet'},
|
{name: 'wallet', align: 'left', label: 'Wallet', field: 'wallet'},
|
||||||
{
|
{
|
||||||
name: 'servicename',
|
name: 'servicename',
|
||||||
@@ -286,7 +289,12 @@
|
|||||||
},
|
},
|
||||||
donationsTable: {
|
donationsTable: {
|
||||||
columns: [
|
columns: [
|
||||||
{name: 'service', align: 'left', label: 'Service', field: 'service'},
|
{
|
||||||
|
name: 'service',
|
||||||
|
align: 'left',
|
||||||
|
label: 'Service',
|
||||||
|
field: 'service'
|
||||||
|
},
|
||||||
{name: 'donor', align: 'left', label: 'Donor', field: 'donor'},
|
{name: 'donor', align: 'left', label: 'Donor', field: 'donor'},
|
||||||
{name: 'ltext', align: 'left', label: 'Message', field: 'ltext'},
|
{name: 'ltext', align: 'left', label: 'Message', field: 'ltext'},
|
||||||
{name: 'sats', align: 'left', label: 'Sats', field: 'sats'}
|
{name: 'sats', align: 'left', label: 'Sats', field: 'sats'}
|
||||||
@@ -302,7 +310,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getDonations: function() {
|
getDonations: function () {
|
||||||
var self = this
|
var self = this
|
||||||
|
|
||||||
LNbits.api
|
LNbits.api
|
||||||
@@ -311,40 +319,40 @@
|
|||||||
'/twitchalerts/api/v1/donations',
|
'/twitchalerts/api/v1/donations',
|
||||||
this.g.user.wallets[0].inkey
|
this.g.user.wallets[0].inkey
|
||||||
)
|
)
|
||||||
.then(function(response) {
|
.then(function (response) {
|
||||||
self.donations = response.data.map(function(obj) {
|
self.donations = response.data.map(function (obj) {
|
||||||
return mapTwitchAlerts(obj)
|
return mapTwitchAlerts(obj)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
deleteDonation: function(donationId) {
|
deleteDonation: function (donationId) {
|
||||||
var self = this
|
var self = this
|
||||||
var donations = _.findWhere(this.donations, {id: donationId})
|
var donations = _.findWhere(this.donations, {id: donationId})
|
||||||
|
|
||||||
LNbits.utils
|
LNbits.utils
|
||||||
.confirmDialog('Are you sure you want to delete this donation?')
|
.confirmDialog('Are you sure you want to delete this donation?')
|
||||||
.onOk(function() {
|
.onOk(function () {
|
||||||
LNbits.api
|
LNbits.api
|
||||||
.request(
|
.request(
|
||||||
'DELETE',
|
'DELETE',
|
||||||
'/twitchalerts/api/v1/donations/' + donationId,
|
'/twitchalerts/api/v1/donations/' + donationId,
|
||||||
_.findWhere(self.g.user.wallets, {id: donations.wallet}).inkey
|
_.findWhere(self.g.user.wallets, {id: donations.wallet}).inkey
|
||||||
)
|
)
|
||||||
.then(function(response) {
|
.then(function (response) {
|
||||||
self.donations = _.reject(self.donations, function(obj) {
|
self.donations = _.reject(self.donations, function (obj) {
|
||||||
return obj.id == ticketId
|
return obj.id == ticketId
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch(function(error) {
|
.catch(function (error) {
|
||||||
LNbits.utils.notifyApiError(error)
|
LNbits.utils.notifyApiError(error)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
exportdonationsCSV: function() {
|
exportdonationsCSV: function () {
|
||||||
LNbits.utils.exportCSV(this.donationsTable.columns, this.donations)
|
LNbits.utils.exportCSV(this.donationsTable.columns, this.donations)
|
||||||
},
|
},
|
||||||
|
|
||||||
getServices: function() {
|
getServices: function () {
|
||||||
var self = this
|
var self = this
|
||||||
|
|
||||||
LNbits.api
|
LNbits.api
|
||||||
@@ -353,13 +361,13 @@
|
|||||||
'/twitchalerts/api/v1/services',
|
'/twitchalerts/api/v1/services',
|
||||||
this.g.user.wallets[0].inkey
|
this.g.user.wallets[0].inkey
|
||||||
)
|
)
|
||||||
.then(function(response) {
|
.then(function (response) {
|
||||||
self.services = response.data.map(function(obj) {
|
self.services = response.data.map(function (obj) {
|
||||||
return mapTwitchAlerts(obj)
|
return mapTwitchAlerts(obj)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
sendServiceData: function() {
|
sendServiceData: function () {
|
||||||
var wallet = _.findWhere(this.g.user.wallets, {
|
var wallet = _.findWhere(this.g.user.wallets, {
|
||||||
id: this.serviceDialog.data.wallet
|
id: this.serviceDialog.data.wallet
|
||||||
})
|
})
|
||||||
@@ -368,20 +376,20 @@
|
|||||||
this.createService(wallet, data)
|
this.createService(wallet, data)
|
||||||
},
|
},
|
||||||
|
|
||||||
createService: function(wallet, data) {
|
createService: function (wallet, data) {
|
||||||
var self = this
|
var self = this
|
||||||
LNbits.api
|
LNbits.api
|
||||||
.request('POST', '/twitchalerts/api/v1/services', wallet.inkey, data)
|
.request('POST', '/twitchalerts/api/v1/services', wallet.inkey, data)
|
||||||
.then(function(response) {
|
.then(function (response) {
|
||||||
self.services.push(mapTwitchAlerts(response.data))
|
self.services.push(mapTwitchAlerts(response.data))
|
||||||
self.serviceDialog.show = false
|
self.serviceDialog.show = false
|
||||||
self.serviceDialog.data = {}
|
self.serviceDialog.data = {}
|
||||||
})
|
})
|
||||||
.catch(function(error) {
|
.catch(function (error) {
|
||||||
LNbits.utils.notifyApiError(error)
|
LNbits.utils.notifyApiError(error)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
updateserviceDialog: function(serviceId) {
|
updateserviceDialog: function (serviceId) {
|
||||||
var link = _.findWhere(this.services, {id: serviceId})
|
var link = _.findWhere(this.services, {id: serviceId})
|
||||||
console.log(link.id)
|
console.log(link.id)
|
||||||
this.serviceDialog.data.id = link.id
|
this.serviceDialog.data.id = link.id
|
||||||
@@ -392,35 +400,35 @@
|
|||||||
this.serviceDialog.data.client_secret = link.client_secret
|
this.serviceDialog.data.client_secret = link.client_secret
|
||||||
this.serviceDialog.show = true
|
this.serviceDialog.show = true
|
||||||
},
|
},
|
||||||
deleteService: function(servicesId) {
|
deleteService: function (servicesId) {
|
||||||
var self = this
|
var self = this
|
||||||
var services = _.findWhere(this.services, {id: servicesId})
|
var services = _.findWhere(this.services, {id: servicesId})
|
||||||
|
|
||||||
LNbits.utils
|
LNbits.utils
|
||||||
.confirmDialog('Are you sure you want to delete this service link?')
|
.confirmDialog('Are you sure you want to delete this service link?')
|
||||||
.onOk(function() {
|
.onOk(function () {
|
||||||
LNbits.api
|
LNbits.api
|
||||||
.request(
|
.request(
|
||||||
'DELETE',
|
'DELETE',
|
||||||
'/twitchalerts/api/v1/services/' + servicesId,
|
'/twitchalerts/api/v1/services/' + servicesId,
|
||||||
_.findWhere(self.g.user.wallets, {id: services.wallet}).inkey
|
_.findWhere(self.g.user.wallets, {id: services.wallet}).inkey
|
||||||
)
|
)
|
||||||
.then(function(response) {
|
.then(function (response) {
|
||||||
self.services = _.reject(self.services, function(obj) {
|
self.services = _.reject(self.services, function (obj) {
|
||||||
return obj.id == servicesId
|
return obj.id == servicesId
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch(function(error) {
|
.catch(function (error) {
|
||||||
LNbits.utils.notifyApiError(error)
|
LNbits.utils.notifyApiError(error)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
exportservicesCSV: function() {
|
exportservicesCSV: function () {
|
||||||
LNbits.utils.exportCSV(this.servicesTable.columns, this.services)
|
LNbits.utils.exportCSV(this.servicesTable.columns, this.services)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created: function() {
|
created: function () {
|
||||||
if (this.g.user.wallets.length) {
|
if (this.g.user.wallets.length) {
|
||||||
this.getDonations()
|
this.getDonations()
|
||||||
this.getServices()
|
this.getServices()
|
||||||
|
@@ -21,6 +21,6 @@ async def donation(state):
|
|||||||
service = await get_service(0, by_state=state)
|
service = await get_service(0, by_state=state)
|
||||||
if not service:
|
if not service:
|
||||||
abort(HTTPStatus.NOT_FOUND, "Service does not exist.")
|
abort(HTTPStatus.NOT_FOUND, "Service does not exist.")
|
||||||
return await render_template("twitchalerts/display.html",
|
return await render_template(
|
||||||
twitchuser=service.twitchuser,
|
"twitchalerts/display.html", twitchuser=service.twitchuser, service=service.id
|
||||||
service=service.id)
|
)
|
||||||
|
@@ -6,11 +6,22 @@ from lnbits.core.crud import get_wallet, get_user
|
|||||||
from lnbits.utils.exchange_rates import btc_price
|
from lnbits.utils.exchange_rates import btc_price
|
||||||
|
|
||||||
from . import twitchalerts_ext
|
from . import twitchalerts_ext
|
||||||
from .crud import (get_charge_details, get_service_redirect_uri,
|
from .crud import (
|
||||||
create_donation, post_donation, get_donation, get_donations,
|
get_charge_details,
|
||||||
delete_donation, create_service, get_service, get_services,
|
get_service_redirect_uri,
|
||||||
authenticate_service, update_donation, update_service,
|
create_donation,
|
||||||
delete_service)
|
post_donation,
|
||||||
|
get_donation,
|
||||||
|
get_donations,
|
||||||
|
delete_donation,
|
||||||
|
create_service,
|
||||||
|
get_service,
|
||||||
|
get_services,
|
||||||
|
authenticate_service,
|
||||||
|
update_donation,
|
||||||
|
update_service,
|
||||||
|
delete_service,
|
||||||
|
)
|
||||||
from ..satspay.crud import create_charge, get_charge
|
from ..satspay.crud import create_charge, get_charge
|
||||||
|
|
||||||
|
|
||||||
@@ -18,30 +29,14 @@ from ..satspay.crud import create_charge, get_charge
|
|||||||
@api_check_wallet_key("invoice")
|
@api_check_wallet_key("invoice")
|
||||||
@api_validate_post_request(
|
@api_validate_post_request(
|
||||||
schema={
|
schema={
|
||||||
"twitchuser": {
|
"twitchuser": {"type": "string", "required": True},
|
||||||
"type": "string",
|
"client_id": {"type": "string", "required": True},
|
||||||
"required": True
|
"client_secret": {"type": "string", "required": True},
|
||||||
},
|
"wallet": {"type": "string", "required": True},
|
||||||
"client_id": {
|
"servicename": {"type": "string", "required": True},
|
||||||
"type": "string",
|
"onchain": {"type": "string"},
|
||||||
"required": True
|
}
|
||||||
},
|
)
|
||||||
"client_secret": {
|
|
||||||
"type": "string",
|
|
||||||
"required": True
|
|
||||||
},
|
|
||||||
"wallet": {
|
|
||||||
"type": "string",
|
|
||||||
"required": True
|
|
||||||
},
|
|
||||||
"servicename": {
|
|
||||||
"type": "string",
|
|
||||||
"required": True
|
|
||||||
},
|
|
||||||
"onchain": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
async def api_create_service():
|
async def api_create_service():
|
||||||
"""Create a service, which holds data about how/where to post donations"""
|
"""Create a service, which holds data about how/where to post donations"""
|
||||||
service = await create_service(**g.data)
|
service = await create_service(**g.data)
|
||||||
@@ -65,16 +60,14 @@ async def api_get_access(service_id):
|
|||||||
"client_id": service.client_id,
|
"client_id": service.client_id,
|
||||||
"redirect_uri": redirect_uri,
|
"redirect_uri": redirect_uri,
|
||||||
"scope": "donations.create",
|
"scope": "donations.create",
|
||||||
"state": service.state
|
"state": service.state,
|
||||||
}
|
}
|
||||||
endpoint_url = "https://streamlabs.com/api/v1.0/authorize/?"
|
endpoint_url = "https://streamlabs.com/api/v1.0/authorize/?"
|
||||||
querystring = "&".join(
|
querystring = "&".join([f"{key}={value}" for key, value in params.items()])
|
||||||
[f"{key}={value}" for key, value in params.items()])
|
|
||||||
redirect_url = endpoint_url + querystring
|
redirect_url = endpoint_url + querystring
|
||||||
return redirect(redirect_url)
|
return redirect(redirect_url)
|
||||||
else:
|
else:
|
||||||
return (jsonify({"message":
|
return (jsonify({"message": "Service does not exist!"}), HTTPStatus.BAD_REQUEST)
|
||||||
"Service does not exist!"}), HTTPStatus.BAD_REQUEST)
|
|
||||||
|
|
||||||
|
|
||||||
@twitchalerts_ext.route("/api/v1/authenticate/<service_id>", methods=["GET"])
|
@twitchalerts_ext.route("/api/v1/authenticate/<service_id>", methods=["GET"])
|
||||||
@@ -84,40 +77,32 @@ async def api_authenticate_service(service_id):
|
|||||||
If successful, an API access token will be added to the service, and
|
If successful, an API access token will be added to the service, and
|
||||||
the user will be redirected to index.html.
|
the user will be redirected to index.html.
|
||||||
"""
|
"""
|
||||||
code = request.args.get('code')
|
code = request.args.get("code")
|
||||||
state = request.args.get('state')
|
state = request.args.get("state")
|
||||||
service = await get_service(service_id)
|
service = await get_service(service_id)
|
||||||
if service.state != state:
|
if service.state != state:
|
||||||
return (jsonify({"message":
|
return (jsonify({"message": "State doesn't match!"}), HTTPStatus.BAD_Request)
|
||||||
"State doesn't match!"}), HTTPStatus.BAD_Request)
|
|
||||||
redirect_uri = request.scheme + "://" + request.headers["Host"]
|
redirect_uri = request.scheme + "://" + request.headers["Host"]
|
||||||
redirect_uri += f"/twitchalerts/api/v1/authenticate/{service_id}"
|
redirect_uri += f"/twitchalerts/api/v1/authenticate/{service_id}"
|
||||||
url, success = await authenticate_service(service_id, code, redirect_uri)
|
url, success = await authenticate_service(service_id, code, redirect_uri)
|
||||||
if success:
|
if success:
|
||||||
return redirect(url)
|
return redirect(url)
|
||||||
else:
|
else:
|
||||||
return (jsonify({"message": "Service already authenticated!"}),
|
return (
|
||||||
HTTPStatus.BAD_REQUEST)
|
jsonify({"message": "Service already authenticated!"}),
|
||||||
|
HTTPStatus.BAD_REQUEST,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@twitchalerts_ext.route("/api/v1/donations", methods=["POST"])
|
@twitchalerts_ext.route("/api/v1/donations", methods=["POST"])
|
||||||
@api_validate_post_request(
|
@api_validate_post_request(
|
||||||
schema={
|
schema={
|
||||||
"name": {
|
"name": {"type": "string"},
|
||||||
"type": "string"
|
"sats": {"type": "integer", "required": True},
|
||||||
},
|
"service": {"type": "integer", "required": True},
|
||||||
"sats": {
|
"message": {"type": "string"},
|
||||||
"type": "integer",
|
}
|
||||||
"required": True
|
)
|
||||||
},
|
|
||||||
"service": {
|
|
||||||
"type": "integer",
|
|
||||||
"required": True
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
async def api_create_donation():
|
async def api_create_donation():
|
||||||
"""Take data from donation form and return satspay charge"""
|
"""Take data from donation form and return satspay charge"""
|
||||||
# Currency is hardcoded while frotnend is limited
|
# Currency is hardcoded while frotnend is limited
|
||||||
@@ -126,7 +111,7 @@ async def api_create_donation():
|
|||||||
message = g.data.get("message", "")
|
message = g.data.get("message", "")
|
||||||
# Fiat amount is calculated here while frontend is limited
|
# Fiat amount is calculated here while frontend is limited
|
||||||
price = await btc_price(cur_code)
|
price = await btc_price(cur_code)
|
||||||
amount = sats * (10**(-8)) * price
|
amount = sats * (10 ** (-8)) * price
|
||||||
webhook_base = request.scheme + "://" + request.headers["Host"]
|
webhook_base = request.scheme + "://" + request.headers["Host"]
|
||||||
service_id = g.data["service"]
|
service_id = g.data["service"]
|
||||||
service = await get_service(service_id)
|
service = await get_service(service_id)
|
||||||
@@ -139,7 +124,8 @@ async def api_create_donation():
|
|||||||
completelinktext="Back to Stream!",
|
completelinktext="Back to Stream!",
|
||||||
webhook=webhook_base + "/twitchalerts/api/v1/postdonation",
|
webhook=webhook_base + "/twitchalerts/api/v1/postdonation",
|
||||||
description=description,
|
description=description,
|
||||||
**charge_details)
|
**charge_details,
|
||||||
|
)
|
||||||
await create_donation(
|
await create_donation(
|
||||||
id=charge.id,
|
id=charge.id,
|
||||||
wallet=service.wallet,
|
wallet=service.wallet,
|
||||||
@@ -154,12 +140,11 @@ async def api_create_donation():
|
|||||||
|
|
||||||
|
|
||||||
@twitchalerts_ext.route("/api/v1/postdonation", methods=["POST"])
|
@twitchalerts_ext.route("/api/v1/postdonation", methods=["POST"])
|
||||||
@api_validate_post_request(schema={
|
@api_validate_post_request(
|
||||||
"id": {
|
schema={
|
||||||
"type": "string",
|
"id": {"type": "string", "required": True},
|
||||||
"required": True
|
}
|
||||||
},
|
)
|
||||||
})
|
|
||||||
async def api_post_donation():
|
async def api_post_donation():
|
||||||
"""Post a paid donation to Stremalabs/StreamElements.
|
"""Post a paid donation to Stremalabs/StreamElements.
|
||||||
|
|
||||||
@@ -170,8 +155,7 @@ async def api_post_donation():
|
|||||||
if charge and charge.paid:
|
if charge and charge.paid:
|
||||||
return await post_donation(donation_id)
|
return await post_donation(donation_id)
|
||||||
else:
|
else:
|
||||||
return (jsonify({"message":
|
return (jsonify({"message": "Not a paid charge!"}), HTTPStatus.BAD_REQUEST)
|
||||||
"Not a paid charge!"}), HTTPStatus.BAD_REQUEST)
|
|
||||||
|
|
||||||
|
|
||||||
@twitchalerts_ext.route("/api/v1/services", methods=["GET"])
|
@twitchalerts_ext.route("/api/v1/services", methods=["GET"])
|
||||||
@@ -184,8 +168,7 @@ async def api_get_services():
|
|||||||
new_services = await get_services(wallet_id)
|
new_services = await get_services(wallet_id)
|
||||||
services += new_services if new_services else []
|
services += new_services if new_services else []
|
||||||
return (
|
return (
|
||||||
jsonify([service._asdict()
|
jsonify([service._asdict() for service in services] if services else []),
|
||||||
for service in services] if services else []),
|
|
||||||
HTTPStatus.OK,
|
HTTPStatus.OK,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -202,8 +185,7 @@ async def api_get_donations():
|
|||||||
new_donations = await get_donations(wallet_id)
|
new_donations = await get_donations(wallet_id)
|
||||||
donations += new_donations if new_donations else []
|
donations += new_donations if new_donations else []
|
||||||
return (
|
return (
|
||||||
jsonify([donation._asdict()
|
jsonify([donation._asdict() for donation in donations] if donations else []),
|
||||||
for donation in donations] if donations else []),
|
|
||||||
HTTPStatus.OK,
|
HTTPStatus.OK,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -216,17 +198,20 @@ async def api_update_donation(donation_id=None):
|
|||||||
donation = await get_donation(donation_id)
|
donation = await get_donation(donation_id)
|
||||||
|
|
||||||
if not donation:
|
if not donation:
|
||||||
return (jsonify({"message": "Donation does not exist."}),
|
return (
|
||||||
HTTPStatus.NOT_FOUND)
|
jsonify({"message": "Donation does not exist."}),
|
||||||
|
HTTPStatus.NOT_FOUND,
|
||||||
|
)
|
||||||
|
|
||||||
if donation.wallet != g.wallet.id:
|
if donation.wallet != g.wallet.id:
|
||||||
return (jsonify({"message":
|
return (jsonify({"message": "Not your donation."}), HTTPStatus.FORBIDDEN)
|
||||||
"Not your donation."}), HTTPStatus.FORBIDDEN)
|
|
||||||
|
|
||||||
donation = await update_donation(donation_id, **g.data)
|
donation = await update_donation(donation_id, **g.data)
|
||||||
else:
|
else:
|
||||||
return (jsonify({"message":
|
return (
|
||||||
"No donation ID specified"}), HTTPStatus.BAD_REQUEST)
|
jsonify({"message": "No donation ID specified"}),
|
||||||
|
HTTPStatus.BAD_REQUEST,
|
||||||
|
)
|
||||||
return jsonify(donation._asdict()), HTTPStatus.CREATED
|
return jsonify(donation._asdict()), HTTPStatus.CREATED
|
||||||
|
|
||||||
|
|
||||||
@@ -238,17 +223,17 @@ async def api_update_service(service_id=None):
|
|||||||
service = await get_service(service_id)
|
service = await get_service(service_id)
|
||||||
|
|
||||||
if not service:
|
if not service:
|
||||||
return (jsonify({"message":
|
return (
|
||||||
"Service does not exist."}), HTTPStatus.NOT_FOUND)
|
jsonify({"message": "Service does not exist."}),
|
||||||
|
HTTPStatus.NOT_FOUND,
|
||||||
|
)
|
||||||
|
|
||||||
if service.wallet != g.wallet.id:
|
if service.wallet != g.wallet.id:
|
||||||
return (jsonify({"message":
|
return (jsonify({"message": "Not your service."}), HTTPStatus.FORBIDDEN)
|
||||||
"Not your service."}), HTTPStatus.FORBIDDEN)
|
|
||||||
|
|
||||||
service = await update_service(service_id, **g.data)
|
service = await update_service(service_id, **g.data)
|
||||||
else:
|
else:
|
||||||
return (jsonify({"message":
|
return (jsonify({"message": "No service ID specified"}), HTTPStatus.BAD_REQUEST)
|
||||||
"No service ID specified"}), HTTPStatus.BAD_REQUEST)
|
|
||||||
return jsonify(service._asdict()), HTTPStatus.CREATED
|
return jsonify(service._asdict()), HTTPStatus.CREATED
|
||||||
|
|
||||||
|
|
||||||
@@ -258,11 +243,12 @@ async def api_delete_donation(donation_id):
|
|||||||
"""Delete the donation with the given donation_id"""
|
"""Delete the donation with the given donation_id"""
|
||||||
donation = await get_donation(donation_id)
|
donation = await get_donation(donation_id)
|
||||||
if not donation:
|
if not donation:
|
||||||
return (jsonify({"message":
|
return (jsonify({"message": "No donation with this ID!"}), HTTPStatus.NOT_FOUND)
|
||||||
"No donation with this ID!"}), HTTPStatus.NOT_FOUND)
|
|
||||||
if donation.wallet != g.wallet.id:
|
if donation.wallet != g.wallet.id:
|
||||||
return (jsonify({"message": "Not authorized to delete this donation!"
|
return (
|
||||||
}), HTTPStatus.FORBIDDEN)
|
jsonify({"message": "Not authorized to delete this donation!"}),
|
||||||
|
HTTPStatus.FORBIDDEN,
|
||||||
|
)
|
||||||
await delete_donation(donation_id)
|
await delete_donation(donation_id)
|
||||||
|
|
||||||
return "", HTTPStatus.NO_CONTENT
|
return "", HTTPStatus.NO_CONTENT
|
||||||
@@ -274,11 +260,12 @@ async def api_delete_service(service_id):
|
|||||||
"""Delete the service with the given service_id"""
|
"""Delete the service with the given service_id"""
|
||||||
service = await get_service(service_id)
|
service = await get_service(service_id)
|
||||||
if not service:
|
if not service:
|
||||||
return (jsonify({"message":
|
return (jsonify({"message": "No service with this ID!"}), HTTPStatus.NOT_FOUND)
|
||||||
"No service with this ID!"}), HTTPStatus.NOT_FOUND)
|
|
||||||
if service.wallet != g.wallet.id:
|
if service.wallet != g.wallet.id:
|
||||||
return (jsonify({"message": "Not authorized to delete this service!"}),
|
return (
|
||||||
HTTPStatus.FORBIDDEN)
|
jsonify({"message": "Not authorized to delete this service!"}),
|
||||||
|
HTTPStatus.FORBIDDEN,
|
||||||
|
)
|
||||||
await delete_service(service_id)
|
await delete_service(service_id)
|
||||||
|
|
||||||
return "", HTTPStatus.NO_CONTENT
|
return "", HTTPStatus.NO_CONTENT
|
||||||
|
Reference in New Issue
Block a user