mirror of
https://github.com/ThisTine/Snip.git
synced 2026-08-18 23:18:47 +07:00
feat: first commit
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/snip/backend/internal/domain"
|
||||
"github.com/snip/backend/internal/service"
|
||||
)
|
||||
|
||||
// /api/v1/links — POST create (auth optional), GET list (auth required)
|
||||
func (a *API) linksCollection(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case http.MethodPost:
|
||||
a.createLink(w, r)
|
||||
case http.MethodGet:
|
||||
a.listLinks(w, r)
|
||||
default:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *API) createLink(w http.ResponseWriter, r *http.Request) {
|
||||
var req createReq
|
||||
if err := decode(r, &req); err != nil {
|
||||
writeError(w, domain.ErrInvalidURL)
|
||||
return
|
||||
}
|
||||
mode := domain.Mode(req.Mode)
|
||||
if mode != domain.ModeRandom && mode != domain.ModeMemorable && mode != domain.ModeCustom {
|
||||
mode = domain.ModeRandom
|
||||
}
|
||||
link, err := a.links.Create(r.Context(), service.CreateInput{
|
||||
LongURL: req.LongURL,
|
||||
Mode: mode,
|
||||
CustomAlias: req.CustomAlias,
|
||||
Pin: req.Pin,
|
||||
}, a.userID(r))
|
||||
if err != nil {
|
||||
writeError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusCreated, toDTO(link))
|
||||
}
|
||||
|
||||
func (a *API) listLinks(w http.ResponseWriter, r *http.Request) {
|
||||
q := r.URL.Query()
|
||||
page, _ := strconv.Atoi(q.Get("page"))
|
||||
pageSize, _ := strconv.Atoi(q.Get("pageSize"))
|
||||
|
||||
result, err := a.links.List(r.Context(), a.userID(r), q.Get("q"), page, pageSize)
|
||||
if err != nil {
|
||||
writeError(w, err)
|
||||
return
|
||||
}
|
||||
items := make([]linkDTO, 0, len(result.Items))
|
||||
for i := range result.Items {
|
||||
items = append(items, toDTO(&result.Items[i]))
|
||||
}
|
||||
writeJSON(w, http.StatusOK, listResponse{
|
||||
Items: items,
|
||||
Total: result.Total,
|
||||
Page: result.Page,
|
||||
PageSize: result.PageSize,
|
||||
})
|
||||
}
|
||||
|
||||
func (a *API) linkStats(w http.ResponseWriter, r *http.Request) {
|
||||
stats, err := a.links.Stats(r.Context(), a.userID(r))
|
||||
if err != nil {
|
||||
writeError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, stats)
|
||||
}
|
||||
|
||||
// /api/v1/links/{id} — PATCH, DELETE
|
||||
// /api/v1/links/{id}/pin — PUT, DELETE
|
||||
func (a *API) linkItem(w http.ResponseWriter, r *http.Request) {
|
||||
rest := pathTail(r.URL.Path, "/api/v1/links/")
|
||||
parts := strings.Split(strings.Trim(rest, "/"), "/")
|
||||
id := parts[0]
|
||||
if id == "" {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
owner := a.userID(r)
|
||||
|
||||
// /{id}/pin
|
||||
if len(parts) == 2 && parts[1] == "pin" {
|
||||
a.managePin(w, r, id, owner)
|
||||
return
|
||||
}
|
||||
if len(parts) != 1 {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
switch r.Method {
|
||||
case http.MethodPatch:
|
||||
var req updateReq
|
||||
if err := decode(r, &req); err != nil {
|
||||
writeError(w, domain.ErrInvalidURL)
|
||||
return
|
||||
}
|
||||
link, err := a.links.UpdateDestination(r.Context(), id, owner, req.LongURL)
|
||||
if err != nil {
|
||||
writeError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, toDTO(link))
|
||||
case http.MethodDelete:
|
||||
if err := a.links.Delete(r.Context(), id, owner); err != nil {
|
||||
writeError(w, err)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
default:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *API) managePin(w http.ResponseWriter, r *http.Request, id, owner string) {
|
||||
switch r.Method {
|
||||
case http.MethodPut:
|
||||
var req pinReq
|
||||
if err := decode(r, &req); err != nil {
|
||||
writeError(w, domain.ErrInvalidPin)
|
||||
return
|
||||
}
|
||||
link, err := a.links.SetPin(r.Context(), id, owner, req.Pin)
|
||||
if err != nil {
|
||||
writeError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, toDTO(link))
|
||||
case http.MethodDelete:
|
||||
link, err := a.links.SetPin(r.Context(), id, owner, "")
|
||||
if err != nil {
|
||||
writeError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, toDTO(link))
|
||||
default:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user