mirror of
git://jb55.com/damus
synced 2024-10-04 19:00:42 +00:00
Initial NIP-51 Mute List Implementation
This commit is contained in:
parent
7d323b65e4
commit
2a8b9f75c1
@ -157,6 +157,8 @@
|
|||||||
4CEE2B02280B39E800AB5EEF /* EventActionBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */; };
|
4CEE2B02280B39E800AB5EEF /* EventActionBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */; };
|
||||||
4CF0ABD42980996B00D66079 /* Report.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABD32980996B00D66079 /* Report.swift */; };
|
4CF0ABD42980996B00D66079 /* Report.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABD32980996B00D66079 /* Report.swift */; };
|
||||||
4CF0ABD629817F5B00D66079 /* ReportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABD529817F5B00D66079 /* ReportView.swift */; };
|
4CF0ABD629817F5B00D66079 /* ReportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABD529817F5B00D66079 /* ReportView.swift */; };
|
||||||
|
4CF0ABD82981980C00D66079 /* Lists.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABD72981980C00D66079 /* Lists.swift */; };
|
||||||
|
4CF0ABDC2981A19E00D66079 /* ListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABDB2981A19E00D66079 /* ListTests.swift */; };
|
||||||
4FE60CDD295E1C5E00105A1F /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE60CDC295E1C5E00105A1F /* Wallet.swift */; };
|
4FE60CDD295E1C5E00105A1F /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE60CDC295E1C5E00105A1F /* Wallet.swift */; };
|
||||||
6439E014296790CF0020672B /* ProfileZoomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6439E013296790CF0020672B /* ProfileZoomView.swift */; };
|
6439E014296790CF0020672B /* ProfileZoomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6439E013296790CF0020672B /* ProfileZoomView.swift */; };
|
||||||
647D9A8D2968520300A295DE /* SideMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647D9A8C2968520300A295DE /* SideMenuView.swift */; };
|
647D9A8D2968520300A295DE /* SideMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647D9A8C2968520300A295DE /* SideMenuView.swift */; };
|
||||||
@ -391,6 +393,8 @@
|
|||||||
4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventActionBar.swift; sourceTree = "<group>"; };
|
4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventActionBar.swift; sourceTree = "<group>"; };
|
||||||
4CF0ABD32980996B00D66079 /* Report.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Report.swift; sourceTree = "<group>"; };
|
4CF0ABD32980996B00D66079 /* Report.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Report.swift; sourceTree = "<group>"; };
|
||||||
4CF0ABD529817F5B00D66079 /* ReportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportView.swift; sourceTree = "<group>"; };
|
4CF0ABD529817F5B00D66079 /* ReportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportView.swift; sourceTree = "<group>"; };
|
||||||
|
4CF0ABD72981980C00D66079 /* Lists.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Lists.swift; sourceTree = "<group>"; };
|
||||||
|
4CF0ABDB2981A19E00D66079 /* ListTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTests.swift; sourceTree = "<group>"; };
|
||||||
4FE60CDC295E1C5E00105A1F /* Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = "<group>"; };
|
4FE60CDC295E1C5E00105A1F /* Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = "<group>"; };
|
||||||
6439E013296790CF0020672B /* ProfileZoomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileZoomView.swift; sourceTree = "<group>"; };
|
6439E013296790CF0020672B /* ProfileZoomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileZoomView.swift; sourceTree = "<group>"; };
|
||||||
647D9A8C2968520300A295DE /* SideMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideMenuView.swift; sourceTree = "<group>"; };
|
647D9A8C2968520300A295DE /* SideMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideMenuView.swift; sourceTree = "<group>"; };
|
||||||
@ -633,6 +637,7 @@
|
|||||||
4C3A1D3629637E0500558C0F /* PreviewCache.swift */,
|
4C3A1D3629637E0500558C0F /* PreviewCache.swift */,
|
||||||
64FBD06E296255C400D9D3B2 /* Theme.swift */,
|
64FBD06E296255C400D9D3B2 /* Theme.swift */,
|
||||||
4CB8838529656C8B00DC99E7 /* NIP05.swift */,
|
4CB8838529656C8B00DC99E7 /* NIP05.swift */,
|
||||||
|
4CF0ABD72981980C00D66079 /* Lists.swift */,
|
||||||
);
|
);
|
||||||
path = Util;
|
path = Util;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -748,6 +753,7 @@
|
|||||||
4C3EA67A28FF7B3900C48A62 /* InvoiceTests.swift */,
|
4C3EA67A28FF7B3900C48A62 /* InvoiceTests.swift */,
|
||||||
3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */,
|
3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */,
|
||||||
4CB88399297322D200DC99E7 /* DMTests.swift */,
|
4CB88399297322D200DC99E7 /* DMTests.swift */,
|
||||||
|
4CF0ABDB2981A19E00D66079 /* ListTests.swift */,
|
||||||
);
|
);
|
||||||
path = damusTests;
|
path = damusTests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1031,6 +1037,7 @@
|
|||||||
4C5F9114283D694D0052CD1C /* FollowTarget.swift in Sources */,
|
4C5F9114283D694D0052CD1C /* FollowTarget.swift in Sources */,
|
||||||
4CF0ABD629817F5B00D66079 /* ReportView.swift in Sources */,
|
4CF0ABD629817F5B00D66079 /* ReportView.swift in Sources */,
|
||||||
4CB8838629656C8B00DC99E7 /* NIP05.swift in Sources */,
|
4CB8838629656C8B00DC99E7 /* NIP05.swift in Sources */,
|
||||||
|
4CF0ABD82981980C00D66079 /* Lists.swift in Sources */,
|
||||||
4C5C7E6A284EDE2E00A22DF5 /* SearchResultsView.swift in Sources */,
|
4C5C7E6A284EDE2E00A22DF5 /* SearchResultsView.swift in Sources */,
|
||||||
6439E014296790CF0020672B /* ProfileZoomView.swift in Sources */,
|
6439E014296790CF0020672B /* ProfileZoomView.swift in Sources */,
|
||||||
4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */,
|
4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */,
|
||||||
@ -1091,6 +1098,7 @@
|
|||||||
4C363AA02828A8DD006E126D /* LikeTests.swift in Sources */,
|
4C363AA02828A8DD006E126D /* LikeTests.swift in Sources */,
|
||||||
4C90BD1C283AC38E008EE7EF /* Bech32Tests.swift in Sources */,
|
4C90BD1C283AC38E008EE7EF /* Bech32Tests.swift in Sources */,
|
||||||
4CE6DEF827F7A08200C66700 /* damusTests.swift in Sources */,
|
4CE6DEF827F7A08200C66700 /* damusTests.swift in Sources */,
|
||||||
|
4CF0ABDC2981A19E00D66079 /* ListTests.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -12,12 +12,25 @@ import Vault
|
|||||||
let PUBKEY_HRP = "npub"
|
let PUBKEY_HRP = "npub"
|
||||||
let PRIVKEY_HRP = "nsec"
|
let PRIVKEY_HRP = "nsec"
|
||||||
|
|
||||||
|
struct FullKeypair {
|
||||||
|
let pubkey: String
|
||||||
|
let privkey: String
|
||||||
|
}
|
||||||
|
|
||||||
struct Keypair {
|
struct Keypair {
|
||||||
let pubkey: String
|
let pubkey: String
|
||||||
let privkey: String?
|
let privkey: String?
|
||||||
let pubkey_bech32: String
|
let pubkey_bech32: String
|
||||||
let privkey_bech32: String?
|
let privkey_bech32: String?
|
||||||
|
|
||||||
|
func to_full() -> FullKeypair? {
|
||||||
|
guard let privkey = self.privkey else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return FullKeypair(pubkey: pubkey, privkey: privkey)
|
||||||
|
}
|
||||||
|
|
||||||
init(pubkey: String, privkey: String?) {
|
init(pubkey: String, privkey: String?) {
|
||||||
self.pubkey = pubkey
|
self.pubkey = pubkey
|
||||||
self.privkey = privkey
|
self.privkey = privkey
|
||||||
|
91
damus/Util/Lists.swift
Normal file
91
damus/Util/Lists.swift
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
//
|
||||||
|
// Mute.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by William Casarin on 2023-01-25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
func create_or_update_mutelist(keypair: FullKeypair, mprev: NostrEvent?, to_add: String) -> NostrEvent? {
|
||||||
|
return create_or_update_list_event(keypair: keypair, mprev: mprev, to_add: to_add, list_name: "mute", list_type: "p")
|
||||||
|
}
|
||||||
|
|
||||||
|
func remove_from_mutelist(keypair: FullKeypair, prev: NostrEvent, to_remove: String) -> NostrEvent? {
|
||||||
|
return remove_from_list_event(keypair: keypair, prev: prev, to_remove: to_remove, tag_type: "p")
|
||||||
|
}
|
||||||
|
|
||||||
|
func create_or_update_list_event(keypair: FullKeypair, mprev: NostrEvent?, to_add: String, list_name: String, list_type: String) -> NostrEvent? {
|
||||||
|
let pubkey = keypair.pubkey
|
||||||
|
|
||||||
|
if let prev = mprev {
|
||||||
|
if let okprev = ensure_list_name(list: prev, name: list_name), prev.pubkey == keypair.pubkey {
|
||||||
|
return add_to_list_event(keypair: keypair, prev: okprev, to_add: to_add, tag_type: list_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var tags = [["d", list_name], [list_type, to_add]]
|
||||||
|
let ev = NostrEvent(content: "", pubkey: pubkey, kind: 30000, tags: tags)
|
||||||
|
|
||||||
|
ev.tags = tags
|
||||||
|
ev.id = calculate_event_id(ev: ev)
|
||||||
|
ev.sig = sign_event(privkey: keypair.privkey, ev: ev)
|
||||||
|
|
||||||
|
return ev
|
||||||
|
}
|
||||||
|
|
||||||
|
func remove_from_list_event(keypair: FullKeypair, prev: NostrEvent, to_remove: String, tag_type: String) -> NostrEvent? {
|
||||||
|
var exists = false
|
||||||
|
for tag in prev.tags {
|
||||||
|
if tag.count >= 2 && tag[0] == tag_type && tag[1] == to_remove {
|
||||||
|
exists = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure we actually have the pubkey to remove
|
||||||
|
guard exists else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_tags = prev.tags.filter { tag in
|
||||||
|
!(tag.count >= 2 && tag[0] == tag_type && tag[1] == to_remove)
|
||||||
|
}
|
||||||
|
|
||||||
|
let ev = NostrEvent(content: prev.content, pubkey: keypair.pubkey, kind: 30000, tags: new_tags)
|
||||||
|
ev.id = calculate_event_id(ev: ev)
|
||||||
|
ev.sig = sign_event(privkey: keypair.privkey, ev: ev)
|
||||||
|
|
||||||
|
return ev
|
||||||
|
}
|
||||||
|
|
||||||
|
func add_to_list_event(keypair: FullKeypair, prev: NostrEvent, to_add: String, tag_type: String) -> NostrEvent? {
|
||||||
|
for tag in prev.tags {
|
||||||
|
// we are already muting this user
|
||||||
|
if tag.count >= 2 && tag[0] == tag_type && tag[1] == to_add {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let new = NostrEvent(content: prev.content, pubkey: keypair.pubkey, kind: 30000, tags: prev.tags)
|
||||||
|
new.tags.append([tag_type, to_add])
|
||||||
|
new.id = calculate_event_id(ev: new)
|
||||||
|
new.sig = sign_event(privkey: keypair.privkey, ev: new)
|
||||||
|
|
||||||
|
return new
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensure_list_name(list: NostrEvent, name: String) -> NostrEvent? {
|
||||||
|
for tag in list.tags {
|
||||||
|
if tag.count >= 2 && tag[0] == "d" {
|
||||||
|
if tag[1] != name {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list.tags.insert(["d", name], at: 0)
|
||||||
|
|
||||||
|
return list
|
||||||
|
}
|
71
damusTests/ListTests.swift
Normal file
71
damusTests/ListTests.swift
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
//
|
||||||
|
// ListTests.swift
|
||||||
|
// damusTests
|
||||||
|
//
|
||||||
|
// Created by William Casarin on 2023-01-25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
@testable import damus
|
||||||
|
|
||||||
|
final class ListTests: XCTestCase {
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tearDownWithError() throws {
|
||||||
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCreateMuteList() throws {
|
||||||
|
let privkey = "87f313b03f2548e6eaf1c188db47078e08e894252949779b639b28db0891937a"
|
||||||
|
let pubkey = "4b0c29bf96496130c1253102f6870c0eee05db38a257315858272aa43fd19685"
|
||||||
|
let to_mute = "2fa2630fea3d2c188c49f2799fcd92f0e9879ea6a36ae60770a5428ed6c19edd"
|
||||||
|
let keypair = FullKeypair(pubkey: pubkey, privkey: privkey)
|
||||||
|
let mutelist = create_or_update_mutelist(keypair: keypair, mprev: nil, to_add: to_mute)!
|
||||||
|
|
||||||
|
XCTAssertEqual(mutelist.pubkey, pubkey)
|
||||||
|
XCTAssertEqual(mutelist.content, "")
|
||||||
|
XCTAssertEqual(mutelist.tags.count, 2)
|
||||||
|
XCTAssertEqual(mutelist.tags[0][0], "d")
|
||||||
|
XCTAssertEqual(mutelist.tags[0][1], "mute")
|
||||||
|
XCTAssertEqual(mutelist.tags[1][0], "p")
|
||||||
|
XCTAssertEqual(mutelist.tags[1][1], to_mute)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCreateAndRemoveMuteList() throws {
|
||||||
|
let privkey = "87f313b03f2548e6eaf1c188db47078e08e894252949779b639b28db0891937a"
|
||||||
|
let pubkey = "4b0c29bf96496130c1253102f6870c0eee05db38a257315858272aa43fd19685"
|
||||||
|
let to_mute = "2fa2630fea3d2c188c49f2799fcd92f0e9879ea6a36ae60770a5428ed6c19edd"
|
||||||
|
let keypair = FullKeypair(pubkey: pubkey, privkey: privkey)
|
||||||
|
let mutelist = create_or_update_mutelist(keypair: keypair, mprev: nil, to_add: to_mute)!
|
||||||
|
let new = remove_from_mutelist(keypair: keypair, prev: mutelist, to_remove: to_mute)!
|
||||||
|
|
||||||
|
XCTAssertEqual(new.pubkey, pubkey)
|
||||||
|
XCTAssertEqual(new.content, "")
|
||||||
|
XCTAssertEqual(new.tags.count, 1)
|
||||||
|
XCTAssertEqual(new.tags[0][0], "d")
|
||||||
|
XCTAssertEqual(new.tags[0][1], "mute")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAddToExistingMutelist() throws {
|
||||||
|
let privkey = "87f313b03f2548e6eaf1c188db47078e08e894252949779b639b28db0891937a"
|
||||||
|
let pubkey = "4b0c29bf96496130c1253102f6870c0eee05db38a257315858272aa43fd19685"
|
||||||
|
let to_mute = "2fa2630fea3d2c188c49f2799fcd92f0e9879ea6a36ae60770a5428ed6c19edd"
|
||||||
|
let to_mute_2 = "976b4ab41f8634119b4f21f57ef5836a4bef65d0bf72c7ced67b8b170ba4a38d"
|
||||||
|
let keypair = FullKeypair(pubkey: pubkey, privkey: privkey)
|
||||||
|
let mutelist = create_or_update_mutelist(keypair: keypair, mprev: nil, to_add: to_mute)!
|
||||||
|
let new = create_or_update_mutelist(keypair: keypair, mprev: mutelist, to_add: to_mute_2)!
|
||||||
|
|
||||||
|
XCTAssertEqual(new.pubkey, pubkey)
|
||||||
|
XCTAssertEqual(new.content, "")
|
||||||
|
XCTAssertEqual(new.tags.count, 3)
|
||||||
|
XCTAssertEqual(new.tags[0][0], "d")
|
||||||
|
XCTAssertEqual(new.tags[0][1], "mute")
|
||||||
|
XCTAssertEqual(new.tags[1][0], "p")
|
||||||
|
XCTAssertEqual(new.tags[1][1], to_mute)
|
||||||
|
XCTAssertEqual(new.tags[2][0], "p")
|
||||||
|
XCTAssertEqual(new.tags[2][1], to_mute_2)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user