forked from coracle/flotilla
Remove old alerts
This commit is contained in:
+2
-180
@@ -1,33 +1,24 @@
|
||||
import {nwc} from "@getalby/sdk"
|
||||
import * as nip19 from "nostr-tools/nip19"
|
||||
import {get, derived} from "svelte/store"
|
||||
import type {Override, MakeOptional} from "@welshman/lib"
|
||||
import {
|
||||
first,
|
||||
sha256,
|
||||
randomId,
|
||||
append,
|
||||
remove,
|
||||
flatten,
|
||||
poll,
|
||||
uniq,
|
||||
equals,
|
||||
TIMEZONE,
|
||||
LOCALE,
|
||||
parseJson,
|
||||
fromPairs,
|
||||
last,
|
||||
simpleCache,
|
||||
normalizeUrl,
|
||||
nthNe,
|
||||
} from "@welshman/lib"
|
||||
import {decrypt, Nip01Signer} from "@welshman/signer"
|
||||
import {Nip01Signer} from "@welshman/signer"
|
||||
import type {UploadTask} from "@welshman/editor"
|
||||
import type {Feed} from "@welshman/feeds"
|
||||
import {makeIntersectionFeed, feedFromFilters, makeRelayFeed} from "@welshman/feeds"
|
||||
import type {TrustedEvent, EventContent, Profile} from "@welshman/util"
|
||||
import {
|
||||
WRAP,
|
||||
DELETE,
|
||||
REPORT,
|
||||
PROFILE,
|
||||
@@ -39,10 +30,6 @@ import {
|
||||
RELAY_LEAVE,
|
||||
ROOMS,
|
||||
COMMENT,
|
||||
ALERT_EMAIL,
|
||||
ALERT_WEB,
|
||||
ALERT_IOS,
|
||||
ALERT_ANDROID,
|
||||
APP_DATA,
|
||||
isSignedEvent,
|
||||
makeEvent,
|
||||
@@ -55,8 +42,6 @@ import {
|
||||
getRelayTagValues,
|
||||
toNostrURI,
|
||||
RelayMode,
|
||||
getAddress,
|
||||
getTagValue,
|
||||
getTagValues,
|
||||
uploadBlob,
|
||||
canUploadBlob,
|
||||
@@ -85,18 +70,15 @@ import {
|
||||
waitForThunkError,
|
||||
getPubkeyRelays,
|
||||
userBlossomServerList,
|
||||
shouldUnwrap,
|
||||
getThunkError,
|
||||
} from "@welshman/app"
|
||||
import {compressFile} from "@lib/html"
|
||||
import {kv, db} from "@app/core/storage"
|
||||
import type {SettingsValues, Alert} from "@app/core/state"
|
||||
import type {SettingsValues} from "@app/core/state"
|
||||
import {
|
||||
SETTINGS,
|
||||
PROTECTED,
|
||||
INDEXER_RELAYS,
|
||||
NOTIFIER_PUBKEY,
|
||||
NOTIFIER_RELAY,
|
||||
DEFAULT_BLOSSOM_SERVERS,
|
||||
userSpaceUrls,
|
||||
userSettingsValues,
|
||||
@@ -107,8 +89,6 @@ import {
|
||||
relaysMostlyRestricted,
|
||||
deriveSocket,
|
||||
} from "@app/core/state"
|
||||
import {loadAlertStatuses} from "@app/core/requests"
|
||||
import {platform, platformName, getPushInfo} from "@app/util/push"
|
||||
|
||||
// Utils
|
||||
|
||||
@@ -373,164 +353,6 @@ export const makeComment = ({event, content, tags = []}: CommentParams) =>
|
||||
export const publishComment = ({relays, ...params}: CommentParams & {relays: string[]}) =>
|
||||
publishThunk({event: makeComment(params), relays})
|
||||
|
||||
// Alerts
|
||||
|
||||
export type AlertParamsEmail = {
|
||||
cron: string
|
||||
email: string
|
||||
handler: string[]
|
||||
}
|
||||
|
||||
export type AlertParamsWeb = {
|
||||
endpoint: string
|
||||
p256dh: string
|
||||
auth: string
|
||||
}
|
||||
|
||||
export type AlertParamsIos = {
|
||||
device_token: string
|
||||
bundle_identifier: string
|
||||
}
|
||||
|
||||
export type AlertParamsAndroid = {
|
||||
device_token: string
|
||||
}
|
||||
|
||||
export type AlertParams = {
|
||||
feed: Feed
|
||||
description: string
|
||||
claims?: Record<string, string>
|
||||
email?: AlertParamsEmail
|
||||
web?: AlertParamsWeb
|
||||
ios?: AlertParamsIos
|
||||
android?: AlertParamsAndroid
|
||||
}
|
||||
|
||||
export const makeAlert = async (params: AlertParams) => {
|
||||
const tags = [
|
||||
["feed", JSON.stringify(params.feed)],
|
||||
["locale", LOCALE],
|
||||
["timezone", TIMEZONE],
|
||||
["description", params.description],
|
||||
]
|
||||
|
||||
for (const [relay, claim] of Object.entries(params.claims || [])) {
|
||||
tags.push(["claim", relay, claim])
|
||||
}
|
||||
|
||||
let kind: number
|
||||
if (params.email) {
|
||||
kind = ALERT_EMAIL
|
||||
tags.push(...Object.entries(params.email).map(flatten))
|
||||
} else if (params.web) {
|
||||
kind = ALERT_WEB
|
||||
tags.push(...Object.entries(params.web).map(flatten))
|
||||
} else if (params.ios) {
|
||||
kind = ALERT_IOS
|
||||
tags.push(...Object.entries(params.ios).map(flatten))
|
||||
} else if (params.android) {
|
||||
kind = ALERT_ANDROID
|
||||
tags.push(...Object.entries(params.android).map(flatten))
|
||||
} else {
|
||||
throw new Error("Alert has invalid params")
|
||||
}
|
||||
|
||||
return makeEvent(kind, {
|
||||
content: await signer.get().nip44.encrypt(NOTIFIER_PUBKEY, JSON.stringify(tags)),
|
||||
tags: [
|
||||
["d", randomId()],
|
||||
["p", NOTIFIER_PUBKEY],
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
export const publishAlert = async (params: AlertParams) =>
|
||||
publishThunk({event: await makeAlert(params), relays: [NOTIFIER_RELAY]})
|
||||
|
||||
export const deleteAlert = (alert: Alert) => {
|
||||
const relays = [NOTIFIER_RELAY]
|
||||
const tags = [["p", NOTIFIER_PUBKEY]]
|
||||
|
||||
return publishDelete({event: alert.event, relays, tags, protect: false})
|
||||
}
|
||||
|
||||
export type CreateAlertParams = Override<
|
||||
AlertParams,
|
||||
{
|
||||
email?: MakeOptional<AlertParamsEmail, "handler">
|
||||
}
|
||||
>
|
||||
|
||||
export type CreateAlertResult = {
|
||||
ok?: true
|
||||
error?: string
|
||||
}
|
||||
|
||||
export const createAlert = async (params: CreateAlertParams): Promise<CreateAlertResult> => {
|
||||
if (params.email) {
|
||||
const cadence = params.email.cron.endsWith("1") ? "Weekly" : "Daily"
|
||||
const handler = [
|
||||
"31990:97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322:1737058597050",
|
||||
"wss://relay.nostr.band/",
|
||||
"web",
|
||||
]
|
||||
|
||||
params.email = {handler, ...params.email}
|
||||
params.description = `${cadence} alert ${params.description}, sent via email.`
|
||||
} else {
|
||||
try {
|
||||
// @ts-ignore
|
||||
params[platform] = await getPushInfo()
|
||||
params.description = `${platformName} push notification ${params.description}.`
|
||||
} catch (e: any) {
|
||||
return {error: String(e)}
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't do this we'll get an event rejection
|
||||
await Pool.get().get(NOTIFIER_RELAY).auth.attemptAuth(sign)
|
||||
|
||||
const thunk = await publishAlert(params as AlertParams)
|
||||
const error = await waitForThunkError(thunk)
|
||||
|
||||
if (error) {
|
||||
return {error}
|
||||
}
|
||||
|
||||
// Fetch our new status to make sure it's active
|
||||
const $pubkey = pubkey.get()!
|
||||
const address = getAddress(thunk.event)
|
||||
const statusEvents = await loadAlertStatuses($pubkey!)
|
||||
const statusEvent = statusEvents.find(event => getTagValue("d", event.tags) === address)
|
||||
const statusTags = statusEvent
|
||||
? parseJson(await decrypt(signer.get(), NOTIFIER_PUBKEY, statusEvent.content))
|
||||
: []
|
||||
const {status = "error", message = "Your alert was not activated"}: Record<string, string> =
|
||||
fromPairs(statusTags)
|
||||
|
||||
if (status === "error") {
|
||||
return {error: message}
|
||||
}
|
||||
|
||||
return {ok: true}
|
||||
}
|
||||
|
||||
export const createDmAlert = async () => {
|
||||
if (!shouldUnwrap.get()) {
|
||||
shouldUnwrap.set(true)
|
||||
}
|
||||
|
||||
const $pubkey = pubkey.get()!
|
||||
|
||||
return createAlert({
|
||||
description: `for direct messages.`,
|
||||
feed: makeIntersectionFeed(
|
||||
feedFromFilters([{kinds: [WRAP], "#p": [$pubkey]}]),
|
||||
makeRelayFeed(...getPubkeyRelays($pubkey, RelayMode.Messaging)),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
// Settings
|
||||
|
||||
export const makeSettings = async (params: Partial<SettingsValues>) => {
|
||||
|
||||
+10
-70
@@ -51,13 +51,7 @@ import {
|
||||
deriveEventsByIdForUrl,
|
||||
getEventsByIdForUrl,
|
||||
} from "@welshman/store"
|
||||
import {isKindFeed, findFeed} from "@welshman/feeds"
|
||||
import {
|
||||
ALERT_ANDROID,
|
||||
ALERT_EMAIL,
|
||||
ALERT_IOS,
|
||||
ALERT_STATUS,
|
||||
ALERT_WEB,
|
||||
APP_DATA,
|
||||
CLIENT_AUTH,
|
||||
COMMENT,
|
||||
@@ -94,7 +88,6 @@ import {
|
||||
getListTags,
|
||||
getPubkeyTagValues,
|
||||
getRelayTagValues,
|
||||
getTagValue,
|
||||
getTagValues,
|
||||
isRelayUrl,
|
||||
normalizeRelayUrl,
|
||||
@@ -105,7 +98,6 @@ import {
|
||||
ManagementMethod,
|
||||
} from "@welshman/util"
|
||||
import type {TrustedEvent, RelayProfile, PublishedRoomMeta, List, Filter} from "@welshman/util"
|
||||
import {decrypt} from "@welshman/signer"
|
||||
import {routerContext, Router} from "@welshman/router"
|
||||
import {
|
||||
pubkey,
|
||||
@@ -114,7 +106,6 @@ import {
|
||||
createSearch,
|
||||
userFollowList,
|
||||
ensurePlaintext,
|
||||
signer,
|
||||
makeOutboxLoader,
|
||||
appContext,
|
||||
deriveRelay,
|
||||
@@ -283,8 +274,11 @@ export type SettingsValues = {
|
||||
relay_auth: RelayAuthMode
|
||||
send_delay: number
|
||||
font_size: number
|
||||
play_notification_sound: boolean
|
||||
show_notifications_badge: boolean
|
||||
alerts_spaces: boolean
|
||||
alerts_mentions: boolean
|
||||
alerts_messages: boolean
|
||||
alerts_sound: boolean
|
||||
alerts_badge: boolean
|
||||
}
|
||||
|
||||
export type Settings = {
|
||||
@@ -301,8 +295,11 @@ export const defaultSettings: SettingsValues = {
|
||||
relay_auth: RelayAuthMode.Conservative,
|
||||
send_delay: 0,
|
||||
font_size: 1.1,
|
||||
play_notification_sound: true,
|
||||
show_notifications_badge: true,
|
||||
alerts_spaces: true,
|
||||
alerts_mentions: true,
|
||||
alerts_messages: true,
|
||||
alerts_sound: true,
|
||||
alerts_badge: true,
|
||||
}
|
||||
|
||||
export const settingsByPubkey = deriveItemsByKey({
|
||||
@@ -341,63 +338,6 @@ export const relaysPendingTrust = writable<string[]>([])
|
||||
|
||||
export const relaysMostlyRestricted = writable<Record<string, string>>({})
|
||||
|
||||
// Alerts
|
||||
|
||||
export type Alert = {
|
||||
event: TrustedEvent
|
||||
tags: string[][]
|
||||
}
|
||||
|
||||
export const alertsById = deriveItemsByKey<Alert>({
|
||||
repository,
|
||||
getKey: alert => alert.event.id,
|
||||
filters: [{kinds: [ALERT_EMAIL, ALERT_WEB, ALERT_IOS, ALERT_ANDROID]}],
|
||||
eventToItem: async event => {
|
||||
const $signer = signer.get()
|
||||
|
||||
if ($signer) {
|
||||
const tags = parseJson(await decrypt($signer, NOTIFIER_PUBKEY, event.content))
|
||||
|
||||
return {event, tags}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export const getAlertFeed = (alert: Alert) =>
|
||||
tryCatch(() => JSON.parse(getTagValue("feed", alert.tags)!))
|
||||
|
||||
export const dmAlert = derived(alertsById, $alertsById => {
|
||||
for (const alert of $alertsById.values()) {
|
||||
if (findFeed(getAlertFeed(alert), f => isKindFeed(f) && f.includes(WRAP))) {
|
||||
return alert
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Alert Statuses
|
||||
|
||||
export type AlertStatus = {
|
||||
event: TrustedEvent
|
||||
tags: string[][]
|
||||
}
|
||||
|
||||
export const alertStatusesByAddress = deriveItemsByKey<AlertStatus>({
|
||||
repository,
|
||||
filters: [{kinds: [ALERT_STATUS]}],
|
||||
getKey: alertStatus => getTagValue("d", alertStatus.event.tags)!,
|
||||
eventToItem: async event => {
|
||||
const $signer = signer.get()
|
||||
|
||||
if ($signer) {
|
||||
const tags = parseJson(await decrypt($signer, NOTIFIER_PUBKEY, event.content))
|
||||
|
||||
return {event, tags}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export const deriveAlertStatus = makeDeriveItem(alertStatusesByAddress)
|
||||
|
||||
// Chats
|
||||
|
||||
export type Chat = {
|
||||
|
||||
Reference in New Issue
Block a user