mirror of
https://github.com/believethehype/nostrdvm.git
synced 2025-09-27 21:36:30 +02:00
fixes
This commit is contained in:
@@ -126,7 +126,7 @@ class DVM:
|
|||||||
print("[" + self.dvm_config.NIP89.NAME + "] Checking Subscription status")
|
print("[" + self.dvm_config.NIP89.NAME + "] Checking Subscription status")
|
||||||
subscription_status = nip88_has_active_subscription(PublicKey.parse(user.npub),
|
subscription_status = nip88_has_active_subscription(PublicKey.parse(user.npub),
|
||||||
self.dvm_config.NIP88.DTAG, self.client,
|
self.dvm_config.NIP88.DTAG, self.client,
|
||||||
self.dvm_config)
|
self.dvm_config.PUBLIC_KEY)
|
||||||
|
|
||||||
if subscription_status["isActive"]:
|
if subscription_status["isActive"]:
|
||||||
print("User subscribed until: " + str(
|
print("User subscribed until: " + str(
|
||||||
@@ -317,7 +317,7 @@ class DVM:
|
|||||||
config=self.dvm_config)
|
config=self.dvm_config)
|
||||||
|
|
||||||
# a regular note
|
# a regular note
|
||||||
elif not anon:
|
elif not anon and dvm_config.NIP88 is None:
|
||||||
print("[" + self.dvm_config.NIP89.NAME + "] Profile Zap received for DVM balance: " +
|
print("[" + self.dvm_config.NIP89.NAME + "] Profile Zap received for DVM balance: " +
|
||||||
str(invoice_amount) + " Sats from " + str(user.name))
|
str(invoice_amount) + " Sats from " + str(user.name))
|
||||||
update_user_balance(self.dvm_config.DB, sender, invoice_amount, client=self.client,
|
update_user_balance(self.dvm_config.DB, sender, invoice_amount, client=self.client,
|
||||||
|
@@ -11,10 +11,12 @@ from nostr_sdk import (Keys, Client, Timestamp, Filter, nip04_decrypt, HandleNot
|
|||||||
from nostr_dvm.utils.database_utils import fetch_user_metadata
|
from nostr_dvm.utils.database_utils import fetch_user_metadata
|
||||||
from nostr_dvm.utils.definitions import EventDefinitions
|
from nostr_dvm.utils.definitions import EventDefinitions
|
||||||
from nostr_dvm.utils.dvmconfig import DVMConfig
|
from nostr_dvm.utils.dvmconfig import DVMConfig
|
||||||
|
from nostr_dvm.utils.nip88_utils import nip88_has_active_subscription
|
||||||
from nostr_dvm.utils.nip89_utils import NIP89Config
|
from nostr_dvm.utils.nip89_utils import NIP89Config
|
||||||
from nostr_dvm.utils.nwc_tools import nwc_zap
|
from nostr_dvm.utils.nwc_tools import nwc_zap
|
||||||
from nostr_dvm.utils.subscription_utils import create_subscription_sql_table, add_to_subscription_sql_table, \
|
from nostr_dvm.utils.subscription_utils import create_subscription_sql_table, add_to_subscription_sql_table, \
|
||||||
get_from_subscription__sql_table, update_subscription_sql_table
|
get_from_subscription_sql_table, update_subscription_sql_table, get_all_subscriptions_from_sql_table, \
|
||||||
|
delete_from_subscription_sql_table
|
||||||
from nostr_dvm.utils.zap_utils import create_bolt11_lud16, zaprequest
|
from nostr_dvm.utils.zap_utils import create_bolt11_lud16, zaprequest
|
||||||
|
|
||||||
|
|
||||||
@@ -95,13 +97,85 @@ class Subscription:
|
|||||||
kind7001eventid = tag.as_vec()[1]
|
kind7001eventid = tag.as_vec()[1]
|
||||||
|
|
||||||
if kind7001eventid != "":
|
if kind7001eventid != "":
|
||||||
subscription = get_from_subscription__sql_table("db/subscriptions", kind7001eventid)
|
subscription = get_from_subscription_sql_table("db/subscriptions", kind7001eventid)
|
||||||
|
|
||||||
if subscription is not None:
|
if subscription is not None:
|
||||||
update_subscription_sql_table("db/subscriptions", kind7001eventid, recipient,
|
update_subscription_sql_table("db/subscriptions", kind7001eventid, recipient,
|
||||||
subscription.subscriber, subscription.nwc, subscription.cadence,
|
subscription.subscriber, subscription.nwc, subscription.cadence,
|
||||||
subscription.amount, subscription.begin, subscription.end,
|
subscription.amount, subscription.begin, subscription.end,
|
||||||
subscription.tier_dtag, subscription.zaps, subscription.recipe, False)
|
subscription.tier_dtag, subscription.zaps, subscription.recipe,
|
||||||
|
False, Timestamp.now().as_secs())
|
||||||
|
|
||||||
|
def infer_subscription_end_time(start, cadence):
|
||||||
|
end = start
|
||||||
|
if cadence == "daily":
|
||||||
|
end = start + 60 * 60 * 24
|
||||||
|
elif cadence == "weekly":
|
||||||
|
end = start + 60 * 60 * 24 * 7
|
||||||
|
elif cadence == "monthly":
|
||||||
|
# TODO check days of month -.-
|
||||||
|
end = start + 60 * 60 * 24 * 31
|
||||||
|
elif cadence == "yearly":
|
||||||
|
# TODO check extra day every 4 years
|
||||||
|
end = start + 60 * 60 * 24 * 356
|
||||||
|
return end
|
||||||
|
|
||||||
|
def pay_zap_split(nwc, overall_amount, zaps):
|
||||||
|
overallsplit = 0
|
||||||
|
|
||||||
|
for zap in zaps:
|
||||||
|
overallsplit += int(zap['split'])
|
||||||
|
|
||||||
|
zapped_amount = 0
|
||||||
|
for zap in zaps:
|
||||||
|
name, nip05, lud16 = fetch_user_metadata(zap['key'], self.client)
|
||||||
|
splitted_amount = math.floor(
|
||||||
|
(int(zap['split']) / overallsplit) * int(overall_amount) / 1000)
|
||||||
|
# invoice = create_bolt11_lud16(lud16, splitted_amount)
|
||||||
|
# TODO add details about DVM in message
|
||||||
|
invoice = zaprequest(lud16, splitted_amount, "DVM subscription", None,
|
||||||
|
PublicKey.parse(zap['key']), self.keys, DVMConfig.RELAY_LIST)
|
||||||
|
print(invoice)
|
||||||
|
if invoice is not None:
|
||||||
|
nwc_event_id = nwc_zap(nwc, invoice, self.keys, zap['relay'])
|
||||||
|
if nwc_event_id is None:
|
||||||
|
print("error zapping " + lud16)
|
||||||
|
else:
|
||||||
|
zapped_amount = zapped_amount + (splitted_amount * 1000)
|
||||||
|
print(str(zapped_amount) + "/" + str(overall_amount))
|
||||||
|
|
||||||
|
if zapped_amount < overall_amount * 0.8: # TODO how do we handle failed zaps for some addresses? we are ok with 80% for now
|
||||||
|
success = False
|
||||||
|
else:
|
||||||
|
print("Zapped successfully")
|
||||||
|
success = True
|
||||||
|
# if no active subscription exists OR the subscription ended, pay
|
||||||
|
|
||||||
|
return success
|
||||||
|
|
||||||
|
def make_subscription_zap_recipe(event7001, recipient, subscriber, start, end, tier_dtag):
|
||||||
|
message = "payed by subscription service"
|
||||||
|
pTag = Tag.parse(["p", recipient])
|
||||||
|
PTag = Tag.parse(["P", subscriber])
|
||||||
|
eTag = Tag.parse(["e", event7001])
|
||||||
|
validTag = Tag.parse(["valid", str(start), str(end)])
|
||||||
|
tierTag = Tag.parse(["tier", tier_dtag])
|
||||||
|
alttag = Tag.parse(["alt", "This is a NIP90 DVM Subscription Payment Recipe"])
|
||||||
|
|
||||||
|
tags = [pTag, PTag, eTag, validTag, tierTag, alttag]
|
||||||
|
|
||||||
|
event = EventBuilder(EventDefinitions.KIND_NIP88_PAYMENT_RECIPE,
|
||||||
|
message, tags).to_event(self.keys)
|
||||||
|
|
||||||
|
dvmconfig = DVMConfig()
|
||||||
|
signer = NostrSigner.keys(self.keys)
|
||||||
|
client = Client(signer)
|
||||||
|
for relay in dvmconfig.RELAY_LIST:
|
||||||
|
client.add_relay(relay)
|
||||||
|
client.connect()
|
||||||
|
recipeid = client.send_event(event)
|
||||||
|
recipe = recipeid.to_hex()
|
||||||
|
return recipe
|
||||||
|
|
||||||
def handle_dm(nostr_event):
|
def handle_dm(nostr_event):
|
||||||
|
|
||||||
@@ -123,105 +197,59 @@ class Subscription:
|
|||||||
tier_dtag = jsonevent['tier_dtag']
|
tier_dtag = jsonevent['tier_dtag']
|
||||||
|
|
||||||
start = Timestamp.now().as_secs()
|
start = Timestamp.now().as_secs()
|
||||||
end = Timestamp.now().as_secs()
|
|
||||||
|
|
||||||
isactivesubscription = False
|
isactivesubscription = False
|
||||||
recipe = ""
|
recipe = ""
|
||||||
|
|
||||||
subscription = get_from_subscription__sql_table("db/subscriptions", event7001)
|
subscription = get_from_subscription_sql_table("db/subscriptions", event7001)
|
||||||
if subscription is not None and subscription.end > start:
|
#if subscription is not None and subscription.end > start:
|
||||||
start = subscription.end
|
# start = subscription.end
|
||||||
isactivesubscription = True
|
# isactivesubscription = True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if cadence == "daily":
|
|
||||||
end = start + 60 * 60 * 24
|
|
||||||
elif cadence == "weekly":
|
|
||||||
end = start + 60 * 60 * 24 * 7
|
|
||||||
elif cadence == "monthly":
|
|
||||||
# TODO check days of month -.-
|
|
||||||
end = start + 60 * 60 * 24 * 31
|
|
||||||
elif cadence == "yearly":
|
|
||||||
# TODO check extra day every 4 years
|
|
||||||
end = start + 60 * 60 * 24 * 356
|
|
||||||
zapsstr = json.dumps(jsonevent['zaps'])
|
zapsstr = json.dumps(jsonevent['zaps'])
|
||||||
print(zapsstr)
|
print(zapsstr)
|
||||||
success = True
|
success = True
|
||||||
if subscription is None or subscription.end <= Timestamp.now().as_secs():
|
if subscription is None or subscription.end <= Timestamp.now().as_secs():
|
||||||
|
#rather check nostr if our db is right
|
||||||
|
subscription_status = nip88_has_active_subscription(
|
||||||
|
PublicKey.parse(subscriber),
|
||||||
|
tier_dtag, self.client, recipient)
|
||||||
|
|
||||||
overallsplit = 0
|
if not subscription_status["isActive"]:
|
||||||
|
success = pay_zap_split(nwc, overall_amount, jsonevent['zaps'])
|
||||||
|
start = Timestamp.now().as_secs()
|
||||||
|
end = infer_subscription_end_time(start, cadence)
|
||||||
|
else:
|
||||||
|
start = Timestamp.now().as_secs()
|
||||||
|
end = subscription_status["validUntil"]
|
||||||
|
else:
|
||||||
|
start = subscription.begin
|
||||||
|
end = subscription.end
|
||||||
|
|
||||||
for zap in jsonevent['zaps']:
|
|
||||||
overallsplit += int(zap['split'])
|
|
||||||
|
|
||||||
zapped_amount = 0
|
|
||||||
for zap in jsonevent['zaps']:
|
|
||||||
name, nip05, lud16 = fetch_user_metadata(zap['key'], self.client)
|
|
||||||
splitted_amount = math.floor(
|
|
||||||
(int(zap['split']) / overallsplit) * int(jsonevent['overall_amount']) / 1000)
|
|
||||||
# invoice = create_bolt11_lud16(lud16, splitted_amount)
|
|
||||||
# TODO add details about DVM in message
|
|
||||||
invoice = zaprequest(lud16, splitted_amount, "DVM subscription", None,
|
|
||||||
PublicKey.parse(zap['key']), self.keys, DVMConfig.RELAY_LIST)
|
|
||||||
print(invoice)
|
|
||||||
if invoice is not None:
|
|
||||||
nwc_event_id = nwc_zap(nwc, invoice, self.keys, zap['relay'])
|
|
||||||
if nwc_event_id is None:
|
|
||||||
print("error zapping " + lud16)
|
|
||||||
else:
|
|
||||||
zapped_amount = zapped_amount + (splitted_amount * 1000)
|
|
||||||
print(str(zapped_amount) + "/" + str(overall_amount))
|
|
||||||
|
|
||||||
if zapped_amount < overall_amount * 0.8: # TODO how do we handle failed zaps for some addresses? we are ok with 80% for now
|
|
||||||
success = False
|
|
||||||
else:
|
|
||||||
print("Zapped successfully")
|
|
||||||
# if no active subscription exists OR the subscription ended, pay
|
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
message = "payed by subscription service"
|
recipe = make_subscription_zap_recipe(event7001, recipient, subscriber, start, end, tier_dtag)
|
||||||
pTag = Tag.parse(["p", recipient])
|
|
||||||
PTag = Tag.parse(["P", subscriber])
|
|
||||||
eTag = Tag.parse(["e", event7001])
|
|
||||||
validTag = Tag.parse(["valid", str(start), str(end)])
|
|
||||||
tierTag = Tag.parse(["tier", tier_dtag])
|
|
||||||
alttag = Tag.parse(["alt", "This is a NIP90 DVM Subscription Payment Recipe"])
|
|
||||||
|
|
||||||
tags = [pTag, PTag, eTag, validTag, tierTag, alttag]
|
|
||||||
|
|
||||||
event = EventBuilder(EventDefinitions.KIND_NIP88_PAYMENT_RECIPE,
|
|
||||||
message, tags).to_event(self.keys)
|
|
||||||
|
|
||||||
dvmconfig = DVMConfig()
|
|
||||||
signer = NostrSigner.keys(self.keys)
|
|
||||||
client = Client(signer)
|
|
||||||
for relay in dvmconfig.RELAY_LIST:
|
|
||||||
client.add_relay(relay)
|
|
||||||
client.connect()
|
|
||||||
recipeid = client.send_event(event)
|
|
||||||
recipe = recipeid.to_hex()
|
|
||||||
print("RECIPE " + recipe)
|
print("RECIPE " + recipe)
|
||||||
isactivesubscription = True
|
isactivesubscription = True
|
||||||
|
|
||||||
if subscription is None:
|
if subscription is None:
|
||||||
add_to_subscription_sql_table("db/subscriptions", event7001, recipient, subscriber, nwc,
|
add_to_subscription_sql_table("db/subscriptions", event7001, recipient, subscriber, nwc,
|
||||||
cadence, overall_amount, start, end, tier_dtag,
|
cadence, overall_amount, start, end, tier_dtag,
|
||||||
zapsstr, recipe, isactivesubscription)
|
zapsstr, recipe, isactivesubscription, Timestamp.now().as_secs())
|
||||||
print("new subscription entry")
|
print("new subscription entry")
|
||||||
else:
|
else:
|
||||||
update_subscription_sql_table("db/subscriptions", event7001, recipient, subscriber, nwc,
|
update_subscription_sql_table("db/subscriptions", event7001, recipient, subscriber, nwc,
|
||||||
cadence, overall_amount, start, end,
|
cadence, overall_amount, start, end,
|
||||||
tier_dtag, zapsstr, recipe, isactivesubscription)
|
tier_dtag, zapsstr, recipe, isactivesubscription,
|
||||||
|
Timestamp.now().as_secs())
|
||||||
print("updated subscription entry")
|
print("updated subscription entry")
|
||||||
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Error in Subscriber " + str(e))
|
print("Error in Subscriber " + str(e))
|
||||||
|
|
||||||
@@ -230,9 +258,65 @@ class Subscription:
|
|||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
time.sleep(60.0)
|
time.sleep(60.0)
|
||||||
|
subscriptions = get_all_subscriptions_from_sql_table("db/subscriptions")
|
||||||
|
print("Checking " + str(len(subscriptions)) + " entries..")
|
||||||
|
for subscription in subscriptions:
|
||||||
|
if subscription.active:
|
||||||
|
if subscription.end < Timestamp.now().as_secs():
|
||||||
|
# We could directly zap, but let's make another check if our subscription expired
|
||||||
|
subscription_status = nip88_has_active_subscription(
|
||||||
|
PublicKey.parse(subscription.subscriber),
|
||||||
|
subscription.tier_dtag, self.client, subscription.recipent)
|
||||||
|
|
||||||
|
if not subscription_status["isActive"] or subscription_status["expires"]:
|
||||||
|
update_subscription_sql_table("db/subscriptions", subscription.id,
|
||||||
|
subscription.recipent,
|
||||||
|
subscription.subscriber, subscription.nwc,
|
||||||
|
subscription.cadence, subscription.amount,
|
||||||
|
subscription.begin, subscription.end,
|
||||||
|
subscription.tier_dtag, subscription.zaps,
|
||||||
|
subscription.recipe,
|
||||||
|
False,
|
||||||
|
Timestamp.now().as_secs())
|
||||||
|
else:
|
||||||
|
zaps = json.loads(subscription.zaps)
|
||||||
|
success = pay_zap_split(subscription.nwc, subscription.amount, zaps)
|
||||||
|
if success:
|
||||||
|
end = infer_subscription_end_time(Timestamp.now().as_secs(), subscription.cadence)
|
||||||
|
recipe = make_subscription_zap_recipe(subscription.id, subscription.recipent,
|
||||||
|
subscription.subscriber, subscription.begin,
|
||||||
|
end, subscription.tier_dtag)
|
||||||
|
else:
|
||||||
|
end = Timestamp.now().as_secs()
|
||||||
|
recipe = subscription.recipe
|
||||||
|
|
||||||
|
update_subscription_sql_table("db/subscriptions", subscription.id,
|
||||||
|
subscription.recipent,
|
||||||
|
subscription.subscriber, subscription.nwc,
|
||||||
|
subscription.cadence, subscription.amount,
|
||||||
|
subscription.begin, end,
|
||||||
|
subscription.tier_dtag, subscription.zaps, recipe,
|
||||||
|
success,
|
||||||
|
Timestamp.now().as_secs())
|
||||||
|
print("updated subscription entry")
|
||||||
|
|
||||||
|
|
||||||
print("Checking Subscription")
|
else:
|
||||||
|
delete_threshold = 60 * 60 * 24 * 365
|
||||||
|
if subscription.cadence == "daily":
|
||||||
|
delete_threshold = 60 * 60 * 24 * 7 # After 7 days, delete the subscription, user can make a new one
|
||||||
|
elif subscription.cadence == "weekly":
|
||||||
|
delete_threshold = 60 * 60 * 24 * 21 # After 21 days, delete the subscription, user can make a new one
|
||||||
|
elif subscription.cadence == "monthly":
|
||||||
|
delete_threshold = 60 * 60 * 24 * 60 # After 60 days, delete the subscription, user can make a new one
|
||||||
|
elif subscription.cadence == "yearoy":
|
||||||
|
delete_threshold = 60 * 60 * 24 * 500 # After 500 days, delete the subscription, user can make a new one
|
||||||
|
|
||||||
|
if subscription.end < (Timestamp.now().as_secs() - delete_threshold):
|
||||||
|
delete_from_subscription_sql_table("db/subscriptions", subscription.id)
|
||||||
|
print("Delete expired subscription")
|
||||||
|
|
||||||
|
print(str(Timestamp.now().as_secs()) + " Checking Subscription")
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print('Stay weird!')
|
print('Stay weird!')
|
||||||
os.kill(os.getpid(), signal.SIGTERM)
|
os.kill(os.getpid(), signal.SIGTERM)
|
||||||
|
@@ -219,7 +219,7 @@ def build_example_subscription(name, identifier, admin_config):
|
|||||||
"lud16": dvm_config.LN_ADDRESS,
|
"lud16": dvm_config.LN_ADDRESS,
|
||||||
"encryptionSupported": True,
|
"encryptionSupported": True,
|
||||||
"cashuAccepted": True,
|
"cashuAccepted": True,
|
||||||
"amount": "subscription",
|
"subscription": True,
|
||||||
"nip90Params": {
|
"nip90Params": {
|
||||||
"max_results": {
|
"max_results": {
|
||||||
"required": False,
|
"required": False,
|
||||||
|
@@ -88,15 +88,16 @@ def nip88_delete_announcement(eid: str, keys: Keys, dtag: str, client: Client, c
|
|||||||
send_event(event, client, config)
|
send_event(event, client, config)
|
||||||
|
|
||||||
|
|
||||||
def nip88_has_active_subscription(user: PublicKey, tiereventdtag, client: Client, dvm_config):
|
def nip88_has_active_subscription(user: PublicKey, tiereventdtag, client: Client, receiver_public_key_hex):
|
||||||
subscription_status = {
|
subscription_status = {
|
||||||
"isActive": False,
|
"isActive": False,
|
||||||
"validUntil": 0,
|
"validUntil": 0,
|
||||||
"subscriptionId": "",
|
"subscriptionId": "",
|
||||||
|
"expires": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
subscriptionfilter = Filter().kind(definitions.EventDefinitions.KIND_NIP88_PAYMENT_RECIPE).pubkey(
|
subscriptionfilter = Filter().kind(definitions.EventDefinitions.KIND_NIP88_PAYMENT_RECIPE).pubkey(
|
||||||
PublicKey.parse(dvm_config.PUBLIC_KEY)).custom_tag(SingleLetterTag.uppercase(Alphabet.P),
|
PublicKey.parse(receiver_public_key_hex)).custom_tag(SingleLetterTag.uppercase(Alphabet.P),
|
||||||
[user.to_hex()]).limit(1)
|
[user.to_hex()]).limit(1)
|
||||||
evts = client.get_events_of([subscriptionfilter], timedelta(seconds=5))
|
evts = client.get_events_of([subscriptionfilter], timedelta(seconds=5))
|
||||||
if len(evts) > 0:
|
if len(evts) > 0:
|
||||||
@@ -114,6 +115,17 @@ def nip88_has_active_subscription(user: PublicKey, tiereventdtag, client: Client
|
|||||||
if subscription_status["validUntil"] > Timestamp.now().as_secs() & matchesdtag:
|
if subscription_status["validUntil"] > Timestamp.now().as_secs() & matchesdtag:
|
||||||
subscription_status["isActive"] = True
|
subscription_status["isActive"] = True
|
||||||
|
|
||||||
|
if subscription_status["isActive"]:
|
||||||
|
cancel_filter = Filter().kind(EventDefinitions.KIND_NIP88_STOP_SUBSCRIPTION_EVENT).author(
|
||||||
|
user).pubkey(PublicKey.parse(receiver_public_key_hex)).event(EventId.parse(subscription_status["subscriptionId"])).limit(1)
|
||||||
|
cancel_events = client.get_events_of([cancel_filter], timedelta(seconds=5))
|
||||||
|
if len(cancel_events) > 0:
|
||||||
|
if cancel_events[0].created_at().as_secs() > evts[0].created_at().as_secs():
|
||||||
|
subscription_status["expires"] = True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return subscription_status
|
return subscription_status
|
||||||
|
|
||||||
|
|
||||||
|
@@ -17,6 +17,7 @@ class Subscription:
|
|||||||
zaps: str
|
zaps: str
|
||||||
recipe: str
|
recipe: str
|
||||||
active: bool
|
active: bool
|
||||||
|
lastupdate: int
|
||||||
|
|
||||||
|
|
||||||
def create_subscription_sql_table(db):
|
def create_subscription_sql_table(db):
|
||||||
@@ -40,7 +41,8 @@ def create_subscription_sql_table(db):
|
|||||||
tier_dtag text,
|
tier_dtag text,
|
||||||
zaps text,
|
zaps text,
|
||||||
recipe text,
|
recipe text,
|
||||||
active boolean
|
active boolean,
|
||||||
|
lastupdate int
|
||||||
|
|
||||||
|
|
||||||
); """)
|
); """)
|
||||||
@@ -52,23 +54,23 @@ def create_subscription_sql_table(db):
|
|||||||
|
|
||||||
|
|
||||||
def add_to_subscription_sql_table(db, id, recipient, subscriber, nwc, cadence, amount, begin, end, tier_dtag, zaps,
|
def add_to_subscription_sql_table(db, id, recipient, subscriber, nwc, cadence, amount, begin, end, tier_dtag, zaps,
|
||||||
recipe, active):
|
recipe, active, lastupdate):
|
||||||
try:
|
try:
|
||||||
con = sqlite3.connect(db)
|
con = sqlite3.connect(db)
|
||||||
cur = con.cursor()
|
cur = con.cursor()
|
||||||
data = (id, recipient, subscriber, nwc, cadence, amount, begin, end, tier_dtag, zaps, recipe, active)
|
data = (id, recipient, subscriber, nwc, cadence, amount, begin, end, tier_dtag, zaps, recipe, active, lastupdate)
|
||||||
print(id)
|
print(id)
|
||||||
print(recipient)
|
print(recipient)
|
||||||
print(subscriber)
|
print(subscriber)
|
||||||
print(nwc)
|
print(nwc)
|
||||||
cur.execute("INSERT or IGNORE INTO subscriptions VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", data)
|
cur.execute("INSERT or IGNORE INTO subscriptions VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", data)
|
||||||
con.commit()
|
con.commit()
|
||||||
con.close()
|
con.close()
|
||||||
except Error as e:
|
except Error as e:
|
||||||
print("Error when Adding to DB: " + str(e))
|
print("Error when Adding to DB: " + str(e))
|
||||||
|
|
||||||
|
|
||||||
def get_from_subscription__sql_table(db, id):
|
def get_from_subscription_sql_table(db, id):
|
||||||
try:
|
try:
|
||||||
con = sqlite3.connect(db)
|
con = sqlite3.connect(db)
|
||||||
cur = con.cursor()
|
cur = con.cursor()
|
||||||
@@ -91,6 +93,7 @@ def get_from_subscription__sql_table(db, id):
|
|||||||
subscription.zaps = row[9]
|
subscription.zaps = row[9]
|
||||||
subscription.recipe = row[10]
|
subscription.recipe = row[10]
|
||||||
subscription.active = row[11]
|
subscription.active = row[11]
|
||||||
|
subscription.lastupdate = row[12]
|
||||||
|
|
||||||
return subscription
|
return subscription
|
||||||
|
|
||||||
@@ -99,12 +102,59 @@ def get_from_subscription__sql_table(db, id):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def update_subscription_sql_table(db, id, recipient, subscriber, nwc, cadence, amount, begin, end, tier_dtag, zaps,
|
def get_all_subscriptions_from_sql_table(db):
|
||||||
recipe, active):
|
try:
|
||||||
|
con = sqlite3.connect(db)
|
||||||
|
cursor = con.cursor()
|
||||||
|
|
||||||
|
sqlite_select_query = """SELECT * from subscriptions"""
|
||||||
|
cursor.execute(sqlite_select_query)
|
||||||
|
records = cursor.fetchall()
|
||||||
|
subscriptions = []
|
||||||
|
for row in records:
|
||||||
|
subscription = Subscription
|
||||||
|
subscription.id = row[0]
|
||||||
|
subscription.recipent = row[1]
|
||||||
|
subscription.subscriber = row[2]
|
||||||
|
subscription.nwc = row[3]
|
||||||
|
subscription.cadence = row[4]
|
||||||
|
subscription.amount = row[5]
|
||||||
|
subscription.begin = row[6]
|
||||||
|
subscription.end = row[7]
|
||||||
|
subscription.tier_dtag = row[8]
|
||||||
|
subscription.zaps = row[9]
|
||||||
|
subscription.recipe = row[10]
|
||||||
|
subscription.active = row[11]
|
||||||
|
subscription.lastupdate = row[12]
|
||||||
|
subscriptions.append(subscription)
|
||||||
|
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
return subscriptions
|
||||||
|
|
||||||
|
except sqlite3.Error as error:
|
||||||
|
print("Failed to read data from sqlite table", error)
|
||||||
|
finally:
|
||||||
|
if con:
|
||||||
|
con.close()
|
||||||
|
#print("The SQLite connection is closed")
|
||||||
|
|
||||||
|
def delete_from_subscription_sql_table(db, id):
|
||||||
try:
|
try:
|
||||||
con = sqlite3.connect(db)
|
con = sqlite3.connect(db)
|
||||||
cur = con.cursor()
|
cur = con.cursor()
|
||||||
data = (recipient, subscriber, nwc, cadence, amount, begin, end, tier_dtag, zaps, recipe, active, id)
|
cur.execute("DELETE FROM subscriptions WHERE id=?", (id,))
|
||||||
|
con.commit()
|
||||||
|
con.close()
|
||||||
|
except Error as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
def update_subscription_sql_table(db, id, recipient, subscriber, nwc, cadence, amount, begin, end, tier_dtag, zaps,
|
||||||
|
recipe, active, lastupdate):
|
||||||
|
try:
|
||||||
|
con = sqlite3.connect(db)
|
||||||
|
cur = con.cursor()
|
||||||
|
data = (recipient, subscriber, nwc, cadence, amount, begin, end, tier_dtag, zaps, recipe, active, lastupdate, id)
|
||||||
|
|
||||||
cur.execute(""" UPDATE subscriptions
|
cur.execute(""" UPDATE subscriptions
|
||||||
SET recipient = ? ,
|
SET recipient = ? ,
|
||||||
@@ -117,7 +167,8 @@ def update_subscription_sql_table(db, id, recipient, subscriber, nwc, cadence, a
|
|||||||
tier_dtag = ?,
|
tier_dtag = ?,
|
||||||
zaps = ?,
|
zaps = ?,
|
||||||
recipe = ?,
|
recipe = ?,
|
||||||
active = ?
|
active = ?,
|
||||||
|
lastupdate = ?
|
||||||
|
|
||||||
WHERE id = ?""", data)
|
WHERE id = ?""", data)
|
||||||
con.commit()
|
con.commit()
|
||||||
|
@@ -757,7 +757,7 @@ export default {
|
|||||||
if(!jsonentry.amount){
|
if(!jsonentry.amount){
|
||||||
jsonentry.amount = ""
|
jsonentry.amount = ""
|
||||||
}
|
}
|
||||||
if(jsonentry.amount === "subscription"){
|
if(jsonentry.subscription === true){
|
||||||
// if(susbcrition_tier) {
|
// if(susbcrition_tier) {
|
||||||
const filter = new Filter().kind(37001).author(entry.author)
|
const filter = new Filter().kind(37001).author(entry.author)
|
||||||
let tiers = await client.getEventsOf([filter], Duration.fromSecs(5))
|
let tiers = await client.getEventsOf([filter], Duration.fromSecs(5))
|
||||||
|
@@ -90,8 +90,8 @@
|
|||||||
<div style="margin-left: auto; margin-right: 10px;">
|
<div style="margin-left: auto; margin-right: 10px;">
|
||||||
<p v-if="dvm.amount.toString().toLowerCase()==='free'" class="badge bg-nostr">Free</p>
|
<p v-if="dvm.amount.toString().toLowerCase()==='free'" class="badge bg-nostr">Free</p>
|
||||||
<p v-if="dvm.amount.toString().toLowerCase()==='flexible'" class="badge bg-nostr2" >Flexible</p>
|
<p v-if="dvm.amount.toString().toLowerCase()==='flexible'" class="badge bg-nostr2" >Flexible</p>
|
||||||
|
<p v-if="dvm.subscription" class="badge text-white bg-gradient-to-br from-pink-500 to-orange-400">Subscription</p>
|
||||||
|
|
||||||
<p v-if="dvm.amount.toString().toLowerCase()==='subscription'" class="badge bg-orange-500">Subscription</p>
|
|
||||||
<p v-if="dvm.amount.toString()===''" ></p>
|
<p v-if="dvm.amount.toString()===''" ></p>
|
||||||
<p v-if="!isNaN(parseInt(dvm.amount))" class="text-sm text-gray-600 rounded" ><div class="flex"><svg style="margin-top:3px" xmlns="http://www.w3.org/2000/svg" width="14" height="16" fill="currentColor" class="bi bi-lightning" viewBox="0 0 16 20">
|
<p v-if="!isNaN(parseInt(dvm.amount))" class="text-sm text-gray-600 rounded" ><div class="flex"><svg style="margin-top:3px" xmlns="http://www.w3.org/2000/svg" width="14" height="16" fill="currentColor" class="bi bi-lightning" viewBox="0 0 16 20">
|
||||||
<path d="M5.52.359A.5.5 0 0 1 6 0h4a.5.5 0 0 1 .474.658L8.694 6H12.5a.5.5 0 0 1 .395.807l-7 9a.5.5 0 0 1-.873-.454L6.823 9.5H3.5a.5.5 0 0 1-.48-.641zM6.374 1 4.168 8.5H7.5a.5.5 0 0 1 .478.647L6.78 13.04 11.478 7H8a.5.5 0 0 1-.474-.658L9.306 1z"/></svg> {{dvm.amount/1000}}</div></p>
|
<path d="M5.52.359A.5.5 0 0 1 6 0h4a.5.5 0 0 1 .474.658L8.694 6H12.5a.5.5 0 0 1 .395.807l-7 9a.5.5 0 0 1-.873-.454L6.823 9.5H3.5a.5.5 0 0 1-.48-.641zM6.374 1 4.168 8.5H7.5a.5.5 0 0 1 .478.647L6.78 13.04 11.478 7H8a.5.5 0 0 1-.474-.658L9.306 1z"/></svg> {{dvm.amount/1000}}</div></p>
|
||||||
|
@@ -60,6 +60,9 @@ function set_subscription_props(amount, cadence, dvm) {
|
|||||||
this.current_subscription_amount = amount
|
this.current_subscription_amount = amount
|
||||||
this.current_subscription_cadence = cadence
|
this.current_subscription_cadence = cadence
|
||||||
this.current_subscription_dvm = dvm
|
this.current_subscription_dvm = dvm
|
||||||
|
this.nwcalby = ""
|
||||||
|
this.nwcmutiny = ""
|
||||||
|
this.nwc = ""
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -905,7 +908,18 @@ const closeNWCModal = () => {
|
|||||||
|
|
||||||
|
|
||||||
<button v-if="dvm.status !== 'finished' && dvm.status !== 'paid' && dvm.status !== 'payment-required' && dvm.status !== 'subscription-required' && dvm.status !== 'subscription-success' && dvm.status !== 'error' && dvm.status !== 'announced'" className="btn">{{dvm.status}}</button>
|
<button v-if="dvm.status !== 'finished' && dvm.status !== 'paid' && dvm.status !== 'payment-required' && dvm.status !== 'subscription-required' && dvm.status !== 'subscription-success' && dvm.status !== 'error' && dvm.status !== 'announced'" className="btn">{{dvm.status}}</button>
|
||||||
<button v-if="dvm.status === 'finished'" @click="generate_feed(dvm.id)" className="request-Button">Done, again?</button>
|
<button v-if="dvm.status === 'finished' && !dvm.nip88 ||(dvm.nip88 && !dvm.nip88.hasActiveSubscription)" @click="generate_feed(dvm.id)" class="relative inline-flex items-center justify-center p-0.5 mb-2 me-2 overflow-hidden text-sm font-medium text-gray-900 rounded-lg group bg-gradient-to-br from-purple-600 to-blue-500 group-hover:from-purple-600 group-hover:to-blue-500 hover:text-white dark:text-white focus:ring-4 focus:outline-none focus:ring-blue-300 dark:focus:ring-blue-800">
|
||||||
|
<span class="relative px-5 py-2.5 transition-all ease-in duration-75 bg-white dark:bg-gray-900 rounded-md group-hover:bg-opacity-0">
|
||||||
|
Done, again?
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button v-if="dvm.status === 'finished' && dvm.nip88 && dvm.nip88.hasActiveSubscription" @click="generate_feed(dvm.id);" class="relative inline-flex items-center justify-center p-0.5 mb-2 me-2 overflow-hidden text-sm font-medium text-gray-900 rounded-lg group bg-gradient-to-br from-pink-500 to-orange-400 group-hover:from-pink-500 group-hover:to-orange-400 hover:text-white dark:text-white focus:ring-4 focus:outline-none focus:ring-pink-200 dark:focus:ring-pink-800">
|
||||||
|
<span class="relative px-5 py-2.5 transition-all ease-in duration-75 bg-white dark:bg-gray-900 rounded-md group-hover:bg-opacity-0">
|
||||||
|
Done, Again?
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
|
||||||
<button v-if="dvm.status === 'paid'" className="btn">Paid, waiting for DVM..</button>
|
<button v-if="dvm.status === 'paid'" className="btn">Paid, waiting for DVM..</button>
|
||||||
<button v-if="dvm.status === 'error'" className="btn">Error</button>
|
<button v-if="dvm.status === 'error'" className="btn">Error</button>
|
||||||
|
|
||||||
@@ -922,7 +936,7 @@ const closeNWCModal = () => {
|
|||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button v-if="dvm.status === 'announced' && dvm.nip88 && dvm.nip88.hasActiveSubscription" @click="generate_feed(dvm.id);"class="relative inline-flex items-center justify-center p-0.5 mb-2 me-2 overflow-hidden text-sm font-medium text-gray-900 rounded-lg group bg-gradient-to-br from-pink-500 to-orange-400 group-hover:from-pink-500 group-hover:to-orange-400 hover:text-white dark:text-white focus:ring-4 focus:outline-none focus:ring-pink-200 dark:focus:ring-pink-800">
|
<button v-if="dvm.status === 'announced' && dvm.nip88 && dvm.nip88.hasActiveSubscription" @click="generate_feed(dvm.id);" class="relative inline-flex items-center justify-center p-0.5 mb-2 me-2 overflow-hidden text-sm font-medium text-gray-900 rounded-lg group bg-gradient-to-br from-pink-500 to-orange-400 group-hover:from-pink-500 group-hover:to-orange-400 hover:text-white dark:text-white focus:ring-4 focus:outline-none focus:ring-pink-200 dark:focus:ring-pink-800">
|
||||||
<span class="relative px-5 py-2.5 transition-all ease-in duration-75 bg-white dark:bg-gray-900 rounded-md group-hover:bg-opacity-0">
|
<span class="relative px-5 py-2.5 transition-all ease-in duration-75 bg-white dark:bg-gray-900 rounded-md group-hover:bg-opacity-0">
|
||||||
Request
|
Request
|
||||||
</span>
|
</span>
|
||||||
@@ -939,8 +953,9 @@ const closeNWCModal = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="margin-left: auto; margin-right: 3px;">
|
<div style="margin-left: auto; margin-right: 3px;">
|
||||||
<p v-if="dvm.subscription ==='' && dvm.amount.toString().toLowerCase()==='free'" class="badge bg-nostr" >Free</p>
|
<p v-if="!dvm.subscription && dvm.amount.toString().toLowerCase()==='free'" class="badge bg-nostr" >Free</p>
|
||||||
<p v-if="dvm.subscription ==='' && dvm.amount.toString().toLowerCase()==='flexible'" class="badge bg-nostr2" >Flexible</p>
|
<p v-if="!dvm.subscription && dvm.amount.toString().toLowerCase()==='flexible'" class="badge bg-nostr2" >Flexible</p>
|
||||||
|
<p v-if="dvm.nip88" class="badge text-white bg-gradient-to-br from-pink-500 to-orange-400">Subscription</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -982,7 +997,7 @@ const closeNWCModal = () => {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse-content">
|
<div class="collapse-content">
|
||||||
<button style="margin-top: 20px;" @click="connect_alby_nwc()">
|
<button v-if="!nwcalby.startsWith('nostr')" style="margin-top: 20px;" @click="connect_alby_nwc()">
|
||||||
<svg width="211" height="40" viewBox="0 0 211 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="211" height="40" viewBox="0 0 211 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<rect x="0.5" width="210" height="40" rx="6" fill="url(#paint0_linear_1_148)"/>
|
<rect x="0.5" width="210" height="40" rx="6" fill="url(#paint0_linear_1_148)"/>
|
||||||
<circle cx="1.575" cy="1.575" r="1.575" transform="matrix(-1 0 0 1 22.1176 13.8575)" fill="black"/>
|
<circle cx="1.575" cy="1.575" r="1.575" transform="matrix(-1 0 0 1 22.1176 13.8575)" fill="black"/>
|
||||||
@@ -1004,6 +1019,7 @@ const closeNWCModal = () => {
|
|||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
</button>
|
</button>
|
||||||
|
<p style="margin-top: 20px;" v-if="nwcalby.startsWith('nostr')">Connected to Alby Wallet.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -1049,7 +1065,12 @@ const closeNWCModal = () => {
|
|||||||
<form method="dialog">
|
<form method="dialog">
|
||||||
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
|
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
|
||||||
<!-- if there is a button in form, it will close the modal -->
|
<!-- if there is a button in form, it will close the modal -->
|
||||||
<button class="btn" @click="store_nwc(); subscribe_to_dvm()">Subscribe</button>
|
<button @click="store_nwc(); subscribe_to_dvm()" class=" relative inline-flex items-center justify-center p-0.5 mb-2 me-2 overflow-hidden text-sm font-medium text-gray-900 rounded-lg group bg-gradient-to-br from-pink-500 to-orange-400 group-hover:from-pink-500 group-hover:to-orange-400 hover:text-white dark:text-white focus:ring-4 focus:outline-none focus:ring-pink-200 dark:focus:ring-pink-800">
|
||||||
|
<span class="relative px-5 py-2.5 transition-all ease-in duration-75 rounded-md group-hover:bg-opacity-0">
|
||||||
|
Subscribe
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -1060,7 +1081,7 @@ const closeNWCModal = () => {
|
|||||||
|
|
||||||
<dialog id="subscr" class="modal">
|
<dialog id="subscr" class="modal">
|
||||||
<div className="modal-box rounded-3xl inner shadow-lg p-6 flex flex-col items-center transition-all duration-1000 bg-gradient-to-br from-pink-500 to-orange-400 ">
|
<div className="modal-box rounded-3xl inner shadow-lg p-6 flex flex-col items-center transition-all duration-1000 bg-gradient-to-br from-pink-500 to-orange-400 ">
|
||||||
<h3 class="font-bold text-lg">Subscribe</h3>
|
<h3 class="font-bold text-lg">Manage your Subscription</h3>
|
||||||
<img style="flex: content" :src="dvm.nip88.image"></img>
|
<img style="flex: content" :src="dvm.nip88.image"></img>
|
||||||
<div class="glass" className="card-body">
|
<div class="glass" className="card-body">
|
||||||
|
|
||||||
@@ -1076,10 +1097,10 @@ const closeNWCModal = () => {
|
|||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<h3 v-if="dvm.nip88.hasActiveSubscription && !dvm.nip88.expires ">Subscription renewing at
|
<h3 v-if="dvm.nip88.hasActiveSubscription && !dvm.nip88.expires ">Subscription renewing at
|
||||||
{{Timestamp.fromSecs(parseInt(dvm.nip88.subscribedUntil)).toHumanDatetime().split("T")[0].split("-")[2].trim()}}.{{Timestamp.fromSecs(parseInt(dvm.nip88.subscribedUntil)).toHumanDatetime().split("T")[0].split("-")[1].trim()}}.{{Timestamp.fromSecs(parseInt(dvm.nip88.subscribedUntil)).toHumanDatetime().split("T")[0].split("-")[0].trim().slice(2)}} {{Timestamp.fromSecs(parseInt(dvm.nip88.subscribedUntil)).toHumanDatetime().split("T")[1].split("Z")[0].trim()}}</h3>
|
{{Timestamp.fromSecs(parseInt(dvm.nip88.subscribedUntil)).toHumanDatetime().split("T")[0].split("-")[2].trim()}}.{{Timestamp.fromSecs(parseInt(dvm.nip88.subscribedUntil)).toHumanDatetime().split("T")[0].split("-")[1].trim()}}.{{Timestamp.fromSecs(parseInt(dvm.nip88.subscribedUntil)).toHumanDatetime().split("T")[0].split("-")[0].trim().slice(2)}} {{Timestamp.fromSecs(parseInt(dvm.nip88.subscribedUntil)).toHumanDatetime().split("T")[1].split("Z")[0].trim()}} GMT</h3>
|
||||||
|
|
||||||
<h3 v-if="dvm.nip88.hasActiveSubscription && dvm.nip88.expires ">Subscription expires on
|
<h3 v-if="dvm.nip88.hasActiveSubscription && dvm.nip88.expires ">Subscription expires on
|
||||||
{{Timestamp.fromSecs(parseInt(dvm.nip88.subscribedUntil)).toHumanDatetime().split("T")[0].split("-")[2].trim()}}.{{Timestamp.fromSecs(parseInt(dvm.nip88.subscribedUntil)).toHumanDatetime().split("T")[0].split("-")[1].trim()}}.{{Timestamp.fromSecs(parseInt(dvm.nip88.subscribedUntil)).toHumanDatetime().split("T")[0].split("-")[0].trim().slice(2)}} {{Timestamp.fromSecs(parseInt(dvm.nip88.subscribedUntil)).toHumanDatetime().split("T")[1].split("Z")[0].trim()}}</h3>
|
{{Timestamp.fromSecs(parseInt(dvm.nip88.subscribedUntil)).toHumanDatetime().split("T")[0].split("-")[2].trim()}}.{{Timestamp.fromSecs(parseInt(dvm.nip88.subscribedUntil)).toHumanDatetime().split("T")[0].split("-")[1].trim()}}.{{Timestamp.fromSecs(parseInt(dvm.nip88.subscribedUntil)).toHumanDatetime().split("T")[0].split("-")[0].trim().slice(2)}} {{Timestamp.fromSecs(parseInt(dvm.nip88.subscribedUntil)).toHumanDatetime().split("T")[1].split("Z")[0].trim()}} GMT</h3>
|
||||||
<h3 v-if="dvm.nip88.hasActiveSubscription && dvm.nip88.expires"> Changed your mind? Resubscribe! The current subscription will continue with a new NWC string</h3>
|
<h3 v-if="dvm.nip88.hasActiveSubscription && dvm.nip88.expires"> Changed your mind? Resubscribe! The current subscription will continue with a new NWC string</h3>
|
||||||
<div v-if="!dvm.nip88.hasActiveSubscription || dvm.nip88.expires" v-for="amount_item in dvm.nip88.amounts">
|
<div v-if="!dvm.nip88.hasActiveSubscription || dvm.nip88.expires" v-for="amount_item in dvm.nip88.amounts">
|
||||||
<br>
|
<br>
|
||||||
|
Reference in New Issue
Block a user