-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1699 from planetary-social/lists
Download and parse user lists
- Loading branch information
Showing
20 changed files
with
640 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import Foundation | ||
|
||
/// Errors for an ``AuthorList``. | ||
enum AuthorListError: LocalizedError, Equatable { | ||
/// The event kind is invalid; that is, an ``AuthorList`` can't be created with the given kind. | ||
case invalidKind | ||
|
||
/// The signature is invalid. | ||
case invalidSignature(AuthorList) | ||
|
||
/// The replaceable ID is missing (the `d` tag from the JSON event). | ||
case missingReplaceableID | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import Foundation | ||
import CoreData | ||
|
||
@objc(AuthorList) | ||
public class AuthorList: Event { | ||
static func createOrUpdate( | ||
from jsonEvent: JSONEvent, | ||
in context: NSManagedObjectContext | ||
) throws -> AuthorList { | ||
guard jsonEvent.kind == EventKind.followSet.rawValue else { throw AuthorListError.invalidKind } | ||
guard let replaceableID = jsonEvent.replaceableID else { throw AuthorListError.missingReplaceableID } | ||
let owner = try Author.findOrCreate(by: jsonEvent.pubKey, context: context) | ||
|
||
// Fetch existing AuthorList if it exists | ||
let fetchRequest = AuthorList.authorList(by: replaceableID, owner: owner, kind: EventKind.followSet.rawValue) | ||
let existingAuthorList = try context.fetch(fetchRequest).first | ||
existingAuthorList?.authors = Set() | ||
|
||
let authorList = existingAuthorList ?? AuthorList(context: context) | ||
authorList.createdAt = jsonEvent.createdDate | ||
authorList.author = owner | ||
authorList.owner = owner | ||
authorList.identifier = jsonEvent.id | ||
authorList.replaceableIdentifier = replaceableID | ||
authorList.kind = jsonEvent.kind | ||
authorList.signature = jsonEvent.signature | ||
authorList.allTags = jsonEvent.tags as NSObject | ||
authorList.content = jsonEvent.content | ||
|
||
let tags = jsonEvent.tags | ||
|
||
for tag in tags { | ||
if tag[safe: 0] == "p", let authorID = tag[safe: 1] { | ||
let author = try Author.findOrCreate(by: authorID, context: context) | ||
authorList.addToAuthors(author) | ||
} else if tag[safe: 0] == "title" { | ||
authorList.title = tag[safe: 1] | ||
} else if tag[safe: 0] == "image" { | ||
if let urlString = tag[safe: 1] { | ||
authorList.image = URL(string: urlString) | ||
} else { | ||
authorList.image = nil | ||
} | ||
} else if tag[safe: 0] == "description" { | ||
authorList.listDescription = tag[safe: 1] | ||
} | ||
} | ||
|
||
return authorList | ||
} | ||
|
||
@nonobjc public class func authorList( | ||
by replaceableID: RawReplaceableID, | ||
owner: Author, | ||
kind: Int64 | ||
) -> NSFetchRequest<AuthorList> { | ||
let fetchRequest = NSFetchRequest<AuthorList>(entityName: "AuthorList") | ||
fetchRequest.predicate = NSPredicate( | ||
format: "replaceableIdentifier = %@ AND owner = %@ AND kind = %i", | ||
replaceableID, | ||
owner, | ||
kind | ||
) | ||
fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \AuthorList.identifier, ascending: true)] | ||
fetchRequest.fetchLimit = 1 | ||
return fetchRequest | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
Nos/Models/CoreData/Generated/AuthorList+CoreDataProperties.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import Foundation | ||
import CoreData | ||
|
||
extension AuthorList { | ||
|
||
@nonobjc public class func fetchRequest() -> NSFetchRequest<AuthorList> { | ||
NSFetchRequest<AuthorList>(entityName: "AuthorList") | ||
} | ||
|
||
/// The URL of an image representing the list. | ||
@NSManaged public var image: URL? | ||
|
||
/// The description of the list. | ||
@NSManaged public var listDescription: String? | ||
|
||
/// The title of the list. | ||
@NSManaged public var title: String? | ||
|
||
/// The owner of the list; the ``Author`` who created it. | ||
/// Duplicates ``author`` but Core Data won't allow for multiple relationships to have the same inverse. | ||
@NSManaged public var owner: Author? | ||
|
||
/// The set of unique authors in this list. | ||
@NSManaged public var authors: Set<Author> | ||
} | ||
|
||
// MARK: Generated accessors for authors | ||
extension AuthorList { | ||
|
||
@objc(addAuthorsObject:) | ||
@NSManaged public func addToAuthors(_ value: Author) | ||
|
||
@objc(removeAuthorsObject:) | ||
@NSManaged public func removeFromAuthors(_ value: Author) | ||
|
||
@objc(addAuthors:) | ||
@NSManaged public func addToAuthors(_ values: NSSet) | ||
|
||
@objc(removeAuthors:) | ||
@NSManaged public func removeFromAuthors(_ values: NSSet) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
Nos/Models/CoreData/Nos.xcdatamodeld/Nos 21.xcdatamodel/.xccurrentversion
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>_XCCurrentVersionName</key> | ||
<string>Nos.xcdatamodel</string> | ||
</dict> | ||
</plist> |
56 changes: 56 additions & 0 deletions
56
Nos/Models/CoreData/Nos.xcdatamodeld/Nos 21.xcdatamodel/Nos.xcdatamodel/contents
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> | ||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21513" systemVersion="22D68" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier=""> | ||
<entity name="Author" representedClassName=".Author" syncable="YES" codeGenerationType="category"> | ||
<attribute name="about" optional="YES" attributeType="String"/> | ||
<attribute name="displayName" optional="YES" attributeType="String"/> | ||
<attribute name="hexadecimalPublicKey" attributeType="String"/> | ||
<attribute name="lastUpdatedContactList" optional="YES" attributeType="Date" usesScalarValueType="NO"/> | ||
<attribute name="lastUpdatedMetadata" optional="YES" attributeType="Date" usesScalarValueType="NO"/> | ||
<attribute name="muted" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/> | ||
<attribute name="name" optional="YES" attributeType="String"/> | ||
<attribute name="nip05" optional="YES" attributeType="String"/> | ||
<attribute name="profilePhotoURL" optional="YES" attributeType="URI"/> | ||
<attribute name="rawMetadata" optional="YES" attributeType="Binary"/> | ||
<relationship name="events" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Event" inverseName="author" inverseEntity="Event"/> | ||
<relationship name="followers" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Follow" inverseName="destination" inverseEntity="Follow"/> | ||
<relationship name="follows" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="Follow" inverseName="source" inverseEntity="Follow"/> | ||
<relationship name="relays" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Relay"/> | ||
</entity> | ||
<entity name="AuthorReference" representedClassName="AuthorReference" syncable="YES" codeGenerationType="category"> | ||
<attribute name="pubkey" optional="YES" attributeType="String"/> | ||
<attribute name="recommendedRelayUrl" optional="YES" attributeType="String"/> | ||
<relationship name="event" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Event" inverseName="authorReferences" inverseEntity="Event"/> | ||
</entity> | ||
<entity name="Event" representedClassName=".Event" syncable="YES" codeGenerationType="category"> | ||
<attribute name="allTags" optional="YES" attributeType="Transformable" valueTransformerName="NSSecureUnarchiveFromDataTransformerName"/> | ||
<attribute name="content" optional="YES" attributeType="String"/> | ||
<attribute name="createdAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/> | ||
<attribute name="identifier" attributeType="String"/> | ||
<attribute name="kind" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/> | ||
<attribute name="sendAttempts" optional="YES" attributeType="Integer 16" usesScalarValueType="YES"/> | ||
<attribute name="signature" optional="YES" attributeType="String"/> | ||
<relationship name="author" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Author" inverseName="events" inverseEntity="Author"/> | ||
<relationship name="authorReferences" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="AuthorReference" inverseName="event" inverseEntity="AuthorReference"/> | ||
<relationship name="deletedOn" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Relay"/> | ||
<relationship name="eventReferences" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="EventReference" inverseName="referencingEvent" inverseEntity="EventReference"/> | ||
<relationship name="publishedTo" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Relay"/> | ||
<relationship name="referencingEvents" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="EventReference" inverseName="referencedEvent" inverseEntity="EventReference"/> | ||
</entity> | ||
<entity name="EventReference" representedClassName="EventReference" syncable="YES" codeGenerationType="category"> | ||
<attribute name="eventId" optional="YES" attributeType="String"/> | ||
<attribute name="marker" optional="YES" attributeType="String"/> | ||
<attribute name="recommendedRelayUrl" optional="YES" attributeType="String"/> | ||
<relationship name="referencedEvent" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Event" inverseName="referencingEvents" inverseEntity="Event"/> | ||
<relationship name="referencingEvent" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Event" inverseName="eventReferences" inverseEntity="Event"/> | ||
</entity> | ||
<entity name="Follow" representedClassName=".Follow" syncable="YES" codeGenerationType="category"> | ||
<attribute name="lastUpdated" optional="YES" attributeType="Date" usesScalarValueType="NO"/> | ||
<attribute name="petName" optional="YES" attributeType="String"/> | ||
<relationship name="destination" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Author" inverseName="followers" inverseEntity="Author"/> | ||
<relationship name="source" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Author" inverseName="follows" inverseEntity="Author"/> | ||
</entity> | ||
<entity name="Relay" representedClassName=".Relay" syncable="YES" codeGenerationType="category"> | ||
<attribute name="address" attributeType="String"/> | ||
<attribute name="createdAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/> | ||
</entity> | ||
</model> |
Oops, something went wrong.