mirror of
https://github.com/believethehype/nostrdvm.git
synced 2025-05-03 05:00:18 +02:00
noogle: update towards subscriptions
This commit is contained in:
parent
f45924601a
commit
53658548e3
12
.idea/dataSources.xml
generated
12
.idea/dataSources.xml
generated
@ -101,5 +101,17 @@
|
|||||||
<jdbc-url>jdbc:sqlite:identifier.sqlite</jdbc-url>
|
<jdbc-url>jdbc:sqlite:identifier.sqlite</jdbc-url>
|
||||||
<working-dir>$ProjectFileDir$</working-dir>
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
</data-source>
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="subscriptions" uuid="ccd96349-b12f-47d5-8caf-c0c8c359d831">
|
||||||
|
<driver-ref>sqlite.xerial</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/db/subscriptions</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
<libraries>
|
||||||
|
<library>
|
||||||
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.43.0/org/xerial/sqlite-jdbc/3.43.0.0/sqlite-jdbc-3.43.0.0.jar</url>
|
||||||
|
</library>
|
||||||
|
</libraries>
|
||||||
|
</data-source>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
236
nostr_dvm/subscription.py
Normal file
236
nostr_dvm/subscription.py
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
import json
|
||||||
|
import math
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import time
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from nostr_sdk import (Keys, Client, Timestamp, Filter, nip04_decrypt, HandleNotification, EventBuilder, PublicKey,
|
||||||
|
Options, Tag, Event, nip04_encrypt, NostrSigner, EventId, Nip19Event, nip44_decrypt, Kind)
|
||||||
|
|
||||||
|
from nostr_dvm.utils.database_utils import fetch_user_metadata
|
||||||
|
from nostr_dvm.utils.definitions import EventDefinitions
|
||||||
|
from nostr_dvm.utils.dvmconfig import DVMConfig
|
||||||
|
from nostr_dvm.utils.nip89_utils import NIP89Config
|
||||||
|
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, \
|
||||||
|
get_from_subscription__sql_table, update_subscription_sql_table
|
||||||
|
from nostr_dvm.utils.zap_utils import create_bolt11_lud16, zaprequest
|
||||||
|
|
||||||
|
|
||||||
|
class Subscription:
|
||||||
|
job_list: list
|
||||||
|
|
||||||
|
# This is a simple list just to keep track which events we created and manage, so we don't pay for other requests
|
||||||
|
def __init__(self, dvm_config, admin_config=None):
|
||||||
|
self.NAME = "Subscription Handler"
|
||||||
|
dvm_config.DB = "db/" + self.NAME + ".db"
|
||||||
|
self.dvm_config = dvm_config
|
||||||
|
nip89config = NIP89Config()
|
||||||
|
nip89config.NAME = self.NAME
|
||||||
|
self.dvm_config.NIP89 = nip89config
|
||||||
|
self.admin_config = admin_config
|
||||||
|
self.keys = Keys.parse(dvm_config.PRIVATE_KEY)
|
||||||
|
wait_for_send = True
|
||||||
|
skip_disconnected_relays = True
|
||||||
|
opts = (Options().wait_for_send(wait_for_send).send_timeout(timedelta(seconds=self.dvm_config.RELAY_TIMEOUT))
|
||||||
|
.skip_disconnected_relays(skip_disconnected_relays))
|
||||||
|
signer = NostrSigner.keys(self.keys)
|
||||||
|
self.client = Client.with_opts(signer, opts)
|
||||||
|
|
||||||
|
pk = self.keys.public_key()
|
||||||
|
|
||||||
|
self.job_list = []
|
||||||
|
|
||||||
|
print("Nostr Subscription Handler public key: " + str(pk.to_bech32()) + " Hex: " + str(
|
||||||
|
pk.to_hex()) + " Name: " + self.NAME +
|
||||||
|
" Supported DVM tasks: " +
|
||||||
|
', '.join(p.NAME + ":" + p.TASK for p in self.dvm_config.SUPPORTED_DVMS) + "\n")
|
||||||
|
|
||||||
|
for relay in self.dvm_config.RELAY_LIST:
|
||||||
|
self.client.add_relay(relay)
|
||||||
|
self.client.connect()
|
||||||
|
|
||||||
|
zap_filter = Filter().pubkey(pk).kinds([EventDefinitions.KIND_ZAP]).since(Timestamp.now())
|
||||||
|
cancel_subscription_filter = Filter().kinds([EventDefinitions.KIND_NIP88_STOP_SUBSCRIPTION_EVENT]).since(
|
||||||
|
Timestamp.now())
|
||||||
|
# TODO define allowed senders somewhere
|
||||||
|
dm_filter = Filter().author(
|
||||||
|
Keys.parse("ece3c0aa759c3e895ecb3c13ab3813c0f98430c6d4bd22160b9c2219efc9cf0e").public_key()).pubkey(
|
||||||
|
pk).kinds([EventDefinitions.KIND_DM]).since(Timestamp.now())
|
||||||
|
|
||||||
|
self.client.subscribe([zap_filter, dm_filter, cancel_subscription_filter], None)
|
||||||
|
|
||||||
|
create_subscription_sql_table("db/subscriptions")
|
||||||
|
|
||||||
|
# admin_make_database_updates(adminconfig=self.admin_config, dvmconfig=self.dvm_config, client=self.client)
|
||||||
|
|
||||||
|
class NotificationHandler(HandleNotification):
|
||||||
|
client = self.client
|
||||||
|
dvm_config = self.dvm_config
|
||||||
|
keys = self.keys
|
||||||
|
|
||||||
|
def handle(self, relay_url, subscription_id, nostr_event: Event):
|
||||||
|
if nostr_event.kind().as_u64() == EventDefinitions.KIND_DM.as_u64():
|
||||||
|
print(nostr_event.as_json())
|
||||||
|
handle_dm(nostr_event)
|
||||||
|
elif nostr_event.kind().as_u64() == EventDefinitions.KIND_NIP88_STOP_SUBSCRIPTION_EVENT.as_u64():
|
||||||
|
handle_cancel(nostr_event)
|
||||||
|
|
||||||
|
def handle_msg(self, relay_url, msg):
|
||||||
|
return
|
||||||
|
|
||||||
|
def handle_cancel(nostr_event):
|
||||||
|
print(nostr_event.as_json())
|
||||||
|
sender = nostr_event.author().to_hex()
|
||||||
|
kind7001eventid = ""
|
||||||
|
recipient = ""
|
||||||
|
if sender == self.keys.public_key().to_hex():
|
||||||
|
return
|
||||||
|
|
||||||
|
for tag in nostr_event.tags():
|
||||||
|
if tag.as_vec()[0] == "p":
|
||||||
|
recipient = tag.as_vec()[1]
|
||||||
|
elif tag.as_vec()[0] == "e":
|
||||||
|
kind7001eventid = tag.as_vec()[1]
|
||||||
|
|
||||||
|
if kind7001eventid != "":
|
||||||
|
subscription = get_from_subscription__sql_table("db/subscriptions", kind7001eventid)
|
||||||
|
|
||||||
|
if subscription is not None:
|
||||||
|
update_subscription_sql_table("db/subscriptions", kind7001eventid, recipient,
|
||||||
|
subscription.subscriber, subscription.nwc, subscription.cadence,
|
||||||
|
subscription.amount, subscription.begin, subscription.end,
|
||||||
|
subscription.tier_dtag, subscription.zaps, subscription.recipe, False)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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'])
|
||||||
|
print(zapsstr)
|
||||||
|
success = True
|
||||||
|
if subscription is None or subscription.end <= Timestamp.now().as_secs():
|
||||||
|
|
||||||
|
overallsplit = 0
|
||||||
|
|
||||||
|
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:
|
||||||
|
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()
|
||||||
|
print("RECIPE " + recipe)
|
||||||
|
isactivesubscription = True
|
||||||
|
|
||||||
|
if subscription is None:
|
||||||
|
add_to_subscription_sql_table("db/subscriptions", event7001, recipient, subscriber, nwc,
|
||||||
|
cadence, overall_amount, start, end, tier_dtag,
|
||||||
|
zapsstr, recipe, isactivesubscription)
|
||||||
|
print("new subscription entry")
|
||||||
|
else:
|
||||||
|
update_subscription_sql_table("db/subscriptions", event7001, recipient, subscriber, nwc,
|
||||||
|
cadence, overall_amount, start, end,
|
||||||
|
tier_dtag, zapsstr, recipe, isactivesubscription)
|
||||||
|
print("updated subscription entry")
|
||||||
|
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print("Error in Subscriber " + str(e))
|
||||||
|
|
||||||
|
self.client.handle_notifications(NotificationHandler())
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
time.sleep(60.0)
|
||||||
|
print("Checking Subscription")
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print('Stay weird!')
|
||||||
|
os.kill(os.getpid(), signal.SIGTERM)
|
@ -408,7 +408,7 @@ const submitHandler = async () => {
|
|||||||
<figure className="w-full" >
|
<figure className="w-full" >
|
||||||
<img v-if="dvm.result" :src="dvm.result" className="tooltip" data-top='Click to copy url' height="200" alt="DVM Picture" @click="copyurl(dvm.result)"/>
|
<img v-if="dvm.result" :src="dvm.result" className="tooltip" data-top='Click to copy url' height="200" alt="DVM Picture" @click="copyurl(dvm.result)"/>
|
||||||
</figure>
|
</figure>
|
||||||
<div v-if="dvm.result && store.state.pubkey.toHex() !== Keys.parse('ece3c0aa759c3e895ecb3c13ab3813c0f98430c6d4bd22160b9c2219efc9cf0e').publicKey.toHex()" >
|
<div v-if="dvm.result && store.state.pubkey.toHex() !== Keys.parse(store.state.nooglekey).publicKey.toHex()" >
|
||||||
<button @click="openModal('Look what I created on noogle.lol\n\n' + dvm.result)" class="w-8 h-8 rounded-full bg-nostr border-white border-1 text-white flex items-center justify-center focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black tooltip" data-top='Share' aria-label="make note" role="button">
|
<button @click="openModal('Look what I created on noogle.lol\n\n' + dvm.result)" class="w-8 h-8 rounded-full bg-nostr border-white border-1 text-white flex items-center justify-center focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black tooltip" data-top='Share' aria-label="make note" role="button">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-pencil" width="20" height="20" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-pencil" width="20" height="20" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
<path stroke="none" d="M0 0h24v24H0z"></path>
|
<path stroke="none" d="M0 0h24v24H0z"></path>
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<h3 className="card-title">Your account</h3>
|
<h3 className="card-title">Your account</h3>
|
||||||
<!--<p>Sign out</p> -->
|
<!--<p>Sign out</p> -->
|
||||||
|
|
||||||
<button className="btn" onclick="nwcmodal.showModal()" >Nostr Wallet Connect</button>
|
<button className="btn" onclick="nwcmodal.showModal()" >Nostr Wallet Connect</button>
|
||||||
<dialog id="nwcmodal" class="modal">
|
<dialog id="nwcmodal" class="modal">
|
||||||
<div class="modal-box rounded-3xl inner shadow-lg p-6 flex flex-col items-center transition-all duration-1000 bg-base-600/60 ">
|
<div class="modal-box rounded-3xl inner shadow-lg p-6 flex flex-col items-center transition-all duration-1000 bg-base-600/60 ">
|
||||||
@ -210,7 +211,6 @@ const isDark = useDark();
|
|||||||
|
|
||||||
|
|
||||||
let nip89dvms = []
|
let nip89dvms = []
|
||||||
const nsec = ref("");
|
|
||||||
|
|
||||||
let logger = false
|
let logger = false
|
||||||
|
|
||||||
@ -372,7 +372,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let keys = Keys.parse("ece3c0aa759c3e895ecb3c13ab3813c0f98430c6d4bd22160b9c2219efc9cf0e")
|
let keys = Keys.parse(store.state.nooglekey)
|
||||||
this.signer = NostrSigner.keys(keys) //TODO store keys
|
this.signer = NostrSigner.keys(keys) //TODO store keys
|
||||||
let opts = new Options().waitForSend(false).connectionTimeout(Duration.fromSecs(5));
|
let opts = new Options().waitForSend(false).connectionTimeout(Duration.fromSecs(5));
|
||||||
let client = new ClientBuilder().signer(this.signer).opts(opts).build()
|
let client = new ClientBuilder().signer(this.signer).opts(opts).build()
|
||||||
@ -560,7 +560,7 @@ export default {
|
|||||||
|
|
||||||
if (connectionstring === ""){
|
if (connectionstring === ""){
|
||||||
//ADD DEFAULT TEST STRING FOR NOW, USE USER INPUT LATER
|
//ADD DEFAULT TEST STRING FOR NOW, USE USER INPUT LATER
|
||||||
connectionstring = "bunker://7f2d38c4f3cf2070935bad7cab046ad088dcef2de4b0b985f2174ea22a094778?relay=wss://relay.nsec.app"
|
connectionstring = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connectionstring.startsWith("nsecbunker://")){
|
if (connectionstring.startsWith("nsecbunker://")){
|
||||||
@ -682,7 +682,7 @@ export default {
|
|||||||
async getnip89s(){
|
async getnip89s(){
|
||||||
|
|
||||||
//let keys = Keys.generate()
|
//let keys = Keys.generate()
|
||||||
let keys = Keys.parse("ece3c0aa759c3e895ecb3c13ab3813c0f98430c6d4bd22160b9c2219efc9cf0e")
|
let keys = Keys.parse(store.state.nooglekey)
|
||||||
let signer = NostrSigner.keys(keys) //TODO store keys
|
let signer = NostrSigner.keys(keys) //TODO store keys
|
||||||
let client = new ClientBuilder().signer(signer).build()
|
let client = new ClientBuilder().signer(signer).build()
|
||||||
|
|
||||||
@ -741,9 +741,13 @@ export default {
|
|||||||
description: "",
|
description: "",
|
||||||
eventid: "",
|
eventid: "",
|
||||||
event: "",
|
event: "",
|
||||||
|
p: "",
|
||||||
hasActiveSubscription: false,
|
hasActiveSubscription: false,
|
||||||
subscribedUntil: 0,
|
subscribedUntil: 0,
|
||||||
subscriptionId: "",
|
d : "",
|
||||||
|
expires : false,
|
||||||
|
subscriptionId: ""
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jsonentry.picture){
|
if (jsonentry.picture){
|
||||||
@ -786,7 +790,15 @@ export default {
|
|||||||
nip88.perks.push(tag.asVec()[1])
|
nip88.perks.push(tag.asVec()[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(tag.asVec()[0] === "zap_local"){
|
else if(tag.asVec()[0] === "p") {
|
||||||
|
nip88.p = tag.asVec()[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(tag.asVec()[0] === "d") {
|
||||||
|
nip88.d = tag.asVec()[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(tag.asVec()[0] === "zap"){
|
||||||
let zap = {
|
let zap = {
|
||||||
key: (tag.asVec()[1] !== "" ? tag.asVec()[1] : PublicKey.parse("npub1nxa4tywfz9nqp7z9zp7nr7d4nchhclsf58lcqt5y782rmf2hefjquaa6q8").toHex()) ,
|
key: (tag.asVec()[1] !== "" ? tag.asVec()[1] : PublicKey.parse("npub1nxa4tywfz9nqp7z9zp7nr7d4nchhclsf58lcqt5y782rmf2hefjquaa6q8").toHex()) ,
|
||||||
relay: tag.asVec()[2],
|
relay: tag.asVec()[2],
|
||||||
@ -805,10 +817,11 @@ export default {
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
let subscription_status = await hasActiveSubscription(localStorage.getItem("nostr-key"), evt.id.toHex(), evt.author.toHex(), nip88.amounts)
|
let subscription_status = await hasActiveSubscription(store.state.pubkey.toHex(), nip88.d, evt.author.toHex(), nip88.amounts)
|
||||||
nip88.hasActiveSubscription = subscription_status.isActive
|
nip88.hasActiveSubscription = subscription_status.isActive
|
||||||
nip88.subscribedUntil = subscription_status.validuntil
|
nip88.subscribedUntil = subscription_status.validUntil
|
||||||
nip88.subscriptionId = subscription_status.subscriptionId
|
nip88.subscriptionId = subscription_status.subscriptionId
|
||||||
|
nip88.expires = subscription_status.expires
|
||||||
|
|
||||||
|
|
||||||
jsonentry.nip88 = nip88
|
jsonentry.nip88 = nip88
|
||||||
@ -844,7 +857,7 @@ export default {
|
|||||||
async reconcile_all_profiles(publicKey) {
|
async reconcile_all_profiles(publicKey) {
|
||||||
{
|
{
|
||||||
let dbclient = Client
|
let dbclient = Client
|
||||||
let keys = Keys.parse("ece3c0aa759c3e895ecb3c13ab3813c0f98430c6d4bd22160b9c2219efc9cf0e")
|
let keys = Keys.parse(store.state.nooglekey)
|
||||||
let db = NostrDatabase.indexeddb("profiles");
|
let db = NostrDatabase.indexeddb("profiles");
|
||||||
let signer = NostrSigner.keys(keys) //TODO store keys
|
let signer = NostrSigner.keys(keys) //TODO store keys
|
||||||
dbclient = new ClientBuilder().signer(signer).database(await db).build()
|
dbclient = new ClientBuilder().signer(signer).database(await db).build()
|
||||||
|
File diff suppressed because one or more lines are too long
@ -475,7 +475,7 @@ const submitHandler = async () => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div data-tip="Make Summarization" v-if="dvm.result.length > 0 && store.state.pubkey.toHex() !== Keys.parse('ece3c0aa759c3e895ecb3c13ab3813c0f98430c6d4bd22160b9c2219efc9cf0e').publicKey.toHex()" >
|
<div data-tip="Make Summarization" v-if="dvm.result.length > 0 && store.state.pubkey.toHex() !== Keys.parse(store.state.nooglekey).publicKey.toHex()" >
|
||||||
<button @click="openModal(dvm.result)" class="w-8 h-8 rounded-full bg-nostr border-white border-1 text-white flex items-center justify-center focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black tooltip" data-top='Share' aria-label="make note" role="button">
|
<button @click="openModal(dvm.result)" class="w-8 h-8 rounded-full bg-nostr border-white border-1 text-white flex items-center justify-center focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black tooltip" data-top='Share' aria-label="make note" role="button">
|
||||||
<svg class="w-4 h-4 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
<svg class="w-4 h-4 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
||||||
<path d="M9 19V.352A3.451 3.451 0 0 0 7.5 0a3.5 3.5 0 0 0-3.261 2.238A3.5 3.5 0 0 0 2.04 6.015a3.518 3.518 0 0 0-.766 1.128c-.042.1-.064.209-.1.313a3.34 3.34 0 0 0-.106.344 3.463 3.463 0 0 0 .02 1.468A4.016 4.016 0 0 0 .3 10.5l-.015.036a3.861 3.861 0 0 0-.216.779A3.968 3.968 0 0 0 0 12a4.032 4.032 0 0 0 .107.889 4 4 0 0 0 .2.659c.006.014.015.027.021.041a3.85 3.85 0 0 0 .417.727c.105.146.219.284.342.415.072.076.148.146.225.216.1.091.205.179.315.26.11.081.2.14.308.2.02.013.039.028.059.04v.053a3.506 3.506 0 0 0 3.03 3.469 3.426 3.426 0 0 0 4.154.577A.972.972 0 0 1 9 19Zm10.934-7.68a3.956 3.956 0 0 0-.215-.779l-.017-.038a4.016 4.016 0 0 0-.79-1.235 3.417 3.417 0 0 0 .017-1.468 3.387 3.387 0 0 0-.1-.333c-.034-.108-.057-.22-.1-.324a3.517 3.517 0 0 0-.766-1.128 3.5 3.5 0 0 0-2.202-3.777A3.5 3.5 0 0 0 12.5 0a3.451 3.451 0 0 0-1.5.352V19a.972.972 0 0 1-.184.546 3.426 3.426 0 0 0 4.154-.577A3.506 3.506 0 0 0 18 15.5v-.049c.02-.012.039-.027.059-.04.106-.064.208-.13.308-.2s.214-.169.315-.26c.077-.07.153-.14.225-.216a4.007 4.007 0 0 0 .459-.588c.115-.176.215-.361.3-.554.006-.014.015-.027.021-.041.087-.213.156-.434.205-.659.013-.057.024-.115.035-.173.046-.237.07-.478.073-.72a3.948 3.948 0 0 0-.066-.68Z"/>
|
<path d="M9 19V.352A3.451 3.451 0 0 0 7.5 0a3.5 3.5 0 0 0-3.261 2.238A3.5 3.5 0 0 0 2.04 6.015a3.518 3.518 0 0 0-.766 1.128c-.042.1-.064.209-.1.313a3.34 3.34 0 0 0-.106.344 3.463 3.463 0 0 0 .02 1.468A4.016 4.016 0 0 0 .3 10.5l-.015.036a3.861 3.861 0 0 0-.216.779A3.968 3.968 0 0 0 0 12a4.032 4.032 0 0 0 .107.889 4 4 0 0 0 .2.659c.006.014.015.027.021.041a3.85 3.85 0 0 0 .417.727c.105.146.219.284.342.415.072.076.148.146.225.216.1.091.205.179.315.26.11.081.2.14.308.2.02.013.039.028.059.04v.053a3.506 3.506 0 0 0 3.03 3.469 3.426 3.426 0 0 0 4.154.577A.972.972 0 0 1 9 19Zm10.934-7.68a3.956 3.956 0 0 0-.215-.779l-.017-.038a4.016 4.016 0 0 0-.79-1.235 3.417 3.417 0 0 0 .017-1.468 3.387 3.387 0 0 0-.1-.333c-.034-.108-.057-.22-.1-.324a3.517 3.517 0 0 0-.766-1.128 3.5 3.5 0 0 0-2.202-3.777A3.5 3.5 0 0 0 12.5 0a3.451 3.451 0 0 0-1.5.352V19a.972.972 0 0 1-.184.546 3.426 3.426 0 0 0 4.154-.577A3.506 3.506 0 0 0 18 15.5v-.049c.02-.012.039-.027.059-.04.106-.064.208-.13.308-.2s.214-.169.315-.26c.077-.07.153-.14.225-.216a4.007 4.007 0 0 0 .459-.588c.115-.176.215-.361.3-.554.006-.014.015-.027.021-.041.087-.213.156-.434.205-.659.013-.057.024-.115.035-.173.046-.237.07-.478.073-.72a3.948 3.948 0 0 0-.066-.68Z"/>
|
||||||
|
@ -13,7 +13,7 @@ import {
|
|||||||
PublicKey,
|
PublicKey,
|
||||||
SingleLetterTag,
|
SingleLetterTag,
|
||||||
Tag,
|
Tag,
|
||||||
Timestamp
|
Timestamp, UnsignedEvent
|
||||||
} from "@rust-nostr/nostr-sdk";
|
} from "@rust-nostr/nostr-sdk";
|
||||||
import miniToastr from "mini-toastr/mini-toastr";
|
import miniToastr from "mini-toastr/mini-toastr";
|
||||||
import VueNotifications from "vue-notifications";
|
import VueNotifications from "vue-notifications";
|
||||||
@ -369,197 +369,59 @@ export async function fetchAsync (url) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
export async function hasActiveSubscription(pubkeystring, tiereventid, tierauthorid, amounts) {
|
export async function hasActiveSubscription(pubkeystring, tiereventdtag, tierauthorid, amounts) {
|
||||||
console.log("Checking for subscription")
|
|
||||||
let client = store.state.client
|
|
||||||
let subscriptionstatus = {
|
|
||||||
isActive: false,
|
|
||||||
validuntil: 0,
|
|
||||||
subscriptionId: "",
|
|
||||||
}
|
|
||||||
|
|
||||||
let event7001id = EventId
|
console.log("Checking for subscription")
|
||||||
console.log(pubkeystring)
|
let client = store.state.client
|
||||||
// look if user has 7001 event, and if 7001 has been canceled by 7002
|
let subscriptionstatus = {
|
||||||
const filter = new Filter().kind(7001).author(PublicKey.parse(pubkeystring)).pubkey(PublicKey.parse(tierauthorid)).event(EventId.parse(tiereventid)) //only get latest with these conditions
|
isActive: false,
|
||||||
let evts = await client.getEventsOf([filter], Duration.fromSecs(5))
|
validUntil: 0,
|
||||||
console.log(evts)
|
subscriptionId: "",
|
||||||
if (evts.length > 0) {
|
expires: false
|
||||||
|
|
||||||
//console.log("7001: " + evts[0].asJson())
|
|
||||||
let checkispaid = []
|
|
||||||
for (let tag of evts[0].tags){
|
|
||||||
/*if (tag.asVec()[0] === "e"){
|
|
||||||
console.log("sanity check")
|
|
||||||
const filtercheck = new Filter().kind(37001).id(EventId.parse(tag.asVec()[1])).limit(1) // get latest with these conditons # customTag(SingleLetterTag.lowercase(Alphabet.A), [eventid])
|
|
||||||
let sanityevents = await client.getEventsOf([filtercheck], Duration.fromSecs(5))
|
|
||||||
if (sanityevents.length === 0){
|
|
||||||
subscriptionstatus.isActive = false
|
|
||||||
return subscriptionstatus
|
|
||||||
}
|
|
||||||
else{console.log(sanityevents[0].asJson())
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
if (tag.asVec()[0] === "zap"){
|
|
||||||
checkispaid.push(tag)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let splitids = []
|
let subscriptionfilter = new Filter().kind(7003).pubkey(PublicKey.parse(tierauthorid)).customTag(SingleLetterTag.uppercase(Alphabet.P), [pubkeystring]).limit(1)
|
||||||
for (let tag of checkispaid){
|
let evts = await client.getEventsOf([subscriptionfilter], Duration.fromSecs(5))
|
||||||
splitids.push(PublicKey.parse(tag.asVec()[1]))
|
console.log(evts)
|
||||||
console.log(tag.asVec())
|
if (evts.length > 0){
|
||||||
}
|
console.log(evts[0].asJson())
|
||||||
if (checkispaid.length === 0){
|
let matchesdtag = false
|
||||||
subscriptionstatus.isActive = false
|
for (let tag of evts[0].tags){
|
||||||
return subscriptionstatus
|
if (tag.asVec()[0] === "valid"){
|
||||||
}
|
subscriptionstatus["validUntil"] = parseInt(tag.asVec()[2])
|
||||||
|
|
||||||
for (let evt in evts){
|
|
||||||
event7001id = evts[0].id
|
|
||||||
}
|
|
||||||
|
|
||||||
event7001id = evts[0].id
|
|
||||||
|
|
||||||
const filter = new Filter().kind(7002).pubkey(PublicKey.parse(tierauthorid)).event(event7001id).limit(1) // get latest with these conditons # customTag(SingleLetterTag.lowercase(Alphabet.A), [eventid])
|
|
||||||
let cancelevts = await client.getEventsOf([filter], Duration.fromSecs(5))
|
|
||||||
if (cancelevts.length > 0) {
|
|
||||||
if (cancelevts[0].createdAt.asSecs() > evts[0].createdAt.asSecs()) {
|
|
||||||
console.log("A subscription exists, but has been canceled")
|
|
||||||
subscriptionstatus.isActive = false
|
|
||||||
subscriptionstatus.subscriptionId = event7001id.toHex()
|
|
||||||
return subscriptionstatus
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.log("A subscription exists, checking payment status")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const zapfilter = new Filter().kind(9735).pubkeys(splitids).event(event7001id).limit(checkispaid.length)
|
|
||||||
let zapevents = await client.getEventsOf([zapfilter], Duration.fromSecs(5))
|
|
||||||
if (zapevents.length > 0) {
|
|
||||||
console.log(zapevents)
|
|
||||||
let timeofourlastzap = 0
|
|
||||||
|
|
||||||
let overallamount = 0
|
|
||||||
|
|
||||||
let overall = 0
|
|
||||||
for (let tag of checkispaid){
|
|
||||||
let split = parseInt(tag.asVec()[2])
|
|
||||||
overall += split
|
|
||||||
}
|
}
|
||||||
for(let zapevent of zapevents) {
|
else if (tag.asVec()[0] === "e"){
|
||||||
|
subscriptionstatus["subscriptionId"] = tag.asVec()[1]
|
||||||
|
|
||||||
if (zapevent.createdAt.asSecs() > timeofourlastzap) {
|
|
||||||
timeofourlastzap = zapevent.createdAt.asSecs()
|
|
||||||
}
|
}
|
||||||
|
else if (tag.asVec()[0] === "tier"){
|
||||||
for (let tag of zapevent.tags) {
|
if (tag.asVec()[1] === tiereventdtag)
|
||||||
if (tag.asVec()[0] === "description") {
|
{
|
||||||
|
matchesdtag = true
|
||||||
let event9734 = Event.fromJson(tag.asVec()[1])
|
}
|
||||||
|
|
||||||
|
|
||||||
for (let tag of event9734.tags) {
|
|
||||||
if (tag.asVec()[0] === "amount") {
|
|
||||||
let amount = parseInt(tag.asVec()[1])
|
|
||||||
console.log("AMOUNT: " + amount)
|
|
||||||
overallamount = overallamount + amount
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (subscriptionstatus["validUntil"] > Timestamp.now().asSecs() && matchesdtag){
|
||||||
|
subscriptionstatus["isActive"] = true
|
||||||
|
}
|
||||||
|
|
||||||
let entry
|
if( subscriptionstatus["isActive"] === true){
|
||||||
for (let index in amounts){
|
const filter = new Filter().kind(7002).author(PublicKey.parse(pubkeystring)).pubkey(PublicKey.parse(tierauthorid)).event(EventId.parse(subscriptionstatus["subscriptionId"])).limit(1) // get latest with these conditons # customTag(SingleLetterTag.lowercase(Alphabet.A), [eventid])
|
||||||
if(parseInt(amounts[index].amount) === overallamount ){
|
let cancelevts = await client.getEventsOf([filter], Duration.fromSecs(5))
|
||||||
entry = amounts[index]
|
if (cancelevts.length > 0) {
|
||||||
}
|
if (cancelevts[0].createdAt.asSecs() > evts[0].createdAt.asSecs()) {
|
||||||
}
|
subscriptionstatus["expires"] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(!entry){
|
}
|
||||||
console.log("Undefined amount")
|
|
||||||
subscriptionstatus.isActive = false
|
|
||||||
subscriptionstatus.subscriptionId = event7001id.toHex()
|
|
||||||
//subscriptionstatus.validuntil = zapevent.createdAt.asSecs() + 24*60*60
|
|
||||||
return subscriptionstatus
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
console.log(entry.amount + " " + entry.cadence)
|
|
||||||
if (entry.cadence === "daily"){
|
|
||||||
if (timeofourlastzap + 24*60*60 > Timestamp.now().asSecs()){
|
|
||||||
console.log("A daily subscription exists, and is active")
|
|
||||||
subscriptionstatus.isActive = true
|
|
||||||
subscriptionstatus.subscriptionId = event7001id.toHex()
|
|
||||||
subscriptionstatus.validuntil = timeofourlastzap + 24*60*60
|
|
||||||
return subscriptionstatus
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (entry.cadence === "monthly"){
|
|
||||||
if (timeofourlastzap + 31*24*60*60 > Timestamp.now().asSecs()){
|
|
||||||
console.log("A monthly subscription exists, and is active")
|
|
||||||
subscriptionstatus.isActive = true
|
|
||||||
subscriptionstatus.subscriptionId = event7001id.toHex()
|
|
||||||
subscriptionstatus.validuntil = timeofourlastzap + 31*24*60*60
|
|
||||||
return subscriptionstatus
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (entry.cadence === "yearly"){
|
|
||||||
if (timeofourlastzap + 366*24*60*60 > Timestamp.now().asSecs()){
|
|
||||||
console.log("A yearly subscription exists, and is active")
|
|
||||||
subscriptionstatus.isActive = true
|
|
||||||
subscriptionstatus.subscriptionId = event7001id.toHex()
|
|
||||||
subscriptionstatus.validuntil = timeofourlastzap + 366*24*60*60
|
|
||||||
return subscriptionstatus
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*else if (tag.asVec()[0] === "bolt11"){
|
|
||||||
let lnurl = tag.asVec()[1]
|
|
||||||
console.log(lnurl)
|
|
||||||
} */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
// todo check that subscription is within the range
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
console.log("A subscription exists, but no payment has been made")
|
|
||||||
subscriptionstatus.isActive = false
|
|
||||||
subscriptionstatus.subscriptionId = event7001id.toHex()
|
|
||||||
return subscriptionstatus
|
return subscriptionstatus
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
|
||||||
console.log("No subscription exists")
|
|
||||||
subscriptionstatus.isActive = false
|
|
||||||
return subscriptionstatus
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ export async function zap_lud16(lud16, eventid, authorid){
|
|||||||
return ob["pr"]
|
return ob["pr"]
|
||||||
}
|
}
|
||||||
catch(e){
|
catch(e){
|
||||||
console.log("HELLO" + e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(error){
|
catch(error){
|
||||||
|
@ -5,11 +5,12 @@ const store = createStore({
|
|||||||
state () {
|
state () {
|
||||||
return {
|
return {
|
||||||
count: 0,
|
count: 0,
|
||||||
test: "hello",
|
|
||||||
client: Client,
|
client: Client,
|
||||||
signer: NostrSigner,
|
signer: NostrSigner,
|
||||||
dbclient: Client,
|
dbclient: Client,
|
||||||
pubkey: PublicKey,
|
pubkey: PublicKey,
|
||||||
|
nooglekey: "ece3c0aa759c3e895ecb3c13ab3813c0f98430c6d4bd22160b9c2219efc9cf0e",
|
||||||
|
subscription_verifier_pubkey: "5b5c045ecdf66fb540bdf2049fe0ef7f1a566fa427a4fe50d400a011b65a3a7e",
|
||||||
requestidSearch: String,
|
requestidSearch: String,
|
||||||
requestidSearchProfile: String,
|
requestidSearchProfile: String,
|
||||||
requestidImage: String,
|
requestidImage: String,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user