diff --git a/Sources/NostrSDK/EventCreating.swift b/Sources/NostrSDK/EventCreating.swift index 64af00b..db99c4c 100644 --- a/Sources/NostrSDK/EventCreating.swift +++ b/Sources/NostrSDK/EventCreating.swift @@ -338,11 +338,11 @@ public extension EventCreating { /// Creates a ``DateBasedCalendarEvent`` (kind 31922) which starts on a date and ends before a different date in the future. /// Its use is appropriate for all-day or multi-day events where time and time zone hold no significance. e.g., anniversary, public holidays, vacation days. /// - Parameters: - /// - name: The name of the calendar event. + /// - title: The title of the calendar event. /// - description: A detailed description of the calendar event. /// - startDate: An inclusive start date. Must be less than end, if it exists. If there are any components other than year, month, /// - endDate: An exclusive end date. If omitted, the calendar event ends on the same date as start. - /// - location: The location of the calendar event. e.g. address, GPS coordinates, meeting room name, link to video call. + /// - locations: The locations of the calendar event. e.g. address, GPS coordinates, meeting room name, link to video call. /// - geohash: The [geohash](https://en.wikipedia.org/wiki/Geohash) to associate calendar event with a searchable physical location. /// - participants: The participants of the calendar event. /// - hashtags: Hashtags to categorize the calendar event. @@ -351,7 +351,7 @@ public extension EventCreating { /// - Returns: The signed ``DateBasedCalendarEvent``. /// /// See [NIP-52](https://github.com/nostr-protocol/nips/blob/master/52.md). - func dateBasedCalendarEvent(withName name: String, description: String = "", startDate: TimeOmittedDate, endDate: TimeOmittedDate? = nil, location: String? = nil, geohash: String? = nil, participants: [CalendarEventParticipant]? = nil, hashtags: [String]? = nil, references: [URL]? = nil, signedBy keypair: Keypair) throws -> DateBasedCalendarEvent { + func dateBasedCalendarEvent(withTitle title: String, description: String = "", startDate: TimeOmittedDate, endDate: TimeOmittedDate? = nil, locations: [String]? = nil, geohash: String? = nil, participants: [CalendarEventParticipant]? = nil, hashtags: [String]? = nil, references: [URL]? = nil, signedBy keypair: Keypair) throws -> DateBasedCalendarEvent { var tags: [Tag] = [] @@ -369,12 +369,12 @@ public extension EventCreating { // and the end date being placed next to the start date. tags = [ Tag(name: .identifier, value: UUID().uuidString), - Tag(name: "name", value: name), + Tag(name: .title, value: title), Tag(name: "start", value: startDate.dateString) ] + tags - if let location { - tags.append(Tag(name: "location", value: location)) + if let locations, !locations.isEmpty { + tags += locations.map { Tag(name: "location", value: $0) } } if let geohash { @@ -398,13 +398,13 @@ public extension EventCreating { /// Creates a ``TimeBasedCalendarEvent`` (kind 31923) which spans between a start time and end time. /// - Parameters: - /// - name: The name of the calendar event. + /// - title: The title of the calendar event. /// - description: A detailed description of the calendar event. /// - startTimestamp: An inclusive start timestamp. /// - endTimestamp: An exclusive end timestamp. If omitted, the calendar event ends instantaneously. /// - startTimeZone: The time zone of the start timestamp. /// - endTimeZone: The time zone of the end timestamp. If omitted and startTimeZone is provided, the time zone of the end timestamp is the same as the start timestamp. - /// - location: The location of the calendar event. e.g. address, GPS coordinates, meeting room name, link to video call. + /// - locations: The locations of the calendar event. e.g. address, GPS coordinates, meeting room name, link to video call. /// - geohash: The [geohash](https://en.wikipedia.org/wiki/Geohash) to associate calendar event with a searchable physical location. /// - participants: The participants of the calendar event. /// - hashtags: Hashtags to categorize the calendar event. @@ -413,7 +413,7 @@ public extension EventCreating { /// - Returns: The signed ``TimeBasedCalendarEvent``. /// /// See [NIP-52](https://github.com/nostr-protocol/nips/blob/master/52.md). - func timeBasedCalendarEvent(withName name: String, description: String = "", startTimestamp: Date, endTimestamp: Date? = nil, startTimeZone: TimeZone? = nil, endTimeZone: TimeZone? = nil, location: String? = nil, geohash: String? = nil, participants: [CalendarEventParticipant]? = nil, hashtags: [String]? = nil, references: [URL]? = nil, signedBy keypair: Keypair) throws -> TimeBasedCalendarEvent { + func timeBasedCalendarEvent(withTitle title: String, description: String = "", startTimestamp: Date, endTimestamp: Date? = nil, startTimeZone: TimeZone? = nil, endTimeZone: TimeZone? = nil, locations: [String]? = nil, geohash: String? = nil, participants: [CalendarEventParticipant]? = nil, hashtags: [String]? = nil, references: [URL]? = nil, signedBy keypair: Keypair) throws -> TimeBasedCalendarEvent { // If the end timestamp is omitted, the calendar event ends instantaneously. if let endTimestamp { @@ -425,7 +425,7 @@ public extension EventCreating { var tags: [Tag] = [ Tag(name: .identifier, value: UUID().uuidString), - Tag(name: "name", value: name), + Tag(name: .title, value: title), Tag(name: "start", value: String(Int64(startTimestamp.timeIntervalSince1970))) ] @@ -442,8 +442,8 @@ public extension EventCreating { tags.append(Tag(name: "end_tzid", value: endTimeZone.identifier)) } - if let location { - tags.append(Tag(name: "location", value: location)) + if let locations, !locations.isEmpty { + tags += locations.map { Tag(name: "location", value: $0) } } if let geohash { diff --git a/Sources/NostrSDK/Events/Calendars/CalendarEventInterpreting.swift b/Sources/NostrSDK/Events/Calendars/CalendarEventInterpreting.swift index 1d3fda1..070ca7e 100644 --- a/Sources/NostrSDK/Events/Calendars/CalendarEventInterpreting.swift +++ b/Sources/NostrSDK/Events/Calendars/CalendarEventInterpreting.swift @@ -7,21 +7,17 @@ import Foundation -public protocol CalendarEventInterpreting: NostrEvent, CalendarEventParticipantInterpreting, HashtagInterpreting, ReferenceTagInterpreting {} +public protocol CalendarEventInterpreting: NostrEvent, CalendarEventParticipantInterpreting, HashtagInterpreting, ReferenceTagInterpreting, IdentifierTagInterpreting, TitleTagInterpreting {} public extension CalendarEventInterpreting { - /// Universally unique identifier (UUID). - var uuid: String? { - tags.first { $0.name == TagName.identifier.rawValue }?.value - } - /// The name of the calendar event. + @available(*, deprecated, message: "This method of naming a calendar event is out of spec, not preferred, and will be removed in the future. Please use only the title field when it is available.") var name: String? { tags.first { $0.name == "name" }?.value } - /// The location of the calendar event. e.g. address, GPS coordinates, meeting room name, link to video call. - var location: String? { - tags.first { $0.name == "location" }?.value + /// The locations of the calendar event. e.g. address, GPS coordinates, meeting room name, link to video call. + var locations: [String] { + tags.filter { $0.name == "location" }.map { $0.value } } /// The [geohash](https://en.wikipedia.org/wiki/Geohash) to associate calendar event with a searchable physical location. diff --git a/Sources/NostrSDK/Events/Calendars/CalendarEventRSVP.swift b/Sources/NostrSDK/Events/Calendars/CalendarEventRSVP.swift new file mode 100644 index 0000000..8b0292b --- /dev/null +++ b/Sources/NostrSDK/Events/Calendars/CalendarEventRSVP.swift @@ -0,0 +1,31 @@ +// +// CalendarEventRSVP.swift +// +// +// Created by Terry Yiu on 12/1/23. +// + +import Foundation + +public final class CalendarEventRSVP: NostrEvent, IdentifierTagInterpreting { + public var calendarEventIdentifier: String? { + // TODO + return nil + } + + public var status: CalendarEventRSVPStatus? { + guard let statusTag = tags.first(where: { $0.name == "l" && $0.otherParameters.first == "status" }) else { + return nil + } + + return CalendarEventRSVPStatus(rawValue: statusTag.value) + } + + public var freebusy: CalendarEventRSVPFreebusy? { + guard let freebusyTag = tags.first(where: { $0.name == "l" && $0.otherParameters.first == "freebusy" }) else { + return nil + } + + return CalendarEventRSVPFreebusy(rawValue: freebusyTag.value) + } +} diff --git a/Sources/NostrSDK/Events/Calendars/CalendarEventRSVPFreebusy.swift b/Sources/NostrSDK/Events/Calendars/CalendarEventRSVPFreebusy.swift new file mode 100644 index 0000000..a6ad83e --- /dev/null +++ b/Sources/NostrSDK/Events/Calendars/CalendarEventRSVPFreebusy.swift @@ -0,0 +1,35 @@ +// +// CalendarEventRSVPFreebusy.swift +// +// +// Created by Terry Yiu on 12/17/23. +// + +import Foundation + +public enum CalendarEventRSVPFreebusy: RawRepresentable, CaseIterable, Codable, Equatable { + + public typealias RawValue = String + + case free + case busy + case unknown(RawValue) + + static public let allCases: AllCases = [ + .free, + .busy + ] + + public init?(rawValue: String) { + self = Self.allCases.first { $0.rawValue == rawValue } + ?? .unknown(rawValue) + } + + public var rawValue: String { + switch self { + case .free: return "free" + case .busy: return "busy" + case let .unknown(value): return value + } + } +} diff --git a/Sources/NostrSDK/Events/Calendars/CalendarEventRSVPStatus.swift b/Sources/NostrSDK/Events/Calendars/CalendarEventRSVPStatus.swift new file mode 100644 index 0000000..c62d7e2 --- /dev/null +++ b/Sources/NostrSDK/Events/Calendars/CalendarEventRSVPStatus.swift @@ -0,0 +1,38 @@ +// +// File.swift +// +// +// Created by Terry Yiu on 12/17/23. +// + +import Foundation + +public enum CalendarEventRSVPStatus: RawRepresentable, CaseIterable, Codable, Equatable { + + public typealias RawValue = String + + case accepted + case declined + case tentative + case unknown(RawValue) + + static public let allCases: AllCases = [ + .accepted, + .declined, + .tentative + ] + + public init?(rawValue: String) { + self = Self.allCases.first { $0.rawValue == rawValue } + ?? .unknown(rawValue) + } + + public var rawValue: String { + switch self { + case .accepted: return "accepted" + case .declined: return "declined" + case .tentative: return "tentative" + case let .unknown(value): return value + } + } +} diff --git a/Sources/NostrSDK/Events/Calendars/CalendarNostrEvent.swift b/Sources/NostrSDK/Events/Calendars/CalendarNostrEvent.swift new file mode 100644 index 0000000..15a2586 --- /dev/null +++ b/Sources/NostrSDK/Events/Calendars/CalendarNostrEvent.swift @@ -0,0 +1,11 @@ +// +// CalendarNostrEvent.swift +// +// +// Created by Terry Yiu on 12/1/23. +// + +import Foundation + +public final class CalendarNostrEvent: NostrEvent, IdentifierTagInterpreting, TitleTagInterpreting { +} diff --git a/Sources/NostrSDK/Events/Tags/IdentifierTagInterpreting.swift b/Sources/NostrSDK/Events/Tags/IdentifierTagInterpreting.swift new file mode 100644 index 0000000..97c1887 --- /dev/null +++ b/Sources/NostrSDK/Events/Tags/IdentifierTagInterpreting.swift @@ -0,0 +1,17 @@ +// +// IdentifierTagInterpreting.swift +// +// +// Created by Terry Yiu on 12/8/23. +// + +import Foundation + +public protocol IdentifierTagInterpreting: NostrEvent {} +public extension IdentifierTagInterpreting { + /// The identifier of the event. For parameterized replaceable events, this identifier remains stable across replacements. + /// This identifier is represented by the ``d`` tag, which is distinctly different from the ``id`` field on ``NostrEvent``. + var identifier: String? { + firstValueForTagName(.identifier) + } +} diff --git a/Sources/NostrSDK/Events/Tags/TitleTagInterpreting.swift b/Sources/NostrSDK/Events/Tags/TitleTagInterpreting.swift new file mode 100644 index 0000000..8885a89 --- /dev/null +++ b/Sources/NostrSDK/Events/Tags/TitleTagInterpreting.swift @@ -0,0 +1,16 @@ +// +// TitleTagInterpreting.swift +// +// +// Created by Terry Yiu on 12/8/23. +// + +import Foundation + +public protocol TitleTagInterpreting: NostrEvent {} +public extension TitleTagInterpreting { + /// The title of the event. + var title: String? { + firstValueForTagName(.title) + } +} diff --git a/Sources/NostrSDK/Tag.swift b/Sources/NostrSDK/Tag.swift index 4cc9570..f6eb98a 100644 --- a/Sources/NostrSDK/Tag.swift +++ b/Sources/NostrSDK/Tag.swift @@ -36,7 +36,7 @@ public enum TagName: String { case summary - /// a title for a long-form content event + /// a title for an event case title /// a web URL the event is referring to in some way. See [NIP-24 - Extra metadata fields and tags](https://github.com/nostr-protocol/nips/blob/master/24.md#tags). diff --git a/Tests/NostrSDKTests/EventCreatingTests.swift b/Tests/NostrSDKTests/EventCreatingTests.swift index 5868e4f..7a9fdc5 100644 --- a/Tests/NostrSDKTests/EventCreatingTests.swift +++ b/Tests/NostrSDKTests/EventCreatingTests.swift @@ -407,13 +407,13 @@ final class EventCreatingTests: XCTestCase, EventCreating, EventVerifying, Fixtu } func testDateBasedCalendarEvent() throws { - let name = "Nostrica" + let title = "Nostrica" let description = "First Nostr unconference" let startDate = try XCTUnwrap(TimeOmittedDate(year: 2023, month: 3, day: 19)) let endDate = try XCTUnwrap(TimeOmittedDate(year: 2023, month: 3, day: 21)) - let location = "Awake, C. Garcias, Provincia de Puntarenas, Uvita, 60504, Costa Rica" + let locations = ["Awake, C. Garcias, Provincia de Puntarenas, Uvita, 60504, Costa Rica", "YouTube"] let geohash = "d1sknt77t3xn" let relayURL = try XCTUnwrap(URL(string: "wss://relay.nostrsdk.com")) @@ -427,11 +427,11 @@ final class EventCreatingTests: XCTestCase, EventCreating, EventVerifying, Fixtu let references = [reference1, reference2] let dateBasedCalendarEvent = try dateBasedCalendarEvent( - withName: name, + withTitle: title, description: description, startDate: startDate, endDate: endDate, - location: location, + locations: locations, geohash: geohash, participants: participants, hashtags: hashtags, @@ -439,11 +439,11 @@ final class EventCreatingTests: XCTestCase, EventCreating, EventVerifying, Fixtu signedBy: Keypair.test ) - XCTAssertEqual(dateBasedCalendarEvent.name, name) + XCTAssertEqual(dateBasedCalendarEvent.title, title) XCTAssertEqual(dateBasedCalendarEvent.content, description) XCTAssertEqual(dateBasedCalendarEvent.startDate, startDate) XCTAssertEqual(dateBasedCalendarEvent.endDate, endDate) - XCTAssertEqual(dateBasedCalendarEvent.location, location) + XCTAssertEqual(dateBasedCalendarEvent.locations, locations) XCTAssertEqual(dateBasedCalendarEvent.geohash, geohash) XCTAssertEqual(dateBasedCalendarEvent.participants, participants) XCTAssertEqual(dateBasedCalendarEvent.hashtags, hashtags) @@ -453,24 +453,24 @@ final class EventCreatingTests: XCTestCase, EventCreating, EventVerifying, Fixtu } func testDateBasedCalendarEventWithStartDateSameAsEndDateShouldFail() throws { - let name = "Nostrica" + let title = "Nostrica" let description = "First Nostr unconference" let timeOmittedDate = try XCTUnwrap(TimeOmittedDate(year: 2023, month: 3, day: 19)) - XCTAssertThrowsError(try dateBasedCalendarEvent(withName: name, description: description, startDate: timeOmittedDate, endDate: timeOmittedDate, signedBy: Keypair.test)) + XCTAssertThrowsError(try dateBasedCalendarEvent(withTitle: title, description: description, startDate: timeOmittedDate, endDate: timeOmittedDate, signedBy: Keypair.test)) } func testDateBasedCalendarEventWithEndDateBeforeStartDateShouldFail() throws { - let name = "Nostrica" + let title = "Nostrica" let description = "First Nostr unconference" let startDate = try XCTUnwrap(TimeOmittedDate(year: 2023, month: 3, day: 19)) let endDate = try XCTUnwrap(TimeOmittedDate(year: 2023, month: 3, day: 18)) - XCTAssertThrowsError(try dateBasedCalendarEvent(withName: name, description: description, startDate: startDate, endDate: endDate, signedBy: Keypair.test)) + XCTAssertThrowsError(try dateBasedCalendarEvent(withTitle: title, description: description, startDate: startDate, endDate: endDate, signedBy: Keypair.test)) } func testTimeBasedCalendarEvent() throws { - let name = "Flight from New York (JFK) to San José, Costa Rica (SJO)" + let title = "Flight from New York (JFK) to San José, Costa Rica (SJO)" let description = "Flight to Nostrica" let startTimeZone = TimeZone(identifier: "America/New_York") @@ -496,13 +496,13 @@ final class EventCreatingTests: XCTestCase, EventCreating, EventVerifying, Fixtu let references = [reference1, reference2] let timeBasedCalendarEvent = try timeBasedCalendarEvent( - withName: name, + withTitle: title, description: description, startTimestamp: startTimestamp, endTimestamp: endTimestamp, startTimeZone: startTimeZone, endTimeZone: endTimeZone, - location: location, + locations: [location], geohash: geohash, participants: participants, hashtags: hashtags, @@ -510,13 +510,13 @@ final class EventCreatingTests: XCTestCase, EventCreating, EventVerifying, Fixtu signedBy: Keypair.test ) - XCTAssertEqual(timeBasedCalendarEvent.name, name) + XCTAssertEqual(timeBasedCalendarEvent.title, title) XCTAssertEqual(timeBasedCalendarEvent.content, description) XCTAssertEqual(timeBasedCalendarEvent.startTimestamp, startTimestamp) XCTAssertEqual(timeBasedCalendarEvent.endTimestamp, endTimestamp) XCTAssertEqual(timeBasedCalendarEvent.startTimeZone, startTimeZone) XCTAssertEqual(timeBasedCalendarEvent.endTimeZone, endTimeZone) - XCTAssertEqual(timeBasedCalendarEvent.location, location) + XCTAssertEqual(timeBasedCalendarEvent.locations, [location]) XCTAssertEqual(timeBasedCalendarEvent.geohash, geohash) XCTAssertEqual(timeBasedCalendarEvent.participants, participants) XCTAssertEqual(timeBasedCalendarEvent.hashtags, hashtags) @@ -526,18 +526,18 @@ final class EventCreatingTests: XCTestCase, EventCreating, EventVerifying, Fixtu } func testTimeBasedCalendarEventWithStartTimestampSameAsEndTimestampShouldFail() throws { - let name = "Flight from New York (JFK) to San José, Costa Rica (SJO)" + let title = "Flight from New York (JFK) to San José, Costa Rica (SJO)" let description = "Flight to Nostrica" let timeZone = TimeZone(identifier: "America/New_York") let dateComponents = DateComponents(calendar: Calendar(identifier: .iso8601), timeZone: timeZone, year: 2023, month: 3, day: 17, hour: 8, minute: 15) let timestamp = try XCTUnwrap(dateComponents.date) - XCTAssertThrowsError(try timeBasedCalendarEvent(withName: name, description: description, startTimestamp: timestamp, endTimestamp: timestamp, signedBy: Keypair.test)) + XCTAssertThrowsError(try timeBasedCalendarEvent(withTitle: title, description: description, startTimestamp: timestamp, endTimestamp: timestamp, signedBy: Keypair.test)) } func testTimeBasedCalendarEventWithEndTimestampBeforeStartTimestampShouldFail() throws { - let name = "Flight from New York (JFK) to San José, Costa Rica (SJO)" + let title = "Flight from New York (JFK) to San José, Costa Rica (SJO)" let description = "Flight to Nostrica" let timeZone = TimeZone(identifier: "America/New_York") @@ -547,6 +547,6 @@ final class EventCreatingTests: XCTestCase, EventCreating, EventVerifying, Fixtu let startTimestamp = try XCTUnwrap(startComponents.date) let endTimestamp = try XCTUnwrap(endComponents.date) - XCTAssertThrowsError(try timeBasedCalendarEvent(withName: name, description: description, startTimestamp: startTimestamp, endTimestamp: endTimestamp, signedBy: Keypair.test)) + XCTAssertThrowsError(try timeBasedCalendarEvent(withTitle: title, description: description, startTimestamp: startTimestamp, endTimestamp: endTimestamp, signedBy: Keypair.test)) } } diff --git a/Tests/NostrSDKTests/EventDecodingTests.swift b/Tests/NostrSDKTests/EventDecodingTests.swift index dcf708f..bb416e3 100644 --- a/Tests/NostrSDKTests/EventDecodingTests.swift +++ b/Tests/NostrSDKTests/EventDecodingTests.swift @@ -335,19 +335,49 @@ final class EventDecodingTests: XCTestCase, FixtureLoading { let publishedAt = try XCTUnwrap(event.publishedAt?.timeIntervalSince1970) XCTAssertEqual(Int64(publishedAt), 1700532108) } - + func testDecodeDateBasedCalendarEvent() throws { let event: DateBasedCalendarEvent = try decodeFixture(filename: "date_based_calendar_event") + XCTAssertEqual(event.id, "a87228880982599ed0f83411e8ea4f6714f35961f32b2274994897c218ad171d") + XCTAssertEqual(event.pubkey, Keypair.test.publicKey.hex) + XCTAssertEqual(event.createdAt, 1702832309) + XCTAssertEqual(event.kind, .dateBasedCalendarEvent) + XCTAssertEqual(event.identifier, "06E43CF4-D253-4AF9-807A-96FDA4763FF4") + XCTAssertEqual(event.title, "Nostrica") + XCTAssertEqual(event.startDate, TimeOmittedDate(year: 2023, month: 3, day: 19)) + XCTAssertEqual(event.endDate, TimeOmittedDate(year: 2023, month: 3, day: 21)) + XCTAssertEqual(event.locations, ["Awake, C. Garcias, Provincia de Puntarenas, Uvita, 60504, Costa Rica", "YouTube"]) + XCTAssertEqual(event.geohash, "d1sknt77t3xn") + + let participants = event.participants + let expectedParticipantPublicKey = Keypair.test.publicKey + let relayURL = URL(string: "wss://relay.nostrsdk.com") + XCTAssertEqual(participants.count, 2) + XCTAssertEqual(participants, + [CalendarEventParticipant(pubkey: expectedParticipantPublicKey, relayURL: relayURL, role: "organizer"), + CalendarEventParticipant(pubkey: expectedParticipantPublicKey, relayURL: relayURL, role: "attendee")]) + + XCTAssertEqual(event.hashtags, ["nostr", "unconference", "nostrica"]) + + XCTAssertEqual(event.references, [URL(string: "https://nostrica.com/"), URL(string: "https://docs.google.com/document/d/1Gsv09gfuwhqhQerIkxeYQ7iOTjOHUC5oTnL2KKyHpR8/edit")]) + + XCTAssertEqual(event.content, "First Nostr unconference") + XCTAssertEqual(event.signature, "b1f04510811195f69552dc1aff5033f306b4fdf9e6e7c1ac265438b457932266414bdf1ed9ec0c2c2f22d56bef7e519af5c3bfb974c933fd20037918b95dc65a") + } + + func testDecodeDeprecatedDateBasedCalendarEvent() throws { + let event: DateBasedCalendarEvent = try decodeFixture(filename: "date_based_calendar_event_deprecated") + XCTAssertEqual(event.id, "14ff9ea332268384f9f72e2623371dd8edf8dd6b8f8b7f0b3d3df29317148d95") XCTAssertEqual(event.pubkey, Keypair.test.publicKey.hex) XCTAssertEqual(event.createdAt, 1700320160) XCTAssertEqual(event.kind, .dateBasedCalendarEvent) - XCTAssertEqual(event.uuid, "6E28808F-43FD-49FE-8B31-350066FD3886") + XCTAssertEqual(event.identifier, "6E28808F-43FD-49FE-8B31-350066FD3886") XCTAssertEqual(event.name, "Nostrica") XCTAssertEqual(event.startDate, TimeOmittedDate(year: 2023, month: 3, day: 19)) XCTAssertEqual(event.endDate, TimeOmittedDate(year: 2023, month: 3, day: 21)) - XCTAssertEqual(event.location, "Awake, C. Garcias, Provincia de Puntarenas, Uvita, 60504, Costa Rica") + XCTAssertEqual(event.locations, ["Awake, C. Garcias, Provincia de Puntarenas, Uvita, 60504, Costa Rica"]) XCTAssertEqual(event.geohash, "d1sknt77t3xn") let participants = event.participants @@ -369,17 +399,49 @@ final class EventDecodingTests: XCTestCase, FixtureLoading { func testDecodeTimeBasedCalendarEvent() throws { let event: TimeBasedCalendarEvent = try decodeFixture(filename: "time_based_calendar_event") + XCTAssertEqual(event.id, "818854c3ff09ac5a2c538cba81d911e59f929dcc5531f61ac92278093d101f1b") + XCTAssertEqual(event.pubkey, Keypair.test.publicKey.hex) + XCTAssertEqual(event.createdAt, 1702833417) + XCTAssertEqual(event.kind, .timeBasedCalendarEvent) + XCTAssertEqual(event.identifier, "798F1F69-1DE3-4623-8DCC-FAF9B773E72B") + XCTAssertEqual(event.title, "Flight from New York (JFK) to San José, Costa Rica (SJO)") + XCTAssertEqual(event.startTimestamp, Date(timeIntervalSince1970: 1679062500)) + XCTAssertEqual(event.endTimestamp, Date(timeIntervalSince1970: 1679067720)) + XCTAssertEqual(event.startTimeZone, TimeZone(identifier: "America/New_York")) + XCTAssertEqual(event.endTimeZone, TimeZone(identifier: "America/Costa_Rica")) + XCTAssertEqual(event.locations, ["John F. Kennedy International Airport, Queens, NY 11430, USA"]) + XCTAssertEqual(event.geohash, "dr5x1p57bg9e") + + let participants = event.participants + let expectedParticipantPublicKey = Keypair.test.publicKey + let relayURL = URL(string: "wss://relay.nostrsdk.com") + XCTAssertEqual(participants.count, 2) + XCTAssertEqual(participants, + [CalendarEventParticipant(pubkey: expectedParticipantPublicKey, relayURL: relayURL, role: "organizer"), + CalendarEventParticipant(pubkey: expectedParticipantPublicKey, relayURL: relayURL, role: "attendee")]) + + XCTAssertEqual(event.hashtags, ["flights", "costarica"]) + + XCTAssertEqual(event.references, [URL(string: "https://nostrica.com/"), URL(string: "https://docs.google.com/document/d/1Gsv09gfuwhqhQerIkxeYQ7iOTjOHUC5oTnL2KKyHpR8/edit")]) + + XCTAssertEqual(event.content, "Flight to Nostrica") + XCTAssertEqual(event.signature, "c2aa36b07c4df050d637dd2be770767c67621e7d87179f9f1e5ef118543328ed238afbd6b33317a61178205b75e6ecb0a61ea4cf6c657a7da0e4cea4842d4c01") + } + + func testDecodeDeprecatedTimeBasedCalendarEvent() throws { + let event: TimeBasedCalendarEvent = try decodeFixture(filename: "time_based_calendar_event_deprecated") + XCTAssertEqual(event.id, "091455f5c9509655e3a4f68f98e807349ac0b5525506b22978566a0bb0f3ced1") XCTAssertEqual(event.pubkey, Keypair.test.publicKey.hex) XCTAssertEqual(event.createdAt, 1700320270) XCTAssertEqual(event.kind, .timeBasedCalendarEvent) - XCTAssertEqual(event.uuid, "9CD6DE6C-F8D9-44FB-B948-CB5A42434F8F") + XCTAssertEqual(event.identifier, "9CD6DE6C-F8D9-44FB-B948-CB5A42434F8F") XCTAssertEqual(event.name, "Flight from New York (JFK) to San José, Costa Rica (SJO)") XCTAssertEqual(event.startTimestamp, Date(timeIntervalSince1970: 1679062500)) XCTAssertEqual(event.endTimestamp, Date(timeIntervalSince1970: 1679067720)) XCTAssertEqual(event.startTimeZone, TimeZone(identifier: "America/New_York")) XCTAssertEqual(event.endTimeZone, TimeZone(identifier: "America/Costa_Rica")) - XCTAssertEqual(event.location, "John F. Kennedy International Airport, Queens, NY 11430, USA") + XCTAssertEqual(event.locations, ["John F. Kennedy International Airport, Queens, NY 11430, USA"]) XCTAssertEqual(event.geohash, "dr5x1p57bg9e") let participants = event.participants diff --git a/Tests/NostrSDKTests/Fixtures/date_based_calendar_event.json b/Tests/NostrSDKTests/Fixtures/date_based_calendar_event.json index 05268f9..22e0ddd 100644 --- a/Tests/NostrSDKTests/Fixtures/date_based_calendar_event.json +++ b/Tests/NostrSDKTests/Fixtures/date_based_calendar_event.json @@ -1,15 +1,15 @@ { - "id": "14ff9ea332268384f9f72e2623371dd8edf8dd6b8f8b7f0b3d3df29317148d95", + "id": "a87228880982599ed0f83411e8ea4f6714f35961f32b2274994897c218ad171d", "pubkey": "9947f9659dd80c3682402b612f5447e28249997fb3709500c32a585eb0977340", - "created_at": 1700320160, + "created_at": 1702832309, "kind": 31922, "tags": [ [ "d", - "6E28808F-43FD-49FE-8B31-350066FD3886" + "06E43CF4-D253-4AF9-807A-96FDA4763FF4" ], [ - "name", + "title", "Nostrica" ], [ @@ -24,6 +24,10 @@ "location", "Awake, C. Garcias, Provincia de Puntarenas, Uvita, 60504, Costa Rica" ], + [ + "location", + "YouTube" + ], [ "g", "d1sknt77t3xn" @@ -62,5 +66,5 @@ ] ], "content": "First Nostr unconference", - "sig": "5cd7174dff637af03b66f46a6ccc19b526d1fdc987583e6c6ced8fd7b2ce56f37510e989b7037dbf75d84cdac5256275e255e97c6ef42534613f2af78f5925dd" -} \ No newline at end of file + "sig": "b1f04510811195f69552dc1aff5033f306b4fdf9e6e7c1ac265438b457932266414bdf1ed9ec0c2c2f22d56bef7e519af5c3bfb974c933fd20037918b95dc65a" +} diff --git a/Tests/NostrSDKTests/Fixtures/date_based_calendar_event_deprecated.json b/Tests/NostrSDKTests/Fixtures/date_based_calendar_event_deprecated.json new file mode 100644 index 0000000..05268f9 --- /dev/null +++ b/Tests/NostrSDKTests/Fixtures/date_based_calendar_event_deprecated.json @@ -0,0 +1,66 @@ +{ + "id": "14ff9ea332268384f9f72e2623371dd8edf8dd6b8f8b7f0b3d3df29317148d95", + "pubkey": "9947f9659dd80c3682402b612f5447e28249997fb3709500c32a585eb0977340", + "created_at": 1700320160, + "kind": 31922, + "tags": [ + [ + "d", + "6E28808F-43FD-49FE-8B31-350066FD3886" + ], + [ + "name", + "Nostrica" + ], + [ + "start", + "2023-03-19" + ], + [ + "end", + "2023-03-21" + ], + [ + "location", + "Awake, C. Garcias, Provincia de Puntarenas, Uvita, 60504, Costa Rica" + ], + [ + "g", + "d1sknt77t3xn" + ], + [ + "p", + "9947f9659dd80c3682402b612f5447e28249997fb3709500c32a585eb0977340", + "wss://relay.nostrsdk.com", + "organizer" + ], + [ + "p", + "9947f9659dd80c3682402b612f5447e28249997fb3709500c32a585eb0977340", + "wss://relay.nostrsdk.com", + "attendee" + ], + [ + "t", + "nostr" + ], + [ + "t", + "unconference" + ], + [ + "t", + "nostrica" + ], + [ + "r", + "https://nostrica.com/" + ], + [ + "r", + "https://docs.google.com/document/d/1Gsv09gfuwhqhQerIkxeYQ7iOTjOHUC5oTnL2KKyHpR8/edit" + ] + ], + "content": "First Nostr unconference", + "sig": "5cd7174dff637af03b66f46a6ccc19b526d1fdc987583e6c6ced8fd7b2ce56f37510e989b7037dbf75d84cdac5256275e255e97c6ef42534613f2af78f5925dd" +} \ No newline at end of file diff --git a/Tests/NostrSDKTests/Fixtures/time_based_calendar_event.json b/Tests/NostrSDKTests/Fixtures/time_based_calendar_event.json index ecc3369..97c0344 100644 --- a/Tests/NostrSDKTests/Fixtures/time_based_calendar_event.json +++ b/Tests/NostrSDKTests/Fixtures/time_based_calendar_event.json @@ -1,15 +1,15 @@ { - "id": "091455f5c9509655e3a4f68f98e807349ac0b5525506b22978566a0bb0f3ced1", + "id": "818854c3ff09ac5a2c538cba81d911e59f929dcc5531f61ac92278093d101f1b", "pubkey": "9947f9659dd80c3682402b612f5447e28249997fb3709500c32a585eb0977340", - "created_at": 1700320270, + "created_at": 1702833417, "kind": 31923, "tags": [ [ "d", - "9CD6DE6C-F8D9-44FB-B948-CB5A42434F8F" + "798F1F69-1DE3-4623-8DCC-FAF9B773E72B" ], [ - "name", + "title", "Flight from New York (JFK) to San José, Costa Rica (SJO)" ], [ @@ -66,5 +66,5 @@ ] ], "content": "Flight to Nostrica", - "sig": "57cdb0735645a7ff7112c2d863c425a75e82b540412117609c1c32bee833622a82acacd836b2790f0f08082e2700cdf1ac363c2aae1db87e613824fea2907845" -} \ No newline at end of file + "sig": "c2aa36b07c4df050d637dd2be770767c67621e7d87179f9f1e5ef118543328ed238afbd6b33317a61178205b75e6ecb0a61ea4cf6c657a7da0e4cea4842d4c01" +} diff --git a/Tests/NostrSDKTests/Fixtures/time_based_calendar_event_deprecated.json b/Tests/NostrSDKTests/Fixtures/time_based_calendar_event_deprecated.json new file mode 100644 index 0000000..ecc3369 --- /dev/null +++ b/Tests/NostrSDKTests/Fixtures/time_based_calendar_event_deprecated.json @@ -0,0 +1,70 @@ +{ + "id": "091455f5c9509655e3a4f68f98e807349ac0b5525506b22978566a0bb0f3ced1", + "pubkey": "9947f9659dd80c3682402b612f5447e28249997fb3709500c32a585eb0977340", + "created_at": 1700320270, + "kind": 31923, + "tags": [ + [ + "d", + "9CD6DE6C-F8D9-44FB-B948-CB5A42434F8F" + ], + [ + "name", + "Flight from New York (JFK) to San José, Costa Rica (SJO)" + ], + [ + "start", + "1679062500" + ], + [ + "end", + "1679067720" + ], + [ + "start_tzid", + "America/New_York" + ], + [ + "end_tzid", + "America/Costa_Rica" + ], + [ + "location", + "John F. Kennedy International Airport, Queens, NY 11430, USA" + ], + [ + "g", + "dr5x1p57bg9e" + ], + [ + "p", + "9947f9659dd80c3682402b612f5447e28249997fb3709500c32a585eb0977340", + "wss://relay.nostrsdk.com", + "organizer" + ], + [ + "p", + "9947f9659dd80c3682402b612f5447e28249997fb3709500c32a585eb0977340", + "wss://relay.nostrsdk.com", + "attendee" + ], + [ + "t", + "flights" + ], + [ + "t", + "costarica" + ], + [ + "r", + "https://nostrica.com/" + ], + [ + "r", + "https://docs.google.com/document/d/1Gsv09gfuwhqhQerIkxeYQ7iOTjOHUC5oTnL2KKyHpR8/edit" + ] + ], + "content": "Flight to Nostrica", + "sig": "57cdb0735645a7ff7112c2d863c425a75e82b540412117609c1c32bee833622a82acacd836b2790f0f08082e2700cdf1ac363c2aae1db87e613824fea2907845" +} \ No newline at end of file