mirror of
https://github.com/versia-pub/versia-go.git
synced 2026-03-13 04:29:15 +01:00
chore: rename everything to versia
This commit is contained in:
parent
0223ea0535
commit
3876ad2738
112 changed files with 587 additions and 576 deletions
|
|
@ -2,7 +2,7 @@ package versia
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
|
||||
versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
|
||||
)
|
||||
|
||||
// Delete signals the deletion of an entity. For more information, see the [Spec].
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package versia
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
|
||||
versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
|
||||
)
|
||||
|
||||
// Follow defines a follow relationship between two users. For more information, see the [Spec].
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package versia
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
|
||||
versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
|
||||
)
|
||||
|
||||
// Group is a way to organize users and notes into communities. For more information, see the [Spec].
|
||||
|
|
|
|||
|
|
@ -2,54 +2,44 @@ 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"
|
||||
versiacrypto "github.com/versia-pub/versia-go/pkg/versia/crypto"
|
||||
versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
|
||||
)
|
||||
|
||||
// User represents a user object in the Lysand protocol. For more information, see the [Spec].
|
||||
// User represents a user object in the Versia protocol. For more information, see the [Spec].
|
||||
//
|
||||
// [Spec]: https://lysand.org/objects/user
|
||||
// [Spec]: https://versia.pub/entities/user
|
||||
type User struct {
|
||||
Entity
|
||||
|
||||
// PublicKey is the public key of the user.
|
||||
// https://lysand.org/objects/user#public-key
|
||||
PublicKey UserPublicKey `json:"public_key"`
|
||||
|
||||
// DisplayName is the display name of the user.
|
||||
// https://lysand.org/objects/user#display-name
|
||||
DisplayName *string `json:"display_name,omitempty"`
|
||||
|
||||
// Username is the username of the user. Must be unique on the instance and match the following regex: ^[a-z0-9_-]+$
|
||||
// https://lysand.org/objects/user#username
|
||||
Username string `json:"username"`
|
||||
|
||||
// Indexable is a boolean that indicates whether the user is indexable by search engines.
|
||||
// https://lysand.org/objects/user#indexable
|
||||
Indexable bool `json:"indexable"`
|
||||
|
||||
// ManuallyApprovesFollowers is a boolean that indicates whether the user manually approves followers.
|
||||
// https://lysand.org/objects/user#manually-approves-followers
|
||||
ManuallyApprovesFollowers bool `json:"manually_approves_followers"`
|
||||
|
||||
// Avatar is the avatar of the user in different image content types.
|
||||
// https://lysand.org/objects/user#avatar
|
||||
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 versiautils.ImageContentTypeMap `json:"header,omitempty"`
|
||||
Avatar versiautils.ImageContentMap `json:"avatar,omitempty"`
|
||||
|
||||
// Bio is the biography of the user in different text content types.
|
||||
// https://lysand.org/objects/user#bio
|
||||
Bio versiautils.TextContentTypeMap `json:"bio"`
|
||||
Bio versiautils.TextContentTypeMap `json:"bio,omitempty"`
|
||||
|
||||
// DisplayName is the display name of the user.
|
||||
DisplayName *string `json:"display_name,omitempty"`
|
||||
|
||||
// Fields is a list of fields that the user has filled out.
|
||||
// https://lysand.org/objects/user#fields
|
||||
Fields []UserField `json:"fields,omitempty"`
|
||||
Fields []UserField `json:"fields"`
|
||||
|
||||
// Username is the username of the user. Must be unique on the instance and match the following regex: ^[a-z0-9_-]+$
|
||||
Username string `json:"username"`
|
||||
|
||||
// Header is the header image of the user in different image content types.
|
||||
Header versiautils.ImageContentMap `json:"header,omitempty"`
|
||||
|
||||
// PublicKey is the public key of the user.
|
||||
PublicKey UserPublicKey `json:"public_key"`
|
||||
|
||||
// ManuallyApprovesFollowers is a boolean that indicates whether the user manually approves followers.
|
||||
ManuallyApprovesFollowers *bool `json:"manually_approves_followers,omitempty"`
|
||||
|
||||
// Indexable is a boolean that indicates whether the user is indexable by search engines.
|
||||
Indexable *bool `json:"indexable,omitempty"`
|
||||
|
||||
// Inbox is the inbox of the user.
|
||||
// https://lysand.org/objects/user#posts
|
||||
Inbox *versiautils.URL `json:"inbox"`
|
||||
|
||||
// Collections is a map of all collections for a user
|
||||
|
|
@ -86,7 +76,7 @@ type UserCollections map[UserCollectionType]*versiautils.URL
|
|||
|
||||
// UserPublicKey represents a public key for a user. For more information, see the [Spec].
|
||||
//
|
||||
// [Spec]: https://lysand.org/security/keys#public-key-cryptography
|
||||
// [Spec]: https://versia.pub/signatures
|
||||
type UserPublicKey struct {
|
||||
Actor *versiautils.URL `json:"actor"`
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
package versia
|
||||
|
||||
// Attachment is a file or other piece of content that is attached to a post. For more information, see the [Spec].
|
||||
//
|
||||
// [Spec]: https://lysand.org/structures/content-format
|
||||
type Attachment struct {
|
||||
// URL to the attachment
|
||||
Content string `json:"content"`
|
||||
Description string `json:"description"`
|
||||
Hash DataHash `json:"hash"`
|
||||
Size int `json:"size"`
|
||||
|
||||
// BlurHash is available when the content type is an image
|
||||
BlurHash *string `json:"blurhash,omitempty"`
|
||||
// BlurHash is available when the content type is an image
|
||||
Height *int `json:"height,omitempty"`
|
||||
// BlurHash is available when the content type is an image
|
||||
Width *int `json:"width,omitempty"`
|
||||
|
||||
FPS *int `json:"fps,omitempty"`
|
||||
}
|
||||
|
||||
type DataHash struct {
|
||||
SHA256 string `json:"sha256"`
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package versia
|
||||
|
||||
import versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
|
||||
import versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
|
||||
|
||||
// Collection is a paginated group of entities. For more information, see the [Spec].
|
||||
//
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
"net/url"
|
||||
)
|
||||
|
||||
// FederationHeaders represents the signature header of the Lysand protocol. For more information, see the [Spec].
|
||||
// FederationHeaders represents the signature header of the Versia protocol. For more information, see the [Spec].
|
||||
//
|
||||
// [Spec]: https://versia.pub/signatures#signature-definition
|
||||
type FederationHeaders struct {
|
||||
|
|
|
|||
|
|
@ -2,43 +2,30 @@ package versia
|
|||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
|
||||
versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
|
||||
)
|
||||
|
||||
// Entity is the base type for all Lysand entities. For more information, see the [Spec].
|
||||
// Entity is the base type for all Versia entities. For more information, see the [Spec].
|
||||
//
|
||||
// [Spec]: https://lysand.org/objects#types
|
||||
// [Spec]: https://versia.pub/entities
|
||||
type Entity struct {
|
||||
// Type is the type of the entity
|
||||
Type string `json:"type"`
|
||||
|
||||
// ID is a UUID for the entity
|
||||
ID uuid.UUID `json:"id"`
|
||||
|
||||
// URI is the URL to the entity
|
||||
URI *versiautils.URL `json:"uri"`
|
||||
// Type is the type of the entity
|
||||
Type string `json:"type"`
|
||||
|
||||
// CreatedAt is the time the entity was created
|
||||
CreatedAt versiautils.Time `json:"created_at"`
|
||||
|
||||
// Extensions is a map of active extensions
|
||||
// https://lysand.org/objects/server-metadata#extensions
|
||||
// URI is the URL to the entity
|
||||
URI *versiautils.URL `json:"uri"`
|
||||
|
||||
// Extensions is a map of active extensions for the entity
|
||||
Extensions Extensions `json:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
// Extensions represents the active extensions on an entity. For more information, see the [Spec].
|
||||
//
|
||||
// [Spec]: https://versia.pub/extensions#extension-definition
|
||||
type Extensions map[string]any
|
||||
|
||||
// {
|
||||
// "org.lysand:custom_emojis": {
|
||||
// "emojis": [
|
||||
// {
|
||||
// "name": "neocat_3c",
|
||||
// "url": {
|
||||
// "image/webp": {
|
||||
// "content": "https://cdn.lysand.org/a97727158bf062ad31cbfb02e212ce0c7eca599a2f863276511b8512270b25e8/neocat_3c_256.webp"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ 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"
|
||||
versiacrypto "github.com/versia-pub/versia-go/pkg/versia/crypto"
|
||||
versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
|
||||
)
|
||||
|
||||
// InstanceMetadata represents the metadata of a Lysand instance. For more information, see the [Spec].
|
||||
// InstanceMetadata represents the metadata of a Versia instance. For more information, see the [Spec].
|
||||
//
|
||||
// ! Unlike other entities, instance metadata is not meant to be federated.
|
||||
//
|
||||
|
|
@ -43,15 +43,15 @@ type InstanceMetadata struct {
|
|||
Admins *versiautils.URL `json:"admins,omitempty"`
|
||||
|
||||
// Logo is the URL to the instance's logo
|
||||
Logo *versiautils.ImageContentTypeMap `json:"logo,omitempty"`
|
||||
Logo *versiautils.ImageContentMap `json:"logo,omitempty"`
|
||||
|
||||
// Banner is the URL to the instance's banner
|
||||
Banner *versiautils.ImageContentTypeMap `json:"banner,omitempty"`
|
||||
Banner *versiautils.ImageContentMap `json:"banner,omitempty"`
|
||||
|
||||
// Software is information about the instance software
|
||||
Software InstanceSoftware `json:"software"`
|
||||
|
||||
// Compatibility is information about the instance's compatibility with different Lysand versions
|
||||
// Compatibility is information about the instance's compatibility with different Versia versions
|
||||
Compatibility InstanceCompatibility `json:"compatibility"`
|
||||
}
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ func (s InstanceMetadata) MarshalJSON() ([]byte, error) {
|
|||
return json.Marshal(s2)
|
||||
}
|
||||
|
||||
// InstanceSoftware represents the software of a Lysand instance.
|
||||
// InstanceSoftware represents the software of a Versia instance.
|
||||
type InstanceSoftware struct {
|
||||
// Name is the name of the instance software
|
||||
Name string `json:"name"`
|
||||
|
|
@ -70,9 +70,9 @@ type InstanceSoftware struct {
|
|||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
// InstanceCompatibility represents the compatibility of a Lysand instance.
|
||||
// InstanceCompatibility represents the compatibility of a Versia instance.
|
||||
type InstanceCompatibility struct {
|
||||
// Versions is a list of versions of Lysand the instance is compatible with
|
||||
// Versions is a list of versions of Versia the instance is compatible with
|
||||
Versions []string `json:"versions"`
|
||||
|
||||
// Extensions is a list of extensions supported by the instance
|
||||
|
|
|
|||
|
|
@ -2,23 +2,7 @@ package versia
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
versiautils "github.com/lysand-org/versia-go/pkg/versia/utils"
|
||||
)
|
||||
|
||||
// NoteVisibility is the visibility of a note. For more information, see the [Spec].
|
||||
//
|
||||
// [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"
|
||||
versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
|
||||
)
|
||||
|
||||
// Note is a published message, similar to a tweet (from Twitter) or a toot (from Mastodon).
|
||||
|
|
@ -28,57 +12,42 @@ const (
|
|||
type Note struct {
|
||||
Entity
|
||||
|
||||
// Attachments is a list of attachment objects, keyed by their MIME type
|
||||
Attachments []versiautils.NoteAttachmentContentMap `json:"attachments,omitempty"`
|
||||
|
||||
// Author is the URL to the user
|
||||
// https://lysand.org/objects/publications#author
|
||||
Author *versiautils.URL `json:"author"`
|
||||
|
||||
// Content is the content of the publication
|
||||
// https://lysand.org/objects/publications#content
|
||||
Content versiautils.TextContentTypeMap `json:"content,omitempty"`
|
||||
|
||||
// Category is the category of the publication
|
||||
// https://lysand.org/objects/publications#category
|
||||
// Category is the category of the note
|
||||
Category *CategoryType `json:"category,omitempty"`
|
||||
|
||||
// Device that created the publication
|
||||
// https://lysand.org/objects/publications#device
|
||||
// Content is the content of the note
|
||||
Content versiautils.TextContentTypeMap `json:"content,omitempty"`
|
||||
|
||||
// Device that created the note
|
||||
Device *Device `json:"device,omitempty"`
|
||||
|
||||
// Previews is a list of URLs to preview images
|
||||
// https://lysand.org/objects/publications#previews
|
||||
Previews []LinkPreview `json:"previews,omitempty"`
|
||||
|
||||
// Group is the URL to a group
|
||||
// https://lysand.org/objects/publications#group
|
||||
// TODO: Properly parse these, can be "public" | "followers" as well
|
||||
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 []versiautils.ContentTypeMap[Attachment] `json:"attachments,omitempty"`
|
||||
|
||||
// RepliesTo is the URL to the publication being replied to
|
||||
// https://lysand.org/objects/publications#replies-to
|
||||
RepliesTo *versiautils.URL `json:"replies_to,omitempty"`
|
||||
|
||||
// Quoting is the URL to the publication being quoted
|
||||
// https://lysand.org/objects/publications#quotes
|
||||
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 []versiautils.URL `json:"mentions,omitempty"`
|
||||
|
||||
// Subject is the subject of the publication
|
||||
// https://lysand.org/objects/publications#subject
|
||||
Subject *string `json:"subject,omitempty"`
|
||||
|
||||
// IsSensitive is a boolean indicating whether the publication contains sensitive content
|
||||
// https://lysand.org/objects/publications#is-sensitive
|
||||
// IsSensitive is a boolean indicating whether the note contains sensitive content
|
||||
IsSensitive *bool `json:"is_sensitive,omitempty"`
|
||||
|
||||
// Visibility is the visibility of the publication
|
||||
// https://lysand.org/objects/publications#visibility
|
||||
Visibility NoteVisibility `json:"visibility"`
|
||||
// Mentions is a list of URLs to users
|
||||
Mentions []versiautils.URL `json:"mentions,omitempty"`
|
||||
|
||||
// Previews is a list of URLs to preview images
|
||||
Previews []LinkPreview `json:"previews,omitempty"`
|
||||
|
||||
// Quotes is the URL to the note being quoted
|
||||
Quotes *versiautils.URL `json:"quotes,omitempty"`
|
||||
|
||||
// RepliesTo is the URL to the note being replied to
|
||||
RepliesTo *versiautils.URL `json:"replies_to,omitempty"`
|
||||
|
||||
// Subject is the subject of the note
|
||||
Subject *string `json:"subject,omitempty"`
|
||||
}
|
||||
|
||||
func (p Note) MarshalJSON() ([]byte, error) {
|
||||
|
|
@ -90,27 +59,27 @@ func (p Note) MarshalJSON() ([]byte, error) {
|
|||
|
||||
// LinkPreview is a preview of a link. For more information, see the [Spec].
|
||||
//
|
||||
// [Spec]: https://lysand.org/objects/publications#types
|
||||
// [Spec]: https://versia.pub/entities/note#entity-definition
|
||||
type LinkPreview struct {
|
||||
Link *versiautils.URL `json:"link"`
|
||||
Title string `json:"title"`
|
||||
Description *string `json:"description"`
|
||||
Image *versiautils.URL `json:"image"`
|
||||
Icon *versiautils.URL `json:"icon"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Image *versiautils.URL `json:"image,omitempty"`
|
||||
Icon *versiautils.URL `json:"icon,omitempty"`
|
||||
}
|
||||
|
||||
// Device is the device that creates publications. For more information, see the [Spec].
|
||||
// Device is the device that creates note. For more information, see the [Spec].
|
||||
//
|
||||
// [Spec]: https://lysand.org/objects/publications#types
|
||||
// [Spec]: https://versia.pub/entities/note#entity-definition
|
||||
type Device struct {
|
||||
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].
|
||||
// CategoryType is the type of note. For more information, see the [Spec].
|
||||
//
|
||||
// [Spec]: https://lysand.org/objects/publications#types
|
||||
// [Spec]: https://versia.pub/entities/note#entity-definition
|
||||
type CategoryType string
|
||||
|
||||
const (
|
||||
|
|
|
|||
150
pkg/versia/utils/content_map.go
Normal file
150
pkg/versia/utils/content_map.go
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
package versiautils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
)
|
||||
|
||||
var (
|
||||
validTextContentTypes = []string{"text/html", "text/plain"}
|
||||
validImageContentTypes = []string{"image/png", "image/jpeg", "image/gif", "image/svg+xml"}
|
||||
)
|
||||
|
||||
// ContentMap is a map of content types to their respective content.
|
||||
type ContentMap[T any] map[string]T
|
||||
|
||||
type UnexpectedContentTypeError struct {
|
||||
MIMEType string
|
||||
}
|
||||
|
||||
func (e UnexpectedContentTypeError) Error() string {
|
||||
return fmt.Sprintf("unexpected content type: %s", e.MIMEType)
|
||||
}
|
||||
|
||||
func (m ContentMap[T]) unmarshalJSON(raw []byte, valid []string) error {
|
||||
var cm map[string]json.RawMessage
|
||||
if err := json.Unmarshal(raw, &cm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m = make(ContentMap[T])
|
||||
|
||||
errs := make([]error, 0)
|
||||
for k, v := range cm {
|
||||
if valid != nil {
|
||||
if !slices.Contains(valid, k) {
|
||||
errs = append(errs, UnexpectedContentTypeError{k})
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
var c T
|
||||
if err := json.Unmarshal(v, &c); err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
m[k] = c
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return MultipleError{errs}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m ContentMap[T]) getPreferred(preferred []string) *T {
|
||||
for _, v := range preferred {
|
||||
if c, ok := m[v]; ok {
|
||||
return &c
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TextContent is embedded string. For more information, see the [Spec].
|
||||
//
|
||||
// [Spec]: https://versia.pub/structures/content-format
|
||||
type TextContent struct {
|
||||
Content string `json:"content"`
|
||||
|
||||
// Remote is always false
|
||||
Remote bool `json:"remote"`
|
||||
}
|
||||
type TextContentTypeMap ContentMap[TextContent]
|
||||
|
||||
func (t TextContentTypeMap) UnmarshalJSON(data []byte) error {
|
||||
return (ContentMap[TextContent])(t).unmarshalJSON(data, validTextContentTypes)
|
||||
}
|
||||
|
||||
func (t TextContentTypeMap) String() string {
|
||||
if c := (ContentMap[TextContent])(t).getPreferred(validTextContentTypes); c != nil {
|
||||
return c.Content
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// File is a file or other piece of content. For more information, see the [Spec].
|
||||
//
|
||||
// [Spec]: https://versia.pub/structures/content-format
|
||||
type File struct {
|
||||
// Remote is always true
|
||||
Remote bool `json:"remote"`
|
||||
|
||||
// URL to the attachment
|
||||
Content *URL `json:"content"`
|
||||
Description string `json:"description"`
|
||||
Hash DataHash `json:"hash"`
|
||||
Size int `json:"size"`
|
||||
|
||||
// BlurHash is available when the content type is an image
|
||||
BlurHash *string `json:"blurhash,omitempty"`
|
||||
// BlurHash is available when the content type is an image
|
||||
Height *int `json:"height,omitempty"`
|
||||
// BlurHash is available when the content type is an image
|
||||
Width *int `json:"width,omitempty"`
|
||||
|
||||
FPS *int `json:"fps,omitempty"`
|
||||
}
|
||||
type DataHash struct {
|
||||
SHA256 string `json:"sha256"`
|
||||
}
|
||||
|
||||
type ImageContentMap ContentMap[File]
|
||||
|
||||
func (i ImageContentMap) UnmarshalJSON(data []byte) error {
|
||||
return (ContentMap[File])(i).unmarshalJSON(data, validImageContentTypes)
|
||||
}
|
||||
|
||||
func (i ImageContentMap) String() string {
|
||||
if c := (ContentMap[File])(i).getPreferred(validImageContentTypes); c != nil {
|
||||
return c.Content.String()
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
type NoteAttachmentContentMap ContentMap[File]
|
||||
|
||||
var ErrContentMapEntryNotRemote = errors.New("content map entry not remote")
|
||||
|
||||
func (i NoteAttachmentContentMap) UnmarshalJSON(data []byte) error {
|
||||
if err := (ContentMap[File])(i).unmarshalJSON(data, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
errs := make([]error, 0)
|
||||
for _, a := range i {
|
||||
if !a.Remote {
|
||||
errs = append(errs, ErrContentMapEntryNotRemote)
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return MultipleError{errs}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
package versiautils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"slices"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var (
|
||||
validTextContentTypes = []string{"text/html", "text/plain"}
|
||||
validImageContentTypes = []string{"image/png", "image/jpeg", "image/gif", "image/svg+xml"}
|
||||
)
|
||||
|
||||
// ContentTypeMap is a map of content types to their respective content.
|
||||
type ContentTypeMap[T any] map[string]T
|
||||
|
||||
func (m *ContentTypeMap[T]) unmarshalJSON(raw []byte, valid []string) error {
|
||||
var cm map[string]json.RawMessage
|
||||
if err := json.Unmarshal(raw, &cm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*m = make(ContentTypeMap[T])
|
||||
|
||||
for k, v := range cm {
|
||||
if !slices.Contains(valid, k) {
|
||||
// TODO: replace with logr
|
||||
log.Debug().Caller().Str("mimetype", k).Msg("unexpected content type, skipping")
|
||||
continue
|
||||
}
|
||||
|
||||
var c T
|
||||
if err := json.Unmarshal(v, &c); err != nil {
|
||||
return err
|
||||
}
|
||||
(*m)[k] = c
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m ContentTypeMap[T]) getPreferred(preferred []string) *T {
|
||||
for _, v := range preferred {
|
||||
if c, ok := m[v]; ok {
|
||||
return &c
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type TextContent struct {
|
||||
Content string `json:"content"`
|
||||
}
|
||||
type TextContentTypeMap ContentTypeMap[TextContent]
|
||||
|
||||
func (t *TextContentTypeMap) UnmarshalJSON(data []byte) error {
|
||||
return (*ContentTypeMap[TextContent])(t).unmarshalJSON(data, validTextContentTypes)
|
||||
}
|
||||
|
||||
func (t TextContentTypeMap) String() string {
|
||||
if c := (ContentTypeMap[TextContent])(t).getPreferred(validTextContentTypes); c != nil {
|
||||
return c.Content
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
type ImageContent struct {
|
||||
Content *URL `json:"content"`
|
||||
}
|
||||
type ImageContentTypeMap ContentTypeMap[ImageContent]
|
||||
|
||||
func (i *ImageContentTypeMap) UnmarshalJSON(data []byte) error {
|
||||
return (*ContentTypeMap[ImageContent])(i).unmarshalJSON(data, validImageContentTypes)
|
||||
}
|
||||
|
||||
func (i ImageContentTypeMap) String() string {
|
||||
if c := (ContentTypeMap[ImageContent])(i).getPreferred(validImageContentTypes); c != nil {
|
||||
return c.Content.String()
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
22
pkg/versia/utils/errors.go
Normal file
22
pkg/versia/utils/errors.go
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
package versiautils
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MultipleError struct {
|
||||
Errors []error
|
||||
}
|
||||
|
||||
func (e MultipleError) Error() string {
|
||||
s := strings.Builder{}
|
||||
for i, err := range e.Errors {
|
||||
s.WriteString(err.Error())
|
||||
|
||||
if i != len(e.Errors) {
|
||||
s.WriteRune('\n')
|
||||
}
|
||||
}
|
||||
|
||||
return s.String()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue