🚧 WIP of entry handler split

This commit is contained in:
Maxim Lebedev 2024-02-14 21:50:54 +06:00
parent 1ee30e4d18
commit 3e4b54cf92
Signed by: toby3d
GPG Key ID: 1F14E25B7C119FC5
2 changed files with 78 additions and 64 deletions

View File

@ -77,18 +77,19 @@ func NewApp(logger *log.Logger, config *domain.Config) (*App, error) {
head, tail := urlutil.ShiftPath(r.URL.Path)
switch strings.ToLower(head) {
case "":
contentType, _, _ := mime.ParseMediaType(r.Header.Get(common.HeaderAccept))
case "": // NOTE(toby3d): render home page or redirect to home subfolder.
mediaType, _, _ := mime.ParseMediaType(r.Header.Get(common.HeaderAccept))
switch contentType {
case common.MIMEApplicationLdJSON: // NOTE(toby3d): show entry as ActivityPub object.
switch mediaType {
case common.MIMEApplicationLdJSON:
entryHandler.ServeHTTP(w, r)
return
}
// NOTE(toby3d): read $HOME_CONTENT_DIR/index.md as a source of
// truth and global settings for any child entry.
// NOTE(toby3d): read $HOME_CONTENT_DIR/index.md as a
// source of truth and global settings for any child
// entry.
s, err := siter.Do(r.Context(), domain.LanguageUnd)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)

View File

@ -6,7 +6,6 @@ import (
"mime"
"net/http"
"strings"
"time"
"github.com/go-ap/activitypub"
@ -20,11 +19,20 @@ import (
type (
Handler struct {
entries entry.UseCase
*ThemeHandler
*ActivityPubHandler
sites site.UseCase
entries entry.UseCase
themes theme.UseCase
}
ThemeHandler struct {
themes theme.UseCase
}
ActivityPubHandler struct{}
/* TODO(toby3d)
Profile struct {
*activitypub.Person
@ -47,13 +55,16 @@ type (
// [Discoverability flag]: https://docs.joinmastodon.org/spec/activitypub/#discoverable
Discoverable bool `json:"discoverable"`
}
*/
)
func NewHandler(sites site.UseCase, entries entry.UseCase, themes theme.UseCase) *Handler {
return &Handler{
sites: sites,
entries: entries,
themes: themes,
sites: sites,
entries: entries,
themes: themes,
ThemeHandler: NewThemeHandler(themes),
ActivityPubHandler: NewActivityPubHandler(),
}
}
@ -69,20 +80,68 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
contentType, params, _ := mime.ParseMediaType(r.Header.Get(common.HeaderAccept))
e, err := h.entries.Do(r.Context(), lang, tail)
if err != nil {
if errors.Is(err, entry.ErrNotExist) {
http.NotFound(w, r)
} else {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
return
}
contentType, _, _ := mime.ParseMediaType(r.Header.Get(common.HeaderAccept))
switch contentType {
case common.MIMEApplicationLdJSON: // NOTE(toby3d): show entry as ActivityPub object.
if profile, ok := params["profile"]; ok && profile != "https://www.w3.org/ns/activitystreams" {
http.Error(w, "got '"+profile+"' profile value, want 'https://www.w3.org/ns/activitystreams'",
http.StatusBadRequest)
default:
h.ThemeHandler.Handle(s, e).ServeHTTP(w, r)
case common.MIMEApplicationLdJSON:
h.ActivityPubHandler.Handle(s, e).ServeHTTP(w, r)
}
}
func NewThemeHandler(themes theme.UseCase) *ThemeHandler {
return &ThemeHandler{
themes: themes,
}
}
func (h *ThemeHandler) Handle(s *domain.Site, e *domain.Entry) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// NOTE(toby3d): wrap founded entry into theme template and
// answer to client.
contentLanguage := make([]string, len(e.Translations))
for i := range e.Translations {
contentLanguage[i] = e.Translations[i].Language.Code()
}
w.Header().Set(common.HeaderContentLanguage, strings.Join(contentLanguage, ", "))
template, err := h.themes.Do(r.Context(), s, e)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set(common.HeaderContentType, common.MIMETextHTMLCharsetUTF8)
if err = template(w); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
}
func NewActivityPubHandler() *ActivityPubHandler {
return &ActivityPubHandler{}
}
func (ActivityPubHandler) Handle(s *domain.Site, e *domain.Entry) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set(common.HeaderContentType, common.MIMEApplicationActivityJSONCharsetUTF8)
encoder := json.NewEncoder(w)
/* TODO(toby3d): handle profiles on root page.
if head == "" { // NOTE(toby3d): base URL point to owner Profile.
langRef := activitypub.LangRef(lang.Lang())
person := activitypub.PersonNew(activitypub.IRI(s.BaseURL.String()))
@ -96,58 +155,12 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
e, err := h.entries.Do(r.Context(), lang, tail)
if err != nil {
if errors.Is(err, entry.ErrNotExist) {
http.NotFound(w, r)
} else {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
return
}
*/
resp := activitypub.ObjectNew(activitypub.NoteType)
resp.ID = activitypub.ID(s.BaseURL.JoinPath(e.File.Path()).String())
resp.Content.Add(activitypub.LangRefValueNew(activitypub.NilLangRef, string(e.Content)))
_ = encoder.Encode(resp)
return
}
// NOTE(toby3d): search entry for requested URL and language
// code in subdir.
e, err := h.entries.Do(r.Context(), lang, tail)
if err != nil {
if errors.Is(err, entry.ErrNotExist) {
http.NotFound(w, r)
} else {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
return
}
// NOTE(toby3d): wrap founded entry into theme template and
// answer to client.
contentLanguage := make([]string, len(e.Translations))
for i := range e.Translations {
contentLanguage[i] = e.Translations[i].Language.Code()
}
w.Header().Set(common.HeaderContentLanguage, strings.Join(contentLanguage, ", "))
template, err := h.themes.Do(r.Context(), s, e)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set(common.HeaderContentType, common.MIMETextHTMLCharsetUTF8)
if err = template(w); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
}