refactor!: add missing fields and docs

This commit is contained in:
DevMiner 2024-08-22 23:03:38 +02:00
parent 61891d891a
commit 6e59386f60
73 changed files with 726 additions and 580 deletions

View file

@ -1,51 +0,0 @@
package lysand
import "encoding/json"
type Follow struct {
Entity
// Author is the URL to the user that triggered the follow
Author *URL `json:"author"`
// Followee is the URL to the user that is being followed
Followee *URL `json:"followee"`
}
func (f Follow) MarshalJSON() ([]byte, error) {
type follow Follow
f2 := follow(f)
f2.Type = "Follow"
return json.Marshal(f2)
}
type FollowAccept struct {
Entity
// Author is the URL to the user that accepted the follow
Author *URL `json:"author"`
// Follower is the URL to the user that is now following the followee
Follower *URL `json:"follower"`
}
func (f FollowAccept) MarshalJSON() ([]byte, error) {
type followAccept FollowAccept
f2 := followAccept(f)
f2.Type = "FollowAccept"
return json.Marshal(f2)
}
type FollowReject struct {
Entity
// Author is the URL to the user that rejected the follow
Author *URL `json:"author"`
// Follower is the URL to the user that is no longer following the followee
Follower *URL `json:"follower"`
}
func (f FollowReject) MarshalJSON() ([]byte, error) {
type followReject FollowReject
f2 := followReject(f)
f2.Type = "FollowReject"
return json.Marshal(f2)
}

View file

@ -1,19 +0,0 @@
package lysand
import "encoding/json"
type Undo struct {
Entity
// Author is the URL to the user that triggered the undo action
Author *URL `json:"author"`
// Object is the URL to the object that was undone
Object *URL `json:"object"`
}
func (u Undo) MarshalJSON() ([]byte, error) {
type undo Undo
u2 := undo(u)
u2.Type = "Undo"
return json.Marshal(u2)
}

View file

@ -1,12 +0,0 @@
package lysand
import "encoding/json"
type Note Publication
func (n Note) MarshalJSON() ([]byte, error) {
type note Note
n2 := note(n)
n2.Type = "Note"
return json.Marshal(n2)
}

View file

@ -1,29 +0,0 @@
package lysand
import (
"encoding/json"
"github.com/google/uuid"
)
// Patch is a type that represents a modification to a note. For more information, see the [Spec].
//
// [Spec]: https://lysand.org/objects/patch
type Patch struct {
Note
// PatchedID is the ID of the publication that was patched.
// https://lysand.org/objects/patch#patched-id
PatchedID uuid.UUID `json:"patched_id"`
// PatchedAt is the time that the publication was patched.
// https://lysand.org/objects/patch#patched-at
PatchedAt Time `json:"patched_at"`
}
func (p Patch) MarshalJSON() ([]byte, error) {
type patch Patch
p2 := patch(p)
p2.Type = "Patch"
return json.Marshal(p2)
}

View file

@ -0,0 +1,32 @@
package versia
import (
"encoding/json"
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
)
// Delete signals the deletion of an entity. For more information, see the [Spec].
// This entity does not have a URI.
//
// Implementations must ensure that the author of the Delete entity has the authorization to delete the target entity.
//
// [Spec]: https://versia.pub/entities/delete
type Delete struct {
Entity
// Author is the URL to the user that triggered the deletion
Author *versiautils.URL `json:"author"`
// DeletedType is the type of the object that is being deleted
DeletedType string `json:"deleted_type"`
// Deleted is the URL to the object that is being deleted
Deleted *versiautils.URL `json:"deleted"`
}
func (d Delete) MarshalJSON() ([]byte, error) {
type a Delete
d2 := a(d)
d2.Type = "Delete"
return json.Marshal(d2)
}

View file

@ -0,0 +1,99 @@
package versia
import (
"encoding/json"
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
)
// Follow defines a follow relationship between two users. For more information, see the [Spec].
//
// Once a follow relationship is established, the followee's instance should send all new notes from the followee to
// the follower's inbox.
//
// [Spec]: https://versia.pub/entities/follow
type Follow struct {
Entity
// Author is the URL to the user that triggered the follow
Author *versiautils.URL `json:"author"`
// Followee is the URL to the user that is being followed
Followee *versiautils.URL `json:"followee"`
}
func (f Follow) MarshalJSON() ([]byte, error) {
type follow Follow
f2 := follow(f)
f2.Type = "Follow"
return json.Marshal(f2)
}
// FollowAccept accepts a Follow request, which will form the follow relationship between the two parties.
// For more information, see the [Spec].
//
// This can only be sent by the Followee.
//
// [Spec]: https://versia.pub/entities/follow-accept
type FollowAccept struct {
Entity
// Author is the URL to the user that accepted the follow
Author *versiautils.URL `json:"author"`
// Follower is the URL to the user that is now following the followee
Follower *versiautils.URL `json:"follower"`
}
func (f FollowAccept) MarshalJSON() ([]byte, error) {
type followAccept FollowAccept
f2 := followAccept(f)
f2.Type = "FollowAccept"
return json.Marshal(f2)
}
// FollowReject rejects a Follow request, which will dismiss the follow relationship between the two parties.
// For more information, see the [Spec].
//
// This can only be sent by the Followee and should not be confused with Unfollow, which can only be sent by the Follower.
// FollowReject can still be sent after the relationship has been formed.
//
// [Spec]: https://versia.pub/entities/follow-reject
type FollowReject struct {
Entity
// Author is the URL to the user that rejected the follow
Author *versiautils.URL `json:"author"`
// Follower is the URL to the user that is no longer following the followee
Follower *versiautils.URL `json:"follower"`
}
func (f FollowReject) MarshalJSON() ([]byte, error) {
type followReject FollowReject
f2 := followReject(f)
f2.Type = "FollowReject"
return json.Marshal(f2)
}
// Unfollow disbands request, which will disband the follow relationship between the two parties.
// For more information, see the [Spec].
//
// This can only be sent by the Follower and should not be confused with FollowReject, which can only be sent by the Followee.
//
// [Spec]: https://versia.pub/entities/unfollow
type Unfollow struct {
Entity
// Author is the URL to the user that unfollowed the followee
Author *versiautils.URL `json:"author"`
// Followee is the URL to the user that has been followed
Followee *versiautils.URL `json:"follower"`
}
func (f Unfollow) MarshalJSON() ([]byte, error) {
type a Unfollow
u := a(f)
u.Type = "Unfollow"
return json.Marshal(u)
}

32
pkg/versia/actor_group.go Normal file
View file

@ -0,0 +1,32 @@
package versia
import (
"encoding/json"
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
)
// Group is a way to organize users and notes into communities. For more information, see the [Spec].
//
// [Spec]: https://versia.pub/entities/pub
type Group struct {
Entity
// Name is the group's name / title.
Name versiautils.TextContentTypeMap `json:"name"`
// Description is a description of the group's contents / purpose.
Description versiautils.TextContentTypeMap `json:"description"`
// Members is a list of URLs of the group's members.
Members []versiautils.URL `json:"members"`
// Notes is a URL to the collection of notes associated with this group.
Notes *versiautils.URL `json:"notes"`
}
func (g Group) MarshalJSON() ([]byte, error) {
type a Group
g2 := a(g)
g2.Type = "Group"
return json.Marshal(g2)
}

View file

@ -1,7 +1,9 @@
package lysand
package versia
import (
"encoding/json"
versiacrypto "github.com/lysand-org/versia-go/pkg/versia/crypto"
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
)
// User represents a user object in the Lysand protocol. For more information, see the [Spec].
@ -32,39 +34,39 @@ type User struct {
// Avatar is the avatar of the user in different image content types.
// https://lysand.org/objects/user#avatar
Avatar ImageContentTypeMap `json:"avatar,omitempty"`
Avatar versiautils.ImageContentTypeMap `json:"avatar,omitempty"`
// Header is the header image of the user in different image content types.
// https://lysand.org/objects/user#header
Header ImageContentTypeMap `json:"header,omitempty"`
Header versiautils.ImageContentTypeMap `json:"header,omitempty"`
// Bio is the biography of the user in different text content types.
// https://lysand.org/objects/user#bio
Bio TextContentTypeMap `json:"bio"`
Bio versiautils.TextContentTypeMap `json:"bio"`
// Fields is a list of fields that the user has filled out.
// https://lysand.org/objects/user#fields
Fields []Field `json:"fields,omitempty"`
Fields []UserField `json:"fields,omitempty"`
// Featured is the featured posts of the user.
// https://lysand.org/objects/user#featured
Featured *URL `json:"featured"`
Featured *versiautils.URL `json:"featured"`
// Followers is the followers of the user.
// https://lysand.org/objects/user#followers
Followers *URL `json:"followers"`
Followers *versiautils.URL `json:"followers"`
// Following is the users that the user is following.
// https://lysand.org/objects/user#following
Following *URL `json:"following"`
Following *versiautils.URL `json:"following"`
// Inbox is the inbox of the user.
// https://lysand.org/objects/user#posts
Inbox *URL `json:"inbox"`
Inbox *versiautils.URL `json:"inbox"`
// Outbox is the outbox of the user.
// https://lysand.org/objects/user#outbox
Outbox *URL `json:"outbox"`
Outbox *versiautils.URL `json:"outbox"`
}
func (u User) MarshalJSON() ([]byte, error) {
@ -74,7 +76,50 @@ func (u User) MarshalJSON() ([]byte, error) {
return json.Marshal(u2)
}
type Field struct {
Key TextContentTypeMap `json:"key"`
Value TextContentTypeMap `json:"value"`
type UserField struct {
Key versiautils.TextContentTypeMap `json:"key"`
Value versiautils.TextContentTypeMap `json:"value"`
}
// UserPublicKey represents a public key for a user. For more information, see the [Spec].
//
// [Spec]: https://lysand.org/security/keys#public-key-cryptography
type UserPublicKey struct {
Actor *versiautils.URL `json:"actor"`
// Algorithm can only be `ed25519` for now
Algorithm string `json:"algorithm"`
Key *versiacrypto.SPKIPublicKey `json:"-"`
RawKey json.RawMessage `json:"key"`
}
func (k *UserPublicKey) UnmarshalJSON(raw []byte) error {
type t UserPublicKey
k2 := (*t)(k)
if err := json.Unmarshal(raw, k2); err != nil {
return err
}
var err error
if k2.Key, err = versiacrypto.UnmarshalSPKIPubKey(k2.Algorithm, k2.RawKey); err != nil {
return err
}
*k = UserPublicKey(*k2)
return nil
}
func (k UserPublicKey) MarshalJSON() ([]byte, error) {
type t UserPublicKey
k2 := t(k)
var err error
if k2.RawKey, err = k2.Key.MarshalJSON(); err != nil {
return nil, err
}
return json.Marshal(k2)
}

View file

@ -1,4 +1,4 @@
package lysand
package versia
// Attachment is a file or other piece of content that is attached to a post. For more information, see the [Spec].
//

31
pkg/versia/collection.go Normal file
View file

@ -0,0 +1,31 @@
package versia
import versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
// Collection is a paginated group of entities. For more information, see the [Spec].
//
// [Spec]: https://versia.pub/structures/collection
type Collection[T any] struct {
// Author represents the author of the collection. `nil` is used to represent the instance.
Author *versiautils.URL `json:"author"`
// First is a URI to the first page of the collection.
First *versiautils.URL `json:"first"`
// Last is a URI to the last page of the collection.
// If the collection only has one page, this should be the same as First.
Last *versiautils.URL `json:"last"`
// Total is a count of all entities in the collection across all pages.
Total uint64 `json:"total"`
// Next is a URI to the next page of the collection. If there's no next page, this should be `nil`.
Next *versiautils.URL `json:"next"`
// Previous is a URI to the previous page of the collection. If there's no next page, this should be `nil`.
// FIXME(spec): The spec uses `prev` instead of `previous` as the field name.
Previous *versiautils.URL `json:"previous"`
// Items is a list of T for the current page of the collection.
Items []T `json:"items"`
}

View file

@ -1,4 +1,4 @@
package lysand
package versiacrypto
import (
"crypto/ed25519"

View file

@ -1,4 +1,4 @@
package lysand
package versiacrypto
import (
"encoding/base64"

View file

@ -1,4 +1,4 @@
package lysand
package versiacrypto
import (
"github.com/stretchr/testify/assert"

View file

@ -1,23 +1,30 @@
package lysand
package versiacrypto
import (
"crypto"
"crypto/ed25519"
"encoding/base64"
"fmt"
versiacrypto "github.com/lysand-org/versia-go/pkg/lysand/crypto"
"net/url"
"os"
"strings"
)
// SignatureData is a combination of HTTP method, URL (only url.URL#Path and url.URL#RawQuery are required),
// a nonce and the Base64 encoded SHA256 hash of the request body.
// For more information, see the [Spec].
//
// [Spec]: https://versia.pub/signatures
type SignatureData struct {
// RequestMethod is the *lowercase* HTTP method of the request
RequestMethod string
// Nonce is a random byte array, used to prevent replay attacks
Nonce string
// RawPath is the path of the request, without the query string
URL *url.URL
// Digest is the SHA-256 hash of the request body
Digest []byte
}
@ -31,14 +38,16 @@ func NewSignatureData(method, nonce string, u *url.URL, digest []byte) *Signatur
}
}
// String returns the payload to sign
func (s *SignatureData) String() string {
return fmt.Sprintf("%s %s?%s %s %s", strings.ToLower(s.RequestMethod), s.URL.Path, s.URL.RawQuery, s.Nonce, base64.StdEncoding.EncodeToString(s.Digest))
}
// Validate validate that the SignatureData belongs to the provided public key and matches the provided signature.
func (s *SignatureData) Validate(pubKey crypto.PublicKey, signature []byte) bool {
data := []byte(s.String())
verify, err := versiacrypto.NewVerify(pubKey)
verify, err := NewVerify(pubKey)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
return false
@ -47,15 +56,21 @@ func (s *SignatureData) Validate(pubKey crypto.PublicKey, signature []byte) bool
return verify(data, signature)
}
// Sign signs the SignatureData with the provided private key.
func (s *SignatureData) Sign(privKey ed25519.PrivateKey) []byte {
return ed25519.Sign(privKey, []byte(s.String()))
}
// Signer is an object, with which requests can be signed with the user's private key.
// For more information, see the [Spec].
//
// [Spec]: https://versia.pub/signatures
type Signer struct {
PrivateKey ed25519.PrivateKey
UserURL *url.URL
}
// Sign signs a signature data and returns the headers to inject into the response.
func (s Signer) Sign(signatureData SignatureData) *FederationHeaders {
return &FederationHeaders{
SignedBy: s.UserURL,
@ -64,11 +79,16 @@ func (s Signer) Sign(signatureData SignatureData) *FederationHeaders {
}
}
// Verifier is an object, with which requests can be verified against a user's public key.
// For more information, see the [Spec].
//
// [Spec]: https://versia.pub/signatures
type Verifier struct {
PublicKey crypto.PublicKey
}
// Verify verifies a request against the public key provided to it duration object creation.
func (v Verifier) Verify(method string, u *url.URL, body []byte, fedHeaders *FederationHeaders) bool {
return NewSignatureData(method, fedHeaders.Nonce, u, versiacrypto.SHA256(body)).
return NewSignatureData(method, fedHeaders.Nonce, u, SHA256(body)).
Validate(v.PublicKey, fedHeaders.Signature)
}

View file

@ -1,4 +1,4 @@
package lysand
package versiacrypto
import (
"crypto"
@ -7,49 +7,6 @@ import (
"encoding/json"
)
// UserPublicKey represents a public key for a user. For more information, see the [Spec].
//
// [Spec]: https://lysand.org/security/keys#public-key-cryptography
type UserPublicKey struct {
Actor *URL `json:"actor"`
// Algorithm can only be `ed25519` for now
Algorithm string `json:"algorithm"`
Key *SPKIPublicKey `json:"-"`
RawKey json.RawMessage `json:"key"`
}
func (k *UserPublicKey) UnmarshalJSON(raw []byte) error {
type t UserPublicKey
k2 := (*t)(k)
if err := json.Unmarshal(raw, k2); err != nil {
return err
}
var err error
if k2.Key, err = unmarshalSPKIPubKey(k2.Algorithm, k2.RawKey); err != nil {
return err
}
*k = UserPublicKey(*k2)
return nil
}
func (k UserPublicKey) MarshalJSON() ([]byte, error) {
type t UserPublicKey
k2 := t(k)
var err error
if k2.RawKey, err = k2.Key.MarshalJSON(); err != nil {
return nil, err
}
return json.Marshal(k2)
}
// SPKIPublicKey is a type that represents a [ed25519.PublicKey] in the SPKI
// format.
type SPKIPublicKey struct {
@ -57,7 +14,7 @@ type SPKIPublicKey struct {
Algorithm string
}
func unmarshalSPKIPubKey(algorithm string, raw []byte) (*SPKIPublicKey, error) {
func UnmarshalSPKIPubKey(algorithm string, raw []byte) (*SPKIPublicKey, error) {
rawStr := ""
if err := json.Unmarshal(raw, &rawStr); err != nil {
return nil, err

View file

@ -1,4 +1,4 @@
package lysand
package versiacrypto
import (
"crypto/ed25519"

View file

@ -1,4 +1,4 @@
package lysand
package versiacrypto
func must[In any, Out any](fn func(In) (Out, error), v In) Out {
out, err := fn(v)

View file

@ -1,7 +1,8 @@
package lysand
package versia
import (
"github.com/google/uuid"
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
)
// Entity is the base type for all Lysand entities. For more information, see the [Spec].
@ -15,10 +16,10 @@ type Entity struct {
ID uuid.UUID `json:"id"`
// URI is the URL to the entity
URI *URL `json:"uri"`
URI *versiautils.URL `json:"uri"`
// CreatedAt is the time the entity was created
CreatedAt Time `json:"created_at"`
CreatedAt versiautils.Time `json:"created_at"`
// Extensions is a map of active extensions
// https://lysand.org/objects/server-metadata#extensions

View file

@ -1,4 +1,4 @@
package lysand
package versia
import (
"fmt"

View file

@ -1,4 +1,4 @@
package lysand
package versia
import (
"encoding/json"
@ -16,20 +16,14 @@ func ParseInboxObject(raw json.RawMessage) (any, error) {
}
switch i.Type {
case "Publication":
m := Publication{}
if err := json.Unmarshal(raw, &m); err != nil {
return nil, err
}
return m, nil
case "Note":
m := Note{}
if err := json.Unmarshal(raw, &m); err != nil {
return nil, err
}
return m, nil
case "Patch":
m := Patch{}
case "Group":
m := Group{}
if err := json.Unmarshal(raw, &m); err != nil {
return nil, err
}
@ -52,21 +46,21 @@ func ParseInboxObject(raw json.RawMessage) (any, error) {
return nil, err
}
return m, nil
case "Undo":
m := Undo{}
case "Unfollow":
m := Unfollow{}
if err := json.Unmarshal(raw, &m); err != nil {
return nil, err
}
return m, nil
default:
return nil, ErrUnknownType{Type: i.Type}
return nil, UnknownEntityTypeError{Type: i.Type}
}
}
type ErrUnknownType struct {
type UnknownEntityTypeError struct {
Type string
}
func (e ErrUnknownType) Error() string {
return fmt.Sprintf("unknown inbox object type: %s", e.Type)
func (e UnknownEntityTypeError) Error() string {
return fmt.Sprintf("unknown entity type: %s", e.Type)
}

View file

@ -1,7 +1,9 @@
package lysand
package versia
import (
"encoding/json"
versiacrypto "github.com/lysand-org/versia-go/pkg/versia/crypto"
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
)
// InstanceMetadata represents the metadata of a Lysand instance. For more information, see the [Spec].
@ -29,19 +31,19 @@ type InstanceMetadata struct {
PublicKey InstancePublicKey `json:"public_key"`
// SharedInbox is the URL to the instance's shared inbox
SharedInbox *URL `json:"shared_inbox,omitempty"`
SharedInbox *versiautils.URL `json:"shared_inbox,omitempty"`
// Moderators is a URL to a collection of moderators
Moderators *URL `json:"moderators,omitempty"`
Moderators *versiautils.URL `json:"moderators,omitempty"`
// Admins is a URL to a collection of administrators
Admins *URL `json:"admins,omitempty"`
Admins *versiautils.URL `json:"admins,omitempty"`
// Logo is the URL to the instance's logo
Logo *ImageContentTypeMap `json:"logo,omitempty"`
Logo *versiautils.ImageContentTypeMap `json:"logo,omitempty"`
// Banner is the URL to the instance's banner
Banner *ImageContentTypeMap `json:"banner,omitempty"`
Banner *versiautils.ImageContentTypeMap `json:"banner,omitempty"`
// Software is information about the instance software
Software InstanceSoftware `json:"software"`
@ -79,8 +81,8 @@ type InstancePublicKey struct {
// Algorithm can only be `ed25519` for now
Algorithm string `json:"algorithm"`
Key *SPKIPublicKey `json:"-"`
RawKey json.RawMessage `json:"key"`
Key *versiacrypto.SPKIPublicKey `json:"-"`
RawKey json.RawMessage `json:"key"`
}
func (k *InstancePublicKey) UnmarshalJSON(raw []byte) error {
@ -91,7 +93,7 @@ func (k *InstancePublicKey) UnmarshalJSON(raw []byte) error {
}
var err error
if k2.Key, err = unmarshalSPKIPubKey(k2.Algorithm, k2.RawKey); err != nil {
if k2.Key, err = versiacrypto.UnmarshalSPKIPubKey(k2.Algorithm, k2.RawKey); err != nil {
return nil
}

View file

@ -1,34 +1,41 @@
package lysand
package versia
// PublicationVisibility is the visibility of a publication. For more information, see the [Spec].
//
// [Spec]: https://lysand.org/objects/publications#visibility
type PublicationVisibility string
const (
// PublicationVisiblePublic means that the publication is visible to everyone.
PublicationVisiblePublic PublicationVisibility = "public"
// PublicationVisibleUnlisted means that the publication is visible everyone, but should not appear in public timelines and search results.
PublicationVisibleUnlisted PublicationVisibility = "unlisted"
// PublicationVisibleFollowers means that the publication is visible to followers only.
PublicationVisibleFollowers PublicationVisibility = "followers"
// PublicationVisibleDirect means that the publication is a direct message, and is visible only to the mentioned users.
PublicationVisibleDirect PublicationVisibility = "direct"
import (
"encoding/json"
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
)
// Publication is a publication object. For more information, see the [Spec].
// NoteVisibility is the visibility of a note. For more information, see the [Spec].
//
// [Spec]: https://lysand.org/objects/publications
type Publication struct {
// TODO:
// [Spec]: https://lysand.org/objects/publications#visibility
type NoteVisibility string
const (
// NoteVisiblePublic means that the Note is visible to everyone.
NoteVisiblePublic NoteVisibility = "public"
// NoteVisibleUnlisted means that the Note is visible everyone, but should not appear in public timelines and search results.
NoteVisibleUnlisted NoteVisibility = "unlisted"
// NoteVisibleFollowers means that the Note is visible to followers only.
NoteVisibleFollowers NoteVisibility = "followers"
// NoteVisibleDirect means that the Note is a direct message, and is visible only to the mentioned users.
NoteVisibleDirect NoteVisibility = "direct"
)
// Note is a published message, similar to a tweet (from Twitter) or a toot (from Mastodon).
// For more information, see the [Spec].
//
// [Spec]: https://versia.pub/entities/note
type Note struct {
Entity
// Author is the URL to the user
// https://lysand.org/objects/publications#author
Author *URL `json:"author"`
Author *versiautils.URL `json:"author"`
// Content is the content of the publication
// https://lysand.org/objects/publications#content
Content TextContentTypeMap `json:"content,omitempty"`
Content versiautils.TextContentTypeMap `json:"content,omitempty"`
// Category is the category of the publication
// https://lysand.org/objects/publications#category
@ -44,23 +51,23 @@ type Publication struct {
// Group is the URL to a group
// https://lysand.org/objects/publications#group
Group *URL `json:"group,omitempty"`
Group *versiautils.URL `json:"group,omitempty"`
// Attachments is a list of attachment objects, keyed by their MIME type
// https://lysand.org/objects/publications#attachments
Attachments []ContentTypeMap[Attachment] `json:"attachments,omitempty"`
Attachments []versiautils.ContentTypeMap[Attachment] `json:"attachments,omitempty"`
// RepliesTo is the URL to the publication being replied to
// https://lysand.org/objects/publications#replies-to
RepliesTo *URL `json:"replies_to,omitempty"`
RepliesTo *versiautils.URL `json:"replies_to,omitempty"`
// Quoting is the URL to the publication being quoted
// https://lysand.org/objects/publications#quotes
Quoting *URL `json:"quoting,omitempty"`
Quoting *versiautils.URL `json:"quoting,omitempty"`
// Mentions is a list of URLs to users
// https://lysand.org/objects/publications#mentionshttps://lysand.org/objects/publications#mentions
Mentions []URL `json:"mentions,omitempty"`
Mentions []versiautils.URL `json:"mentions,omitempty"`
// Subject is the subject of the publication
// https://lysand.org/objects/publications#subject
@ -72,27 +79,34 @@ type Publication struct {
// Visibility is the visibility of the publication
// https://lysand.org/objects/publications#visibility
Visibility PublicationVisibility `json:"visibility"`
Visibility NoteVisibility `json:"visibility"`
}
func (p Note) MarshalJSON() ([]byte, error) {
type a Note
n2 := a(p)
n2.Type = "Note"
return json.Marshal(n2)
}
// LinkPreview is a preview of a link. For more information, see the [Spec].
//
// [Spec]: https://lysand.org/objects/publications#types
type LinkPreview struct {
Link URL `json:"link"`
Title string `json:"title"`
Description *string `json:"description"`
Image *URL `json:"image"`
Icon *URL `json:"icon"`
Link *versiautils.URL `json:"link"`
Title string `json:"title"`
Description *string `json:"description"`
Image *versiautils.URL `json:"image"`
Icon *versiautils.URL `json:"icon"`
}
// Device is the device that creates publications. For more information, see the [Spec].
//
// [Spec]: https://lysand.org/objects/publications#types
type Device struct {
Name string `json:"name"`
Version string `json:"version,omitempty"`
URL *URL `json:"url,omitempty"`
Name string `json:"name"`
Version string `json:"version,omitempty"`
URL *versiautils.URL `json:"url,omitempty"`
}
// CategoryType is the type of publication. For more information, see the [Spec].

View file

@ -1,4 +1,4 @@
package lysand
package versiautils
import (
"encoding/json"

View file

@ -1,4 +1,4 @@
package lysand
package versiautils
import (
"encoding/json"

View file

@ -1,4 +1,4 @@
package lysand
package versiautils
import (
"encoding/json"