feat: organizer-side "Republish mine" button + scoped endpoint
The admin /republish-all hits every approved event regardless of owner — useful for the catalog migration, but heavy. Organizers who want to re-emit just THEIR own events (e.g. after the AIO publisher gained the tickets_* tags and an organizer's events should pick them up) need a lighter knob. Backend: new POST /republish-mine wallet-scoped via require_admin_key, mirrors api_tickets's `all_wallets=true` shape so the page can re-emit across every wallet the user owns. Filters to approved + non-canceled rows. UI: "Republish mine" button alongside "New Event" so every logged-in user sees it (no isAdmin gate). Loading state + confirm dialog + success count notification. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fa2a6e40f0
commit
ced6ca2b2b
3 changed files with 79 additions and 3 deletions
|
|
@ -10,6 +10,7 @@ window.PageEvents = {
|
||||||
allUserEvents: [],
|
allUserEvents: [],
|
||||||
isAdmin: false,
|
isAdmin: false,
|
||||||
republishing: false,
|
republishing: false,
|
||||||
|
republishingMine: false,
|
||||||
settings: {
|
settings: {
|
||||||
auto_approve: false
|
auto_approve: false
|
||||||
},
|
},
|
||||||
|
|
@ -303,6 +304,36 @@ window.PageEvents = {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
republishMyEvents() {
|
||||||
|
LNbits.utils
|
||||||
|
.confirmDialog(
|
||||||
|
'Re-emit your approved events to Nostr relays?'
|
||||||
|
)
|
||||||
|
.onOk(() => {
|
||||||
|
this.republishingMine = true
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'POST',
|
||||||
|
'/events/api/v1/events/republish-mine?all_wallets=true',
|
||||||
|
this.g.user.wallets[0].adminkey
|
||||||
|
)
|
||||||
|
.then(response => {
|
||||||
|
Quasar.Notify.create({
|
||||||
|
type: 'positive',
|
||||||
|
message:
|
||||||
|
'Republished ' +
|
||||||
|
response.data.republished +
|
||||||
|
' of your ' +
|
||||||
|
response.data.total +
|
||||||
|
' events'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(LNbits.utils.notifyApiError)
|
||||||
|
.finally(() => {
|
||||||
|
this.republishingMine = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
foldDateTime(day, time) {
|
foldDateTime(day, time) {
|
||||||
// Combine separate date/time inputs into the wire format
|
// Combine separate date/time inputs into the wire format
|
||||||
// expected by the events extension: "YYYY-MM-DD" or
|
// expected by the events extension: "YYYY-MM-DD" or
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,23 @@
|
||||||
|
|
||||||
<q-card>
|
<q-card>
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
|
<div class="row items-center q-gutter-sm">
|
||||||
<q-btn unelevated color="primary" @click="openEventDialog"
|
<q-btn unelevated color="primary" @click="openEventDialog"
|
||||||
>New Event</q-btn
|
>New Event</q-btn
|
||||||
>
|
>
|
||||||
|
<q-btn
|
||||||
|
outline
|
||||||
|
color="primary"
|
||||||
|
icon="cloud_upload"
|
||||||
|
label="Republish mine"
|
||||||
|
:loading="republishingMine"
|
||||||
|
@click="republishMyEvents"
|
||||||
|
></q-btn>
|
||||||
|
</div>
|
||||||
|
<div class="text-caption q-mt-sm" style="color: #aaa">
|
||||||
|
Re-emit your approved events to Nostr relays. Useful after
|
||||||
|
a publisher upgrade or if a relay dropped your events.
|
||||||
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
|
|
||||||
|
|
|
||||||
31
views_api.py
31
views_api.py
|
|
@ -136,6 +136,37 @@ async def api_republish_all(
|
||||||
return {"republished": len(approved), "total": len(events)}
|
return {"republished": len(approved), "total": len(events)}
|
||||||
|
|
||||||
|
|
||||||
|
@events_api_router.post("/republish-mine")
|
||||||
|
async def api_republish_mine(
|
||||||
|
all_wallets: bool = Query(False),
|
||||||
|
key_info: WalletTypeInfo = Depends(require_admin_key),
|
||||||
|
) -> dict:
|
||||||
|
"""Force-republish the caller's own approved events to Nostr relays.
|
||||||
|
|
||||||
|
Same shape as /republish-all but scoped to events owned by the
|
||||||
|
authenticated wallet (or all wallets belonging to the wallet's
|
||||||
|
user when `?all_wallets=true`). Lets the organizer trigger the
|
||||||
|
same migration the admin uses, without needing instance-admin
|
||||||
|
rights — useful when the AIO publisher gains a new tag set and
|
||||||
|
an organizer wants their published events to carry it.
|
||||||
|
|
||||||
|
Only events with `status == "approved"` are republished; pending
|
||||||
|
and rejected rows aren't on relays in the first place, so a
|
||||||
|
republish for them would be a no-op (or worse, surface a
|
||||||
|
proposed-but-not-approved row to subscribers).
|
||||||
|
"""
|
||||||
|
wallet_ids: list[str] = [key_info.wallet.id]
|
||||||
|
if all_wallets:
|
||||||
|
user = await get_user(key_info.wallet.user)
|
||||||
|
wallet_ids = user.wallet_ids if user else []
|
||||||
|
|
||||||
|
events = await get_events(wallet_ids)
|
||||||
|
approved = [e for e in events if e.status == "approved" and not e.canceled]
|
||||||
|
for event in approved:
|
||||||
|
await publish_or_delete_nostr_event(event)
|
||||||
|
return {"republished": len(approved), "total": len(events)}
|
||||||
|
|
||||||
|
|
||||||
@events_api_router.get("/settings")
|
@events_api_router.get("/settings")
|
||||||
async def api_get_settings(
|
async def api_get_settings(
|
||||||
admin: Account = Depends(check_admin),
|
admin: Account = Depends(check_admin),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue