diff --git a/server/api/resource.go b/server/api/resource.go index 517a80a..4d384fb 100644 --- a/server/api/resource.go +++ b/server/api/resource.go @@ -2,7 +2,6 @@ package api import ( "encoding/json" - "github.com/gofiber/fiber/v3/log" "net/url" "nysoure/server/dao" "nysoure/server/model" @@ -10,6 +9,8 @@ import ( "nysoure/server/utils" "strconv" + "github.com/gofiber/fiber/v3/log" + "github.com/gofiber/fiber/v3" ) @@ -54,7 +55,8 @@ func handleGetResource(c fiber.Ctx) error { if err != nil { return model.NewRequestError("Invalid resource ID") } - resource, err := service.GetResource(uint(id)) + host := c.Hostname() + resource, err := service.GetResource(uint(id), host) if err != nil { return err } diff --git a/server/middleware/frontend_middleware.go b/server/middleware/frontend_middleware.go index 61e1049..8f30729 100644 --- a/server/middleware/frontend_middleware.go +++ b/server/middleware/frontend_middleware.go @@ -75,7 +75,7 @@ func serveIndexHtml(c fiber.Ctx) error { idStr := strings.TrimPrefix(path, "/resources/") id, err := strconv.Atoi(idStr) if err == nil { - r, err := service.GetResource(uint(id)) + r, err := service.GetResource(uint(id), "") if err == nil { if len(r.Images) > 0 { preview = fmt.Sprintf("%s/api/image/%d", serverBaseURL, r.Images[0].ID) diff --git a/server/model/resource.go b/server/model/resource.go index 03c15a0..696a4e8 100644 --- a/server/model/resource.go +++ b/server/model/resource.go @@ -30,17 +30,18 @@ type ResourceView struct { } type ResourceDetailView struct { - ID uint `json:"id"` - Title string `json:"title"` - AlternativeTitles []string `json:"alternativeTitles"` - Article string `json:"article"` - CreatedAt time.Time `json:"createdAt"` - Tags []TagView `json:"tags"` - Images []ImageView `json:"images"` - Files []FileView `json:"files"` - Author UserView `json:"author"` - Views uint `json:"views"` - Downloads uint `json:"downloads"` + ID uint `json:"id"` + Title string `json:"title"` + AlternativeTitles []string `json:"alternativeTitles"` + Article string `json:"article"` + CreatedAt time.Time `json:"createdAt"` + Tags []TagView `json:"tags"` + Images []ImageView `json:"images"` + Files []FileView `json:"files"` + Author UserView `json:"author"` + Views uint `json:"views"` + Downloads uint `json:"downloads"` + Related []ResourceView `json:"related"` } func (r *Resource) ToView() ResourceView { diff --git a/server/service/resource.go b/server/service/resource.go index a49084d..b85fdb5 100644 --- a/server/service/resource.go +++ b/server/service/resource.go @@ -1,9 +1,13 @@ package service import ( - "github.com/gofiber/fiber/v3/log" + "net/url" "nysoure/server/dao" "nysoure/server/model" + "strconv" + "strings" + + "github.com/gofiber/fiber/v3/log" "gorm.io/gorm" ) @@ -55,13 +59,69 @@ func CreateResource(uid uint, params *ResourceCreateParams) (uint, error) { return r.ID, nil } -func GetResource(id uint) (*model.ResourceDetailView, error) { +func findRelatedResources(r model.Resource, host string) []model.ResourceView { + lines := strings.Split(r.Article, "\n") + var relatedResources []model.ResourceView + for _, line := range lines { + r := parseResourceIfPresent(line, host) + if r != nil { + relatedResources = append(relatedResources, *r) + } + } + return relatedResources +} + +func parseResourceIfPresent(line string, host string) *model.ResourceView { + if len(line) < 4 { + return nil + } + if !strings.HasPrefix(line, "[") || !strings.HasSuffix(line, ")") { + return nil + } + if !strings.Contains(line, "](") { + return nil + } + splites := strings.Split(line, "(") + if len(splites) != 2 { + return nil + } + u := strings.TrimSuffix(splites[1], ")") + u = strings.TrimSpace(u) + parsed, err := url.Parse(u) + if err != nil { + return nil + } + if parsed.Hostname() != host { + return nil + } + path := parsed.Path + if !strings.HasPrefix(path, "/resources/") { + return nil + } + idStr := strings.TrimPrefix(path, "/resources/") + id, err := strconv.Atoi(idStr) + if err != nil { + return nil + } + r, err := dao.GetResourceByID(uint(id)) + if err != nil { + return nil + } + v := r.ToView() + return &v +} + +func GetResource(id uint, host string) (*model.ResourceDetailView, error) { r, err := dao.GetResourceByID(id) _ = dao.AddResourceViewCount(id) if err != nil { return nil, err } v := r.ToDetailView() + if host != "" { + related := findRelatedResources(r, host) + v.Related = related + } return &v, nil }