diff --git a/api/devices_by_slug.go b/api/devices_by_slug.go new file mode 100644 index 0000000..33f3f07 --- /dev/null +++ b/api/devices_by_slug.go @@ -0,0 +1,25 @@ +package api + +import ( + "context" + "net/http" + + "github.com/tigorlazuardi/redmage/models" + "github.com/tigorlazuardi/redmage/pkg/errs" +) + +func (api *API) DeviceBySlug(ctx context.Context, slug string) (device *models.Device, err error) { + ctx, span := tracer.Start(ctx, "*API.DeviceByName") + defer span.End() + + device, err = models.FindDevice(ctx, api.db, slug) + if err != nil { + if err.Error() == "sql: no rows in result set" { + return device, errs.Wrapw(err, "device not found", "device", device).Code(http.StatusNotFound) + } + + return device, errs.Wrapw(err, "failed to find device", "device", device) + } + + return device, nil +} diff --git a/server/routes/page_devices_details.go b/server/routes/page_devices_details.go new file mode 100644 index 0000000..c2297d5 --- /dev/null +++ b/server/routes/page_devices_details.go @@ -0,0 +1,58 @@ +package routes + +import ( + "net/http" + + "github.com/go-chi/chi/v5" + "github.com/tigorlazuardi/redmage/pkg/errs" + "github.com/tigorlazuardi/redmage/pkg/log" + "github.com/tigorlazuardi/redmage/views" + "github.com/tigorlazuardi/redmage/views/devicesview/devicedetails" +) + +func (routes *Routes) PageDeviceDetails(rw http.ResponseWriter, req *http.Request) { + ctx, span := tracer.Start(req.Context(), "*Routees.PageDeviceDetails") + defer span.End() + + c := views.NewContext(routes.Config, req) + + slug := chi.URLParam(req, "slug") + + var data devicedetails.Data + data.Params.FillFromQuery(req.URL.Query()) + + var err error + + data.Device, err = routes.API.DeviceBySlug(ctx, slug) + if err != nil { + log.New(ctx).Err(err).Error("failed to get device by slug") + code, message := errs.HTTPMessage(err) + rw.WriteHeader(code) + data.Error = message + if err := devicedetails.View(c, data).Render(ctx, rw); err != nil { + log.New(ctx).Err(err).Error("failed to render device details page") + } + return + } + + data.Params.Device = data.Device.Slug + + result, err := routes.API.ImagesList(ctx, data.Params) + if err != nil { + log.New(ctx).Err(err).Error("failed to get image by device") + code, message := errs.HTTPMessage(err) + rw.WriteHeader(code) + data.Error = message + if err := devicedetails.View(c, data).Render(ctx, rw); err != nil { + log.New(ctx).Err(err).Error("failed to render device details page") + } + return + } + + data.Images = result.Images + data.TotalImages = result.Total + + if err := devicedetails.View(c, data).Render(ctx, rw); err != nil { + log.New(ctx).Err(err).Error("failed to render device details page") + } +} diff --git a/server/routes/routes.go b/server/routes/routes.go index 7e2f433..e1056f5 100644 --- a/server/routes/routes.go +++ b/server/routes/routes.go @@ -82,6 +82,7 @@ func (routes *Routes) registerWWWRoutes(router chi.Router) { r.Get("/subreddits/add", routes.PageSubredditsAdd) r.Get("/config", routes.PageConfig) r.Get("/devices", routes.PageDevices) + r.Get("/devices/details/{slug}", routes.PageDeviceDetails) r.Get("/schedules", routes.PageScheduleHistory) }) } diff --git a/views/devicesview/devicedetails/data.go b/views/devicesview/devicedetails/data.go new file mode 100644 index 0000000..7af151a --- /dev/null +++ b/views/devicesview/devicedetails/data.go @@ -0,0 +1,46 @@ +package devicedetails + +import ( + "github.com/tigorlazuardi/redmage/api" + "github.com/tigorlazuardi/redmage/models" +) + +type Data struct { + Error string + Device *models.Device + Images models.ImageSlice + TotalImages int64 + Params api.ImageListParams +} + +type splitBySubredditImages struct { + Subreddit string + Images models.ImageSlice +} + +func (data Data) splitImages() []*splitBySubredditImages { + var out []*splitBySubredditImages + + for _, image := range data.Images { + var found bool + + inner: + for _, o := range out { + if o.Subreddit == image.Subreddit { + found = true + o.Images = append(o.Images, image) + break inner + } + } + + if !found { + out = append(out, &splitBySubredditImages{ + Subreddit: image.Subreddit, + Images: models.ImageSlice{image}, + }) + } + + } + + return out +} diff --git a/views/devicesview/devicedetails/filter.templ b/views/devicesview/devicedetails/filter.templ new file mode 100644 index 0000000..b7a591b --- /dev/null +++ b/views/devicesview/devicedetails/filter.templ @@ -0,0 +1,35 @@ +package devicedetails + +import "fmt" + +templ filter(data Data) { +
+ +
+} diff --git a/views/devicesview/devicedetails/view.templ b/views/devicesview/devicedetails/view.templ new file mode 100644 index 0000000..d463483 --- /dev/null +++ b/views/devicesview/devicedetails/view.templ @@ -0,0 +1,45 @@ +package devicedetails + +import "github.com/tigorlazuardi/redmage/views" +import "github.com/tigorlazuardi/redmage/views/components" +import "fmt" +import "github.com/tigorlazuardi/redmage/models" + +templ View(c *views.Context, data Data) { + @components.Doctype() { + if data.Device == nil { + @components.Head(c, components.HeadTitle("Redmage - Device Not Found")) + } else { + @components.Head(c, components.HeadTitle(fmt.Sprintf("Redmage - %s", data.Device.Name))) + } + @components.Body(c) { + @Content(c, data) + } + } +} + +templ Content(c *views.Context, data Data) { +
+ @components.Container() { + if data.Error != "" { + @components.ErrorToast(data.Error) + } else { +

{ data.Device.Name }

+
+ @filter(data) + for _, group := range data.splitImages() { +

{ group.Subreddit }

+ @imageList(group.Images) + } + } + } +
+} + +templ imageList(images models.ImageSlice) { +
+ for _, data := range images { + @components.ImageCard(data, 0) + } +
+} diff --git a/views/devicesview/filter.templ b/views/devicesview/filter.templ new file mode 100644 index 0000000..ee7814d --- /dev/null +++ b/views/devicesview/filter.templ @@ -0,0 +1,67 @@ +package devicesview + +import "github.com/tigorlazuardi/redmage/api" +import "strconv" + +templ filter(data Data) { +
+ +
+ + + + +
+
+} + +templ limitOption(params api.DevicesListParams, value int) { + if int(params.Limit) == value { + + } else { + + } +} diff --git a/views/devicesview/devicesview.templ b/views/devicesview/view.templ similarity index 97% rename from views/devicesview/devicesview.templ rename to views/devicesview/view.templ index 48371e7..7646038 100644 --- a/views/devicesview/devicesview.templ +++ b/views/devicesview/view.templ @@ -32,6 +32,7 @@ templ DevicesContent(c *views.Context, data Data) { } else {

Devices

+ @filter(data)

{ strconv.FormatInt(data.Total, 10) } Devices

@devicesList(data) } @@ -55,6 +56,7 @@ templ devicesList(data Data) { { device.Slug }

{ fmt.Sprintf("%.0f \u00d7 %.0f", device.ResolutionX, device.ResolutionY) } px

+
Filter
if device.NSFW == 1 {
NSFW
diff --git a/views/homeview/homeview_data.go b/views/homeview/homeview_data.go index feaf7fe..f99459e 100644 --- a/views/homeview/homeview_data.go +++ b/views/homeview/homeview_data.go @@ -33,8 +33,6 @@ type Subreddit struct { func NewRecentlyAddedImages(images models.ImageSlice) RecentlyAddedImages { r := make(RecentlyAddedImages, 0, len(images)) - var count int - for _, image := range images { if image.R.Device == nil || image.R.Subreddit == nil { continue @@ -48,7 +46,6 @@ func NewRecentlyAddedImages(images models.ImageSlice) RecentlyAddedImages { if subreddit.Subreddit.Name == image.R.Subreddit.Name { subredditFound = true r[i].Subreddits[j].Images = append(r[i].Subreddits[j].Images, image) - count++ } } if !subredditFound { @@ -56,12 +53,10 @@ func NewRecentlyAddedImages(images models.ImageSlice) RecentlyAddedImages { Subreddit: image.R.Subreddit, Images: models.ImageSlice{image}, }) - count++ } } } if !deviceFound { - count++ r = append(r, RecentlyAddedImage{ Device: image.R.Device, Subreddits: []Subreddit{