mirror of
https://github.com/versia-pub/versia-go.git
synced 2026-03-13 04:29:15 +01:00
refactor!: add missing fields and docs
This commit is contained in:
parent
61891d891a
commit
6e59386f60
73 changed files with 726 additions and 580 deletions
85
pkg/versia/utils/content_types.go
Normal file
85
pkg/versia/utils/content_types.go
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
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 ""
|
||||
}
|
||||
57
pkg/versia/utils/time.go
Normal file
57
pkg/versia/utils/time.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package versiautils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
const ISO8601 = "2006-01-02T15:04:05.000Z"
|
||||
|
||||
func ParseTime(s string) (Time, error) {
|
||||
t, err := time.Parse(ISO8601, s)
|
||||
return Time(t), err
|
||||
}
|
||||
|
||||
// Time is a type that represents a time in the ISO8601 format.
|
||||
type Time time.Time
|
||||
|
||||
// String returns the time in the ISO8601 format.
|
||||
func (t Time) String() string {
|
||||
return t.ToStd().Format(ISO8601)
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes the time from a string in the ISO8601 format.
|
||||
func (t *Time) UnmarshalJSON(data []byte) error {
|
||||
raw := ""
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
parsed, err := time.Parse(ISO8601, raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*t = Time(parsed)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the time to a string in the ISO8601 format.
|
||||
func (t Time) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.String())
|
||||
}
|
||||
|
||||
// ToStd converts the time to a [time.Time].
|
||||
func (t Time) ToStd() time.Time {
|
||||
return time.Time(t)
|
||||
}
|
||||
|
||||
// TimeFromStd converts a [time.Time] to a Time.
|
||||
func TimeFromStd(u time.Time) Time {
|
||||
return Time(u)
|
||||
}
|
||||
|
||||
func TimeNow() Time {
|
||||
return Time(time.Now())
|
||||
}
|
||||
54
pkg/versia/utils/url.go
Normal file
54
pkg/versia/utils/url.go
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
package versiautils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// URL is a type that represents a URL, represented by a string in JSON, instead of a JSON object.
|
||||
type URL url.URL
|
||||
|
||||
func (u *URL) ResolveReference(ref *url.URL) *URL {
|
||||
return URLFromStd(u.ToStd().ResolveReference(ref))
|
||||
}
|
||||
|
||||
func (u *URL) String() string {
|
||||
return u.ToStd().String()
|
||||
}
|
||||
|
||||
func (u *URL) UnmarshalJSON(data []byte) error {
|
||||
raw := ""
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
parsed, err := url.Parse(raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*u = URL(*parsed)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *URL) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(u.String())
|
||||
}
|
||||
|
||||
func (u *URL) ToStd() *url.URL {
|
||||
return (*url.URL)(u)
|
||||
}
|
||||
|
||||
func URLFromStd(u *url.URL) *URL {
|
||||
return (*URL)(u)
|
||||
}
|
||||
|
||||
func ParseURL(raw string) (*URL, error) {
|
||||
parsed, err := url.Parse(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return URLFromStd(parsed), nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue