Skip to content

Commit

Permalink
added ContactListEvent and tests (#62)
Browse files Browse the repository at this point in the history
Closes #52
  • Loading branch information
bryanmontz authored Aug 12, 2023
1 parent cb8ac12 commit 3f197ef
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 1 deletion.
60 changes: 60 additions & 0 deletions Sources/NostrSDK/Events/ContactListEvent.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// ContactListEvent.swift
//
//
// Created by Bryan Montz on 8/3/23.
//

import Foundation

/// Describes the permissions that a user has for a given relay.
public struct RelayPermissions: Equatable {

/// Whether or not the user can read from the relay.
public let read: Bool

/// Whether or not the user cn write to the relay.
public let write: Bool

init(read: Bool, write: Bool) {
self.read = read
self.write = write
}

init(dictionary: [AnyHashable: Any]) {
read = dictionary["read"] as? Bool ?? false
write = dictionary["write"] as? Bool ?? false
}
}

/// A special event with kind 3, meaning "contact list" is defined as having a list of p tags, one for each of the followed/known profiles one is following.
///
/// > Note: [NIP-02 Specification](https://github.com/nostr-protocol/nips/blob/master/02.md#contact-list-and-petnames)
public final class ContactListEvent: NostrEvent {

/// Pubkeys for followed/known profiles.
var contactPubkeys: [String] {
tags.filter({ $0.name == .pubkey }).map { $0.value }
}

/// Pubkey tags for followed/known profiles.
var contactPubkeyTags: [Tag] {
tags.filter({ $0.name == .pubkey })
}

/// Relays the user knows about.
///
/// > Warning: This method of storing and accessing a user's relays is out of spec, not preferred,
/// and will be removed in the future. It is provided here for completeness and because of common usage.
@available(*, deprecated, message: "This method of storing and accessing a user's relays is out of spec, not preferred, and will be removed in the future.")
var relays: [String: RelayPermissions] {
guard let contentData = content.data(using: .utf8),
let contentDictionary = try? JSONSerialization.jsonObject(with: contentData) as? [String: [AnyHashable: Any]] else {
return [:]
}
return contentDictionary.reduce(into: [String: RelayPermissions]()) { partialResult, element in
let (key, value) = element
partialResult[key] = RelayPermissions(dictionary: value)
}
}
}
1 change: 1 addition & 0 deletions Sources/NostrSDK/RelayResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ fileprivate struct EventKindMapper: Decodable { // swiftlint:disable:this pr
case .setMetadata: return SetMetadataEvent.self
case .textNote: return TextNoteEvent.self
case .recommendServer: return RecommendServerEvent.self
case .contactList: return ContactListEvent.self
case .repost: return TextNoteRepostEvent.self
case .genericRepost: return GenericRepostEvent.self
default: return NostrEvent.self
Expand Down
29 changes: 28 additions & 1 deletion Tests/NostrSDKTests/EventDecodingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ final class EventDecodingTests: XCTestCase, FixtureLoading {

func testDecodeContactList() throws {

let event: NostrEvent = try decodeFixture(filename: "contact_list")
let event: ContactListEvent = try decodeFixture(filename: "contact_list")

XCTAssertEqual(event.id, "test-id")
XCTAssertEqual(event.pubkey, "test-pubkey")
Expand All @@ -93,6 +93,33 @@ final class EventDecodingTests: XCTestCase, FixtureLoading {
XCTAssertEqual(event.signature, "hex-signature")
}

func testDecodeContactListWithRelays() throws {
let event: ContactListEvent = try decodeFixture(filename: "contact_list_with_relays")

let expectedPubkeys = [
"3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681",
"07ecf9838136fe430fac43fa0860dbc62a0aac0729c5a33df1192ce75e330c9f",
"020f2d21ae09bf35fcdfb65decf1478b846f5f728ab30c5eaabcd6d081a81c3e",
"58c741aa630c2da35a56a77c1d05381908bd10504fdd2d8b43f725efa6d23196",
"59fbee7369df7713dbbfa9bbdb0892c62eba929232615c6ff2787da384cb770f"
]

XCTAssertEqual(event.contactPubkeys, expectedPubkeys)

let firstTag = Tag(name: .pubkey, value: "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681")
XCTAssertEqual(event.contactPubkeyTags.first, firstTag)

let expectedRelays = [
"wss://relay.damus.io": RelayPermissions(read: true, write: true),
"wss://relay.current.fyi": RelayPermissions(read: false, write: true),
"wss://eden.nostr.land": RelayPermissions(read: true, write: true),
"wss://relay.snort.social": RelayPermissions(read: true, write: false),
"wss://nos.lol": RelayPermissions(read: true, write: true)
]

XCTAssertEqual(event.relays, expectedRelays)
}

func testDecodeRepost() throws {

let event: TextNoteRepostEvent = try decodeFixture(filename: "repost")
Expand Down
30 changes: 30 additions & 0 deletions Tests/NostrSDKTests/Fixtures/contact_list_with_relays.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"id": "367d16ca453b07552c3cd4cc553da62e5c6b20c59747417691b7fda4efdb055a",
"pubkey": "07ecf9838136fe430fac43fa0860dbc62a0aac0729c5a33df1192ce75e330c9f",
"created_at": 1681754187,
"kind": 3,
"tags": [
[
"p",
"3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"
],
[
"p",
"07ecf9838136fe430fac43fa0860dbc62a0aac0729c5a33df1192ce75e330c9f"
],
[
"p",
"020f2d21ae09bf35fcdfb65decf1478b846f5f728ab30c5eaabcd6d081a81c3e"
],
[
"p",
"58c741aa630c2da35a56a77c1d05381908bd10504fdd2d8b43f725efa6d23196"
],
[
"p",
"59fbee7369df7713dbbfa9bbdb0892c62eba929232615c6ff2787da384cb770f"
]
],
"content": "{\"wss://relay.damus.io\":{\"write\":true,\"read\":true},\"wss://relay.current.fyi\":{\"write\":true,\"read\":false},\"wss://eden.nostr.land\":{\"write\":true,\"read\":true},\"wss://relay.snort.social\":{\"write\":false,\"read\":true},\"wss://nos.lol\":{\"write\":true,\"read\":true}}",
"sig": "c83838d776595b6b7f31fb11970891402fc69983f88321a19c7f4f2b8891675b4c1eede4d73dc920068d353c90bbd839a34b4b03ebde34a3295c1c4b79094043"
}

0 comments on commit 3f197ef

Please sign in to comment.