Skip to content

Commit

Permalink
feat: call postSaveEntry on sync storage
Browse files Browse the repository at this point in the history
  • Loading branch information
hacdias committed Feb 10, 2025
1 parent 57fcc19 commit 94ce17f
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 171 deletions.
169 changes: 169 additions & 0 deletions server/entries.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package server

import (
"context"
"fmt"
"io"
"net/http"

"github.com/gabriel-vasile/mimetype"
"github.com/karlseguin/typed"
"github.com/samber/lo"
"go.hacdias.com/eagle/core"
"go.hacdias.com/eagle/services/media"
"go.hacdias.com/indielib/micropub"
)

func (s *Server) getEntryPhotos(e *core.Entry) ([]Photo, error) {
var photos []Photo

for i, photo := range e.Photos {
if i >= 4 {
break
}

photoUrl, err := s.media.GetImageURL(photo.URL, media.FormatJPEG, media.Width1000)
if err != nil {
return nil, err
}

res, err := http.Get(photoUrl)
if err != nil {
return nil, err
}

data, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}

err = res.Body.Close()
if err != nil {
return nil, err
}

mime := mimetype.Detect(data)
if mime == nil {
return nil, fmt.Errorf("cannot detect mimetype of %s", photo)
}

photos = append(photos, Photo{
Data: data,
MimeType: mime.String(),
})
}

return photos, nil
}

func (s *Server) syndicate(e *core.Entry, syndicators []string) {
// Get the photos to use during syndication
photos, err := s.getEntryPhotos(e)
if err != nil {
s.log.Errorw("failed to get photos for syndication", "entry", e.ID, "err", err)
return
}

// Include syndicators that have already been used for this post
for name, syndicator := range s.syndicators {
if syndicator.IsSyndicated(e) {
syndicators = append(syndicators, name)
}
}

// Do the actual syndication
syndications := typed.New(e.Other).Strings(SyndicationField)
for _, name := range syndicators {
if syndicator, ok := s.syndicators[name]; ok {
syndication, removed, err := syndicator.Syndicate(context.Background(), e, photos)
if err != nil {
s.log.Errorw("failed to syndicate", "entry", e.ID, "syndicator", name, "err", err)
continue
}

if removed {
syndications = lo.Without(syndications, syndication)
} else {
syndications = append(syndications, syndication)
}
}
}

syndications = lo.Uniq(syndications)
if len(syndications) == 0 {
delete(e.Other, SyndicationField)
} else {
e.Other[SyndicationField] = lo.Uniq(syndications)
}

err = s.core.SaveEntry(e)
if err != nil {
s.log.Errorw("failed save entry", "id", e.ID, "err", err)
}
}

func (s *Server) preSaveEntry(e *core.Entry) error {
for name, plugin := range s.plugins {
hookPlugin, ok := plugin.(HookPlugin)
if !ok {
continue
}

err := hookPlugin.PreSaveHook(e)
if err != nil {
return fmt.Errorf("plugin %s error: %w", name, err)
}
}

return nil
}

func (s *Server) postSaveEntry(e *core.Entry, req *micropub.Request, oldTargets []string, skipBuild bool) {
// Syndications
var syndicateTo []string
if req != nil {
syndicateTo, _ = getRequestSyndicateTo(req)
}
s.syndicate(e, syndicateTo)

// Post-save hooks
for name, plugin := range s.plugins {
hookPlugin, ok := plugin.(HookPlugin)
if !ok {
continue
}

err := hookPlugin.PostSaveHook(e)
if err != nil {
s.log.Errorw("plugin post save hook failed", "plugin", name, "err", err)
}
}

// Search indexing
if s.meilisearch != nil {
var err error
if e.Deleted() {
err = s.meilisearch.Remove(e.ID)
} else {
err = s.meilisearch.Add(e)
}
if err != nil {
s.log.Errorw("meilisearch sync failed", "err", err)
}
}

// Rebuild
if !skipBuild && !e.Deleted() && !e.Draft {
s.build(false)
}

// No further action for drafts or no webmentions
if e.Draft || e.NoWebmentions {
return
}

err := s.core.SendWebmentions(e.Permalink, oldTargets...)
if err != nil {
s.log.Errorw("failed to send webmentions", "id", e.ID, "err", err)
}
}
163 changes: 4 additions & 159 deletions server/micropub.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,16 @@ import (
"context"
"errors"
"fmt"
"io"
"net/http"
"path/filepath"
"reflect"
"strings"
"time"

"github.com/araddon/dateparse"
"github.com/gabriel-vasile/mimetype"
"github.com/karlseguin/typed"
"github.com/samber/lo"
"go.hacdias.com/eagle/core"
"go.hacdias.com/eagle/services/media"
"go.hacdias.com/indielib/micropub"
)

Expand Down Expand Up @@ -131,7 +128,7 @@ func (m *micropubServer) Create(req *micropub.Request) (string, error) {
e.Other[m.s.c.Micropub.ChannelsTaxonomy], _ = getRequestChannels(req)
}

err = m.preSave(e)
err = m.s.preSaveEntry(e)
if err != nil {
return "", err
}
Expand All @@ -146,7 +143,7 @@ func (m *micropubServer) Create(req *micropub.Request) (string, error) {
return "", err
}

go m.postSave(e, req, nil)
go m.s.postSaveEntry(e, req, nil, false)
return e.Permalink, nil
}

Expand Down Expand Up @@ -209,7 +206,7 @@ func (m *micropubServer) update(permalink string, req *micropub.Request, update
return nil
}

err = m.preSave(e)
err = m.s.preSaveEntry(e)
if err != nil {
return err
}
Expand All @@ -224,162 +221,10 @@ func (m *micropubServer) update(permalink string, req *micropub.Request, update
return err
}

go m.postSave(e, req, targets)
go m.s.postSaveEntry(e, req, targets, false)
return nil
}

func (m *micropubServer) getPhotos(e *core.Entry) ([]Photo, error) {
var photos []Photo

for i, photo := range e.Photos {
if i >= 4 {
break
}

photoUrl, err := m.s.media.GetImageURL(photo.URL, media.FormatJPEG, media.Width1000)
if err != nil {
return nil, err
}

res, err := http.Get(photoUrl)
if err != nil {
return nil, err
}

data, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}

err = res.Body.Close()
if err != nil {
return nil, err
}

mime := mimetype.Detect(data)
if mime == nil {
return nil, fmt.Errorf("cannot detect mimetype of %s", photo)
}

photos = append(photos, Photo{
Data: data,
MimeType: mime.String(),
})
}

return photos, nil
}

func (m *micropubServer) syndicate(e *core.Entry, syndicators []string) {
// Get the photos to use during syndication
photos, err := m.getPhotos(e)
if err != nil {
m.s.log.Errorw("failed to get photos for syndication", "entry", e.ID, "err", err)
return
}

// Include syndicators that have already been used for this post
for name, syndicator := range m.s.syndicators {
if syndicator.IsSyndicated(e) {
syndicators = append(syndicators, name)
}
}

// Do the actual syndication
syndications := typed.New(e.Other).Strings(SyndicationField)
for _, name := range syndicators {
if syndicator, ok := m.s.syndicators[name]; ok {
syndication, removed, err := syndicator.Syndicate(context.Background(), e, photos)
if err != nil {
m.s.log.Errorw("failed to syndicate", "entry", e.ID, "syndicator", name, "err", err)
continue
}

if removed {
syndications = lo.Without(syndications, syndication)
} else {
syndications = append(syndications, syndication)
}
}
}

syndications = lo.Uniq(syndications)
if len(syndications) == 0 {
delete(e.Other, SyndicationField)
} else {
e.Other[SyndicationField] = lo.Uniq(syndications)
}

err = m.s.core.SaveEntry(e)
if err != nil {
m.s.log.Errorw("failed save entry", "id", e.ID, "err", err)
}
}

func (m *micropubServer) preSave(e *core.Entry) error {
for name, plugin := range m.s.plugins {
hookPlugin, ok := plugin.(HookPlugin)
if !ok {
continue
}

err := hookPlugin.PreSaveHook(e)
if err != nil {
return fmt.Errorf("plugin %s error: %w", name, err)
}
}

return nil
}

func (m *micropubServer) postSave(e *core.Entry, req *micropub.Request, oldTargets []string) {
// Syndications
var syndicateTo []string
if req != nil {
syndicateTo, _ = getRequestSyndicateTo(req)
}
m.syndicate(e, syndicateTo)

// Post-save hooks
for name, plugin := range m.s.plugins {
hookPlugin, ok := plugin.(HookPlugin)
if !ok {
continue
}

err := hookPlugin.PostSaveHook(e)
if err != nil {
m.s.log.Errorw("plugin post save hook failed", "plugin", name, "err", err)
}
}

// Search indexing
if m.s.meilisearch != nil {
var err error
if e.Deleted() {
err = m.s.meilisearch.Remove(e.ID)
} else {
err = m.s.meilisearch.Add(e)
}
if err != nil {
m.s.log.Errorw("meilisearch sync failed", "err", err)
}
}

// Rebuild
m.s.build(false)

// No further action for drafts or no webmentions
if e.Draft || e.NoWebmentions {
return
}

err := m.s.core.SendWebmentions(e.Permalink, oldTargets...)
if err != nil {
m.s.log.Errorw("failed to send webmentions", "id", e.ID, "err", err)
}
}

func (m *micropubServer) entryToMF2(e *core.Entry) map[string]any {
properties := map[string]interface{}{}

Expand Down
Loading

0 comments on commit 94ce17f

Please sign in to comment.