Net-Nostr
view release on metacpan or search on metacpan
lib/Net/Nostr/Calendar.pm view on Meta::CPAN
["31922:$pk:vacation-2024", 'wss://relay'],
],
);
# RSVP (kind 31925)
my $rsvp = Net::Nostr::Calendar->rsvp(
pubkey => $hex_pubkey,
identifier => 'rsvp-1',
event_coord => "31922:$organizer_pk:vacation-2024",
status => 'accepted',
fb => 'busy',
);
# Parse any calendar event
my $parsed = Net::Nostr::Calendar->from_event($event);
# Validate
Net::Nostr::Calendar->validate($event);
=head1 DESCRIPTION
lib/Net/Nostr/Calendar.pm view on Meta::CPAN
=head2 rsvp
my $event = Net::Nostr::Calendar->rsvp(
pubkey => $hex_pubkey, # required
identifier => $id, # required (d tag)
event_coord => $coord, # required (a tag)
status => 'accepted', # required
event_relay => $url, # optional (a tag relay)
event_id => $eid, # optional (e tag)
event_id_relay => $url, # optional (e tag relay)
fb => 'busy', # optional (free/busy)
event_author => $pk, # optional (p tag)
event_author_relay => $url, # optional (p tag relay)
content => $note, # optional, defaults to ''
);
Creates a kind 31925 RSVP L<Net::Nostr::Event>. C<status> must be
C<accepted>, C<declined>, or C<tentative>. The C<fb> tag is
automatically omitted when C<status> is C<declined>.
=head2 from_event
lib/Net/Nostr/Calendar.pm view on Meta::CPAN
=head2 event_id
The specific calendar event revision ID (C<e> tag value, RSVP only).
=head2 status
RSVP status: C<accepted>, C<declined>, or C<tentative>.
=head2 fb
Free/busy indicator: C<free> or C<busy>. Must be omitted or ignored if
C<status> is C<declined>.
=head2 event_author
Pubkey of the calendar event author (RSVP only).
=head1 SEE ALSO
L<NIP-52|https://github.com/nostr-protocol/nips/blob/master/52.md>,
L<Net::Nostr>, L<Net::Nostr::Event>
t/51-Calendar.t view on Meta::CPAN
# POD example: rsvp
###############################################################################
subtest 'POD: rsvp' => sub {
my $organizer_pk = 'c' x 64;
my $rsvp = Net::Nostr::Calendar->rsvp(
pubkey => $PK,
identifier => 'rsvp-1',
event_coord => "31922:${organizer_pk}:vacation-2024",
status => 'accepted',
fb => 'busy',
);
is($rsvp->kind, 31925, 'kind');
};
###############################################################################
# POD example: from_event
###############################################################################
subtest 'POD: from_event' => sub {
my $event = Net::Nostr::Calendar->date_event(
'public key matches spec';
is $key->privkey_nsec, 'nsec10allq0gjx7fddtzef0ax00mdps9t2kmtrldkyjfs8l5xruwvh2dq0lhhkp',
'nsec matches spec';
is $key->pubkey_npub, 'npub1zutzeysacnf9rru6zqwmxd54mud0k44tst6l70ja5mhv8jjumytsd2x7nu',
'npub matches spec';
};
# --- Test vector 2 from NIP-06 spec ---
subtest 'test vector 2: 24-word mnemonic' => sub {
my $mnemonic = 'what bleak badge arrange retreat wolf trade produce cricket blur garlic valid proud rude strong choose busy staff weather area salt hollow arm fade';
my $key = Net::Nostr::Key->from_mnemonic($mnemonic);
is $key->privkey_hex, 'c15d739894c81a2fcfd3a2df85a0d2c0dbc47a280d092799f144d73d7ae78add',
'private key matches spec';
is $key->pubkey_hex, 'd41b22899549e1f3d335a31002cfd382174006e166d3e658e3a5eecdb6463573',
'public key matches spec';
is $key->privkey_nsec, 'nsec1c9wh8xy5eqdzln7n5t0ctgxjcrdug73gp5yj0x03gntn67h83twssdfhel',
'nsec matches spec';
is $key->pubkey_npub, 'npub16sdj9zv4f8sl85e45vgq9n7nsgt5qphpvmf7vk8r5hhvmdjxx4es8rq74h',
'npub matches spec';
my $event = Net::Nostr::Calendar->rsvp(
pubkey => $PK,
identifier => 'test',
event_coord => "31922:${PK}:test",
status => 'tentative',
);
my @s = grep { $_->[0] eq 'status' } @{$event->tags};
is($s[0][1], 'tentative', 'tentative');
};
# Spec: fb tag (optional) free/busy
subtest 'rsvp: fb tag busy' => sub {
my $event = Net::Nostr::Calendar->rsvp(
pubkey => $PK,
identifier => 'test',
event_coord => "31922:${PK}:test",
status => 'accepted',
fb => 'busy',
);
my @fb = grep { $_->[0] eq 'fb' } @{$event->tags};
is($fb[0][1], 'busy', 'fb busy');
};
subtest 'rsvp: fb tag free' => sub {
my $event = Net::Nostr::Calendar->rsvp(
pubkey => $PK,
identifier => 'test',
event_coord => "31922:${PK}:test",
status => 'accepted',
fb => 'free',
);
my @fb = grep { $_->[0] eq 'fb' } @{$event->tags};
is($fb[0][1], 'free', 'fb free');
};
subtest 'rsvp: fb tag omitted when status declined' => sub {
my $event = Net::Nostr::Calendar->rsvp(
pubkey => $PK,
identifier => 'test',
event_coord => "31922:${PK}:test",
status => 'declined',
fb => 'busy',
);
my @fb = grep { $_->[0] eq 'fb' } @{$event->tags};
is(scalar @fb, 0, 'fb omitted when declined');
};
# Spec: p tag (optional) pubkey of calendar event author
subtest 'rsvp: p tag (optional)' => sub {
my $author = 'b' x 64;
my $event = Net::Nostr::Calendar->rsvp(
pubkey => $PK,
my $eid = 'b' x 64;
my $author = 'c' x 64;
my $event = Net::Nostr::Calendar->rsvp(
pubkey => $PK,
identifier => 'random-identifier',
event_coord => "31922:${author}:d-identifier",
event_relay => 'wss://relay.example.com',
event_id => $eid,
event_id_relay => 'wss://relay.example.com',
status => 'accepted',
fb => 'busy',
event_author => $author,
event_author_relay => 'wss://relay.example.com',
content => 'note',
);
is($event->kind, 31925, 'kind');
is($event->content, 'note', 'content');
my @e = grep { $_->[0] eq 'e' } @{$event->tags};
is($e[0][1], $eid, 'e tag');
my @a = grep { $_->[0] eq 'a' } @{$event->tags};
is($a[0][1], "31922:${author}:d-identifier", 'a tag');
my @d = grep { $_->[0] eq 'd' } @{$event->tags};
is($d[0][1], 'random-identifier', 'd');
my @s = grep { $_->[0] eq 'status' } @{$event->tags};
is($s[0][1], 'accepted', 'status');
my @fb = grep { $_->[0] eq 'fb' } @{$event->tags};
is($fb[0][1], 'busy', 'fb');
my @p = grep { $_->[0] eq 'p' } @{$event->tags};
is($p[0][1], $author, 'p tag');
};
###############################################################################
# from_event: round-trip parsing
###############################################################################
subtest 'from_event: date event round-trip' => sub {
( run in 1.891 second using v1.01-cache-2.11-cpan-39bf76dae61 )