aboutsummaryrefslogtreecommitdiff
path: root/pkg/handler
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/handler')
-rw-r--r--pkg/handler/add/add.go (renamed from pkg/handler/add.go)4
-rw-r--r--pkg/handler/add/handler.go21
-rw-r--r--pkg/handler/admin/admin.go (renamed from pkg/handler/admin.go)36
-rw-r--r--pkg/handler/captcha/handler.go17
-rw-r--r--pkg/handler/feed/feed.go73
-rw-r--r--pkg/handler/feed/handler.go21
-rw-r--r--pkg/handler/handler.go14
-rw-r--r--pkg/handler/quote/handler.go26
-rw-r--r--pkg/handler/quote/index.go (renamed from pkg/handler/index.go)10
-rw-r--r--pkg/handler/quote/quote.go (renamed from pkg/handler/quote.go)4
-rw-r--r--pkg/handler/quote/random.go18
-rw-r--r--pkg/handler/quote/top.go28
-rw-r--r--pkg/handler/random.go31
-rw-r--r--pkg/handler/rate/handler.go19
-rw-r--r--pkg/handler/rate/rate.go69
15 files changed, 341 insertions, 50 deletions
diff --git a/pkg/handler/add.go b/pkg/handler/add/add.go
index a6a5ced..dbcce47 100644
--- a/pkg/handler/add.go
+++ b/pkg/handler/add/add.go
@@ -1,4 +1,4 @@
-package handler
+package add
import (
"net/http"
@@ -40,7 +40,7 @@ func (h *Handler) AddQuotePost(c echo.Context) error {
Approved: false,
Archive: false,
}
- if _, err := h.DB.NewInsert().Model(q).Exec(c.Request().Context()); err != nil {
+ if _, err := h.db.NewInsert().Model(q).Exec(c.Request().Context()); err != nil {
return err
}
diff --git a/pkg/handler/add/handler.go b/pkg/handler/add/handler.go
new file mode 100644
index 0000000..8f744ab
--- /dev/null
+++ b/pkg/handler/add/handler.go
@@ -0,0 +1,21 @@
+package add
+
+import (
+ "github.com/labstack/echo/v4"
+ "github.com/uptrace/bun"
+)
+
+type Handler struct {
+ db *bun.DB
+}
+
+// NewHandler returns new Handler.
+func NewHandler(db *bun.DB) *Handler {
+ return &Handler{db: db}
+}
+
+func (h *Handler) Register(g *echo.Group) {
+ g.GET("", h.AddQuote)
+ g.POST("", h.AddQuotePost)
+ g.GET("/success", h.AddQuoteSuccess)
+}
diff --git a/pkg/handler/admin.go b/pkg/handler/admin/admin.go
index 75fb650..494da05 100644
--- a/pkg/handler/admin.go
+++ b/pkg/handler/admin/admin.go
@@ -1,16 +1,42 @@
-package handler
+package admin
import (
"net/http"
"github.com/labstack/echo/v4"
+ "github.com/labstack/echo/v4/middleware"
+ "github.com/uptrace/bun"
+ "sh.org.ru/pkg/config"
"sh.org.ru/pkg/model"
"sh.org.ru/pkg/tpl"
)
+type Handler struct {
+ db *bun.DB
+ cfg *config.Config
+}
+
+// NewHandler returns new Handler.
+func NewHandler(db *bun.DB, cfg *config.Config) *Handler {
+ return &Handler{
+ db: db,
+ cfg: cfg,
+ }
+}
+
+func (h *Handler) Register(g *echo.Group) {
+ g.Use(middleware.BasicAuth(func(u, p string, ctx echo.Context) (bool, error) {
+ return h.cfg.Admins[u] == p, nil
+ }))
+
+ g.GET("/", h.Admin)
+ g.POST("/action", h.AdminAction)
+ g.GET("/export", h.AdminExport)
+}
+
func (h *Handler) Admin(c echo.Context) error {
quotes := make([]model.Quote, 0, 20)
- count, err := h.DB.NewSelect().
+ count, err := h.db.NewSelect().
Model((*model.Quote)(nil)).
Order("id ASC").
Where("approved = ?", false).
@@ -30,7 +56,7 @@ func (h *Handler) AdminAction(c echo.Context) error {
switch form.Action {
case "approve":
- _, err := h.DB.NewUpdate().
+ _, err := h.db.NewUpdate().
Model(&model.Quote{
ID: int64(form.ID),
Approved: true,
@@ -42,7 +68,7 @@ func (h *Handler) AdminAction(c echo.Context) error {
return err
}
case "decline":
- _, err := h.DB.NewDelete().
+ _, err := h.db.NewDelete().
Model(&model.Quote{
ID: int64(form.ID),
}).
@@ -58,7 +84,7 @@ func (h *Handler) AdminAction(c echo.Context) error {
func (h *Handler) AdminExport(c echo.Context) error {
quotes := []model.Quote{}
- err := h.DB.NewSelect().
+ err := h.db.NewSelect().
Model((*model.Quote)(nil)).
Order("id ASC").
Scan(c.Request().Context(), &quotes)
diff --git a/pkg/handler/captcha/handler.go b/pkg/handler/captcha/handler.go
new file mode 100644
index 0000000..2e3b483
--- /dev/null
+++ b/pkg/handler/captcha/handler.go
@@ -0,0 +1,17 @@
+package captcha
+
+import (
+ "github.com/labstack/echo/v4"
+ "github.com/ssoda/captcha"
+)
+
+type Handler struct{}
+
+// NewHandler returns new Handler.
+func NewHandler() *Handler {
+ return &Handler{}
+}
+
+func (h *Handler) Register(g *echo.Group) {
+ g.GET("/*", echo.WrapHandler(captcha.Server(400, 65)))
+}
diff --git a/pkg/handler/feed/feed.go b/pkg/handler/feed/feed.go
new file mode 100644
index 0000000..05921e9
--- /dev/null
+++ b/pkg/handler/feed/feed.go
@@ -0,0 +1,73 @@
+package feed
+
+import (
+ "fmt"
+ "net/http"
+ "time"
+
+ "github.com/gorilla/feeds"
+ "github.com/labstack/echo/v4"
+ "sh.org.ru/pkg/model"
+)
+
+func (h *Handler) Feed(c echo.Context) error {
+ feedType := c.Param("type")
+
+ quotes := make([]model.Quote, 0, 20)
+ err := h.db.NewSelect().
+ Model((*model.Quote)(nil)).
+ Order("id DESC").
+ Where("approved = ?", true).
+ Limit(20).
+ Scan(c.Request().Context(), &quotes)
+ if err != nil {
+ return err
+ }
+
+ feed := &feeds.Feed{
+ Title: "sh.org.ru - Новый цитатник Рунета",
+ Link: &feeds.Link{Href: h.cfg.Host},
+ Description: "",
+ Author: &feeds.Author{Name: "NeonXP", Email: "i@neonxp.ru"},
+ Created: time.Now(),
+ }
+
+ for _, q := range quotes {
+ uid := fmt.Sprintf("%s/quote/%d", h.cfg.Host, q.ID)
+ feed.Items = append(feed.Items, &feeds.Item{
+ Id: uid,
+ Title: fmt.Sprintf("Цитата #%d", q.ID),
+ Link: &feeds.Link{Href: uid},
+ Created: q.CreatedAt,
+ Description: q.Text(),
+ })
+ }
+ switch feedType {
+ case "rss":
+ result, err := feed.ToRss()
+ if err != nil {
+ return err
+ }
+
+ c.Response().Header().Set("Content-Type", "application/rss+xml")
+ return c.String(http.StatusOK, result)
+ case "atom":
+ result, err := feed.ToAtom()
+ if err != nil {
+ return err
+ }
+
+ c.Response().Header().Set("Content-Type", "application/atom+xml")
+ return c.String(http.StatusOK, result)
+ case "json":
+ result, err := feed.ToJSON()
+ if err != nil {
+ return err
+ }
+
+ c.Response().Header().Set("Content-Type", "application/json")
+ return c.String(http.StatusOK, result)
+ default:
+ return echo.ErrNotFound
+ }
+}
diff --git a/pkg/handler/feed/handler.go b/pkg/handler/feed/handler.go
new file mode 100644
index 0000000..868e477
--- /dev/null
+++ b/pkg/handler/feed/handler.go
@@ -0,0 +1,21 @@
+package feed
+
+import (
+ "github.com/labstack/echo/v4"
+ "github.com/uptrace/bun"
+ "sh.org.ru/pkg/config"
+)
+
+type Handler struct {
+ db *bun.DB
+ cfg *config.Config
+}
+
+// NewHandler returns new Handler.
+func NewHandler(db *bun.DB, cfg *config.Config) *Handler {
+ return &Handler{db: db, cfg: cfg}
+}
+
+func (h *Handler) Register(g *echo.Group) {
+ g.GET("/:type", h.Feed)
+}
diff --git a/pkg/handler/handler.go b/pkg/handler/handler.go
index 5ba3966..15eb42d 100644
--- a/pkg/handler/handler.go
+++ b/pkg/handler/handler.go
@@ -1,7 +1,15 @@
package handler
-import "github.com/uptrace/bun"
+import "github.com/labstack/echo/v4"
-type Handler struct {
- DB *bun.DB
+type Handler interface {
+ Register(g *echo.Group)
+}
+
+type Router map[string]Handler
+
+func (r Router) Register(e *echo.Echo) {
+ for groupName, handlers := range r {
+ handlers.Register(e.Group(groupName))
+ }
}
diff --git a/pkg/handler/quote/handler.go b/pkg/handler/quote/handler.go
new file mode 100644
index 0000000..04807c0
--- /dev/null
+++ b/pkg/handler/quote/handler.go
@@ -0,0 +1,26 @@
+package quote
+
+import (
+ "github.com/labstack/echo/v4"
+ "github.com/uptrace/bun"
+)
+
+type Handler struct {
+ db *bun.DB
+}
+
+// NewHandler returns new Handler.
+func NewHandler(db *bun.DB) *Handler {
+ return &Handler{db: db}
+}
+
+func (h *Handler) Register(g *echo.Group) {
+ g.GET("", h.Index)
+ g.GET("quote/:id", h.Quote)
+ g.GET("random", h.Random)
+ g.GET("top", h.Top)
+}
+
+type Pagination struct {
+ Page int `query:"page" default:"0"`
+}
diff --git a/pkg/handler/index.go b/pkg/handler/quote/index.go
index 611a544..9dd21f8 100644
--- a/pkg/handler/index.go
+++ b/pkg/handler/quote/index.go
@@ -1,4 +1,4 @@
-package handler
+package quote
import (
"github.com/labstack/echo/v4"
@@ -13,7 +13,7 @@ func (h *Handler) Index(c echo.Context) error {
}
quotes := make([]model.Quote, 0, 20)
- count, err := h.DB.NewSelect().
+ count, err := h.db.NewSelect().
Model((*model.Quote)(nil)).
Order("id DESC").
Where("approved = ?", true).
@@ -24,9 +24,5 @@ func (h *Handler) Index(c echo.Context) error {
return err
}
- return tpl.Index(quotes, p.Page, count).Render(c.Request().Context(), c.Response())
-}
-
-type Pagination struct {
- Page int `query:"page" default:"0"`
+ return tpl.List(quotes, p.Page, count).Render(c.Request().Context(), c.Response())
}
diff --git a/pkg/handler/quote.go b/pkg/handler/quote/quote.go
index 2a5f7e6..b25eb90 100644
--- a/pkg/handler/quote.go
+++ b/pkg/handler/quote/quote.go
@@ -1,4 +1,4 @@
-package handler
+package quote
import (
"strconv"
@@ -16,7 +16,7 @@ func (h *Handler) Quote(c echo.Context) error {
}
quote := new(model.Quote)
- err = h.DB.NewSelect().
+ err = h.db.NewSelect().
Model(quote).
Where("id = ?", id).Scan(c.Request().Context(), quote)
if err != nil {
diff --git a/pkg/handler/quote/random.go b/pkg/handler/quote/random.go
new file mode 100644
index 0000000..1e04ff0
--- /dev/null
+++ b/pkg/handler/quote/random.go
@@ -0,0 +1,18 @@
+package quote
+
+import (
+ "github.com/labstack/echo/v4"
+ "sh.org.ru/pkg/model"
+ "sh.org.ru/pkg/tpl"
+)
+
+func (h *Handler) Random(c echo.Context) error {
+ quotes := make([]model.Quote, 0, 20)
+ err := h.db.NewRaw(`select q.* from quotes q where q.approved = true order by random() limit 20`).
+ Scan(c.Request().Context(), &quotes)
+ if err != nil {
+ return err
+ }
+
+ return tpl.Random(quotes).Render(c.Request().Context(), c.Response())
+}
diff --git a/pkg/handler/quote/top.go b/pkg/handler/quote/top.go
new file mode 100644
index 0000000..c2803ea
--- /dev/null
+++ b/pkg/handler/quote/top.go
@@ -0,0 +1,28 @@
+package quote
+
+import (
+ "github.com/labstack/echo/v4"
+ "sh.org.ru/pkg/model"
+ "sh.org.ru/pkg/tpl"
+)
+
+func (h *Handler) Top(c echo.Context) error {
+ p := &Pagination{}
+ if err := c.Bind(p); err != nil {
+ return err
+ }
+
+ quotes := make([]model.Quote, 0, 20)
+ count, err := h.db.NewSelect().
+ Model((*model.Quote)(nil)).
+ Order("rating DESC").
+ Where("approved = ?", true).
+ Limit(20).
+ Offset(p.Page*20).
+ ScanAndCount(c.Request().Context(), &quotes)
+ if err != nil {
+ return err
+ }
+
+ return tpl.List(quotes, p.Page, count).Render(c.Request().Context(), c.Response())
+}
diff --git a/pkg/handler/random.go b/pkg/handler/random.go
deleted file mode 100644
index 29c5f6f..0000000
--- a/pkg/handler/random.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package handler
-
-import (
- "github.com/a-h/templ"
- "github.com/labstack/echo/v4"
- "sh.org.ru/pkg/model"
- "sh.org.ru/pkg/tpl"
-)
-
-func (h *Handler) Random(c echo.Context) error {
- quotes := make([]model.Quote, 0, 20)
- err := h.DB.NewRaw(`select q.* from quotes q where q.approved = true order by random() limit 20`).
- Scan(c.Request().Context(), &quotes)
- if err != nil {
- return err
- }
-
- comp := tpl.Random(quotes)
-
- if c.Request().Header.Get("Hx-Request") == "true" {
- return comp.Render(c.Request().Context(), c.Response())
- }
-
- ctx := templ.WithChildren(c.Request().Context(), comp)
-
- return tpl.Layout(tpl.HeaderParams{
- Title: "Цитатник Рунета",
- Description: "Новый цитатник Рунета",
- URL: "https://sh.org.ru/",
- }).Render(ctx, c.Response())
-}
diff --git a/pkg/handler/rate/handler.go b/pkg/handler/rate/handler.go
new file mode 100644
index 0000000..1a2ecf3
--- /dev/null
+++ b/pkg/handler/rate/handler.go
@@ -0,0 +1,19 @@
+package rate
+
+import (
+ "github.com/labstack/echo/v4"
+ "github.com/uptrace/bun"
+)
+
+type Handler struct {
+ db *bun.DB
+}
+
+// NewHandler returns new Handler.
+func NewHandler(db *bun.DB) *Handler {
+ return &Handler{db: db}
+}
+
+func (h *Handler) Register(g *echo.Group) {
+ g.POST("/:id", h.Rate)
+}
diff --git a/pkg/handler/rate/rate.go b/pkg/handler/rate/rate.go
new file mode 100644
index 0000000..df6713f
--- /dev/null
+++ b/pkg/handler/rate/rate.go
@@ -0,0 +1,69 @@
+package rate
+
+import (
+ "strconv"
+
+ "github.com/labstack/echo-contrib/session"
+ "github.com/labstack/echo/v4"
+ "sh.org.ru/pkg/model"
+ "sh.org.ru/pkg/tpl"
+)
+
+func (h *Handler) Rate(c echo.Context) error {
+ voted, err := session.Get("votes", c)
+ if err != nil {
+ return err
+ }
+ sid := c.Param("id")
+ id, err := strconv.Atoi(sid)
+ if err != nil {
+ return err
+ }
+ f := new(rateForm)
+ if err := c.Bind(f); err != nil {
+ return err
+ }
+
+ quote := new(model.Quote)
+
+ if _, ok := voted.Values[id]; !ok {
+ voted.Values[id] = true
+ if err := voted.Save(c.Request(), c.Response()); err != nil {
+ return err
+ }
+ set := ""
+ switch f.Vote {
+ case "up":
+ set = "rating = rating + 1"
+ case "down":
+ set = "rating = rating - 1"
+ }
+ _, err = h.db.NewUpdate().
+ Model(quote).
+ Where("id = ?", id).
+ Set(set).
+ Returning("*").
+ Exec(c.Request().Context(), quote)
+ } else {
+ err = h.db.NewSelect().
+ Model(quote).
+ Where("id = ?", id).
+ Scan(c.Request().Context(), quote)
+ }
+ if err != nil {
+ return err
+ }
+
+ return tpl.Rate(quote, 0).Render(c.Request().Context(), c.Response())
+}
+
+type rateForm struct {
+ Vote string `form:"vote"`
+}
+
+type voteType string
+
+const (
+ voteUp voteType = "up"
+ voteDown voteType = "down"
+)