This commit is contained in:
Believethehype
2024-03-18 22:50:48 +01:00
parent 3788bf8ec1
commit 7d2c3f3a36
8 changed files with 265 additions and 97 deletions

View File

@@ -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,

View File

@@ -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,46 +97,17 @@ 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 handle_dm(nostr_event):
sender = nostr_event.author().to_hex()
if sender == self.keys.public_key().to_hex():
return
try:
decrypted_text = nip04_decrypt(self.keys.secret_key(), nostr_event.author(), nostr_event.content())
try:
jsonevent = json.loads(decrypted_text)
print(jsonevent)
nwc = nip44_decrypt(self.keys.secret_key(), nostr_event.author(), jsonevent['nwc'])
event7001 = jsonevent['subscribe_event']
cadence = jsonevent['cadence']
recipient = jsonevent['recipient']
subscriber = jsonevent['subscriber']
overall_amount = int(jsonevent['overall_amount'])
tier_dtag = jsonevent['tier_dtag']
start = Timestamp.now().as_secs()
end = Timestamp.now().as_secs()
isactivesubscription = False
recipe = ""
subscription = get_from_subscription__sql_table("db/subscriptions", event7001)
if subscription is not None and subscription.end > start:
start = subscription.end
isactivesubscription = True
def infer_subscription_end_time(start, cadence):
end = start
if cadence == "daily": if cadence == "daily":
end = start + 60 * 60 * 24 end = start + 60 * 60 * 24
elif cadence == "weekly": elif cadence == "weekly":
@@ -145,21 +118,19 @@ class Subscription:
elif cadence == "yearly": elif cadence == "yearly":
# TODO check extra day every 4 years # TODO check extra day every 4 years
end = start + 60 * 60 * 24 * 356 end = start + 60 * 60 * 24 * 356
zapsstr = json.dumps(jsonevent['zaps']) return end
print(zapsstr)
success = True
if subscription is None or subscription.end <= Timestamp.now().as_secs():
def pay_zap_split(nwc, overall_amount, zaps):
overallsplit = 0 overallsplit = 0
for zap in jsonevent['zaps']: for zap in zaps:
overallsplit += int(zap['split']) overallsplit += int(zap['split'])
zapped_amount = 0 zapped_amount = 0
for zap in jsonevent['zaps']: for zap in zaps:
name, nip05, lud16 = fetch_user_metadata(zap['key'], self.client) name, nip05, lud16 = fetch_user_metadata(zap['key'], self.client)
splitted_amount = math.floor( splitted_amount = math.floor(
(int(zap['split']) / overallsplit) * int(jsonevent['overall_amount']) / 1000) (int(zap['split']) / overallsplit) * int(overall_amount) / 1000)
# invoice = create_bolt11_lud16(lud16, splitted_amount) # invoice = create_bolt11_lud16(lud16, splitted_amount)
# TODO add details about DVM in message # TODO add details about DVM in message
invoice = zaprequest(lud16, splitted_amount, "DVM subscription", None, invoice = zaprequest(lud16, splitted_amount, "DVM subscription", None,
@@ -177,9 +148,12 @@ class Subscription:
success = False success = False
else: else:
print("Zapped successfully") print("Zapped successfully")
success = True
# if no active subscription exists OR the subscription ended, pay # if no active subscription exists OR the subscription ended, pay
if success: return success
def make_subscription_zap_recipe(event7001, recipient, subscriber, start, end, tier_dtag):
message = "payed by subscription service" message = "payed by subscription service"
pTag = Tag.parse(["p", recipient]) pTag = Tag.parse(["p", recipient])
PTag = Tag.parse(["P", subscriber]) PTag = Tag.parse(["P", subscriber])
@@ -201,27 +175,81 @@ class Subscription:
client.connect() client.connect()
recipeid = client.send_event(event) recipeid = client.send_event(event)
recipe = recipeid.to_hex() recipe = recipeid.to_hex()
return recipe
def handle_dm(nostr_event):
sender = nostr_event.author().to_hex()
if sender == self.keys.public_key().to_hex():
return
try:
decrypted_text = nip04_decrypt(self.keys.secret_key(), nostr_event.author(), nostr_event.content())
try:
jsonevent = json.loads(decrypted_text)
print(jsonevent)
nwc = nip44_decrypt(self.keys.secret_key(), nostr_event.author(), jsonevent['nwc'])
event7001 = jsonevent['subscribe_event']
cadence = jsonevent['cadence']
recipient = jsonevent['recipient']
subscriber = jsonevent['subscriber']
overall_amount = int(jsonevent['overall_amount'])
tier_dtag = jsonevent['tier_dtag']
start = Timestamp.now().as_secs()
isactivesubscription = False
recipe = ""
subscription = get_from_subscription_sql_table("db/subscriptions", event7001)
#if subscription is not None and subscription.end > start:
# start = subscription.end
# isactivesubscription = True
zapsstr = json.dumps(jsonevent['zaps'])
print(zapsstr)
success = True
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)
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
if success:
recipe = make_subscription_zap_recipe(event7001, recipient, subscriber, start, end, tier_dtag)
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)

View File

@@ -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,

View File

@@ -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

View File

@@ -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()

View File

@@ -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))

View File

@@ -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>

View File

@@ -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>