Skip to content

Commit

Permalink
feat: closes #13 and implementspreview endpoint and logo via base64 i…
Browse files Browse the repository at this point in the history
…n json body arg 'logo'
  • Loading branch information
bolovsky committed Jun 5, 2023
1 parent de98aa4 commit 3ea07dc
Show file tree
Hide file tree
Showing 14 changed files with 309 additions and 95 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,30 @@ curl -XPOST https://yourdomain.something/api/v1/short \
-d $BODY
```

If you want to preview the QR code only, you can use the preview endpoint with the same body as above
No TTL exists in that endpoint though (as its only preview mode), and the link is exactly the one you sent
```bash
read -r -d '' BODY <<EOF
{
"link": "https://www.google.pt/",
"qr_code": {
"create": true,
"width" : 50,
"height": 50,
"foreground_color": "#000000",
"background_color": "#ffffff",
"shape": "circle"
}
}
EOF

curl -XPOST https://yourdomain.something/api/v1/preview \
-H 'token: Whatever_Token_you_put_in_your_env' \
-H 'Content-Type: application/json' \
-d $BODY
```


this would render an answer like:
```json
{
Expand Down
26 changes: 17 additions & 9 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,23 @@ import (

type API struct {
BaseGinServer
log *zap.Logger
config *Config
service *service.ShortyService
log *zap.Logger
config *Config
shortySvc *service.ShortyService
qrSvc *service.QRCodeService
}

func NewAPI(log *zap.Logger, config *Config, shortyService *service.ShortyService) *API {
func NewAPI(
log *zap.Logger,
config *Config,
shortyService *service.ShortyService,
qrSvc *service.QRCodeService,
) *API {
return &API{
log: log,
config: config,
service: shortyService,
log: log,
config: config,
shortySvc: shortyService,
qrSvc: qrSvc,
}
}

Expand All @@ -39,13 +46,14 @@ func (a *API) Run() {
gzip.Gzip(gzip.DefaultCompression),
)

a.PushHandlerWithGroup(NewURLHandler(a.config.UnknownPage, a.service), g.Group("/"))
a.PushHandlerWithGroup(NewURLHandler(a.config.UnknownPage, a.shortySvc), g.Group("/"))

authMiddleware := NewAuthenticationMiddleware(a.config.Token)

apiGroup := g.Group("/api/v1")
apiGroup.Use(authMiddleware.Authenticated)
a.PushHandlerWithGroup(NewShortenerHandler(a.service), apiGroup)
a.PushHandlerWithGroup(NewShortenerHandler(a.shortySvc), apiGroup)
a.PushHandlerWithGroup(NewPreviewHandler(a.qrSvc), apiGroup)

if err := g.Run(fmt.Sprintf(":%d", a.config.Port)); err != nil {
a.log.Fatal(err.Error())
Expand Down
3 changes: 2 additions & 1 deletion api/authentication.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package api
import (
"net/http"

"github.com/doutorfinancas/pun-sho/api/response"
"github.com/gin-gonic/gin"
)

Expand All @@ -20,7 +21,7 @@ func (a *AuthenticationMiddleware) Authenticated(c *gin.Context) {
token := c.GetHeader("token")

if token != a.token {
c.AbortWithStatusJSON(http.StatusUnauthorized, NewErrorResponse("unauthorized"))
c.AbortWithStatusJSON(http.StatusUnauthorized, response.NewErrorResponse("unauthorized"))
return
}

Expand Down
55 changes: 55 additions & 0 deletions api/preview.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package api

import (
"net/http"

"github.com/doutorfinancas/pun-sho/api/request"
"github.com/doutorfinancas/pun-sho/api/response"
"github.com/doutorfinancas/pun-sho/service"
"github.com/doutorfinancas/pun-sho/str"
"github.com/gin-gonic/gin"
)

type previewHandler struct {
qrSvc *service.QRCodeService
}

func NewPreviewHandler(qrSvc *service.QRCodeService) HTTPHandler {
return &previewHandler{
qrSvc: qrSvc,
}
}

func (h *previewHandler) Routes(rg *gin.RouterGroup) {
rg.POST("", h.CreateLink)
rg.POST("/", h.CreateLink)
}

func (h *previewHandler) Group() *string {
return str.ToStringNil("preview")
}

func (h *previewHandler) CreateLink(c *gin.Context) {
m := &request.GeneratePreview{}
err := c.BindJSON(m)

if err != nil {
c.JSON(
http.StatusBadRequest,
response.NewErrorResponse("invalid payload"),
)
return
}
s, err := h.qrSvc.Generate(m.QRCode, m.Link)
if err != nil {
c.JSON(
http.StatusBadRequest,
response.NewErrorResponse("kaput, no save"),
)
return
}

a := response.NewGeneratePreviewResponse(s, nil)

c.JSON(http.StatusCreated, a)
}
9 changes: 0 additions & 9 deletions api/request/create_shorty.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,3 @@ type CreateShorty struct {
TTL *time.Time `json:"TTL"`
QRCode *QRCode `json:"qr_code"`
}

type QRCode struct {
Create bool `json:"create"`
Width int `json:"width"`
BorderWidth int `json:"border_width"`
FgColor string `json:"foreground_color"`
BgColor string `json:"background_color"`
Shape string `json:"shape"`
}
6 changes: 6 additions & 0 deletions api/request/generate_preview.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package request

type GeneratePreview struct {
Link string `json:"link"`
QRCode *QRCode `json:"qr_code"`
}
11 changes: 11 additions & 0 deletions api/request/qr_code.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package request

type QRCode struct {
Create bool `json:"create"`
Width int `json:"width"`
BorderWidth int `json:"border_width"`
FgColor string `json:"foreground_color"`
BgColor string `json:"background_color"`
Shape string `json:"shape"`
LogoImage string `json:"logo"`
}
16 changes: 16 additions & 0 deletions api/response/generate_preview.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package response

type GeneratePreviewResponse struct {
BaseResponse
QrCode string `json:"qr_code"`
Message *[]string `json:"message,omitempty"`
}

// NewGeneratePreviewResponse creates a base preview response
func NewGeneratePreviewResponse(qrCode string, message *[]string) *GeneratePreviewResponse {
return &GeneratePreviewResponse{
BaseResponse{Status: Ok},
qrCode,
message,
}
}
10 changes: 5 additions & 5 deletions api/response.go → api/response/response.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package api
package response

const ResponseOk = "ok"
const ResponseError = "error"
const Ok = "ok"
const Error = "error"

type BaseResponse struct {
Status string `json:"status"`
Expand All @@ -13,9 +13,9 @@ type ErrorResponse struct {
}

func NewErrorResponse(message string) *ErrorResponse {
return &ErrorResponse{BaseResponse{Status: ResponseError}, []string{message}}
return &ErrorResponse{BaseResponse{Status: Error}, []string{message}}
}

func NewOkResponse() *BaseResponse {
return &BaseResponse{Status: ResponseOk}
return &BaseResponse{Status: Ok}
}
31 changes: 17 additions & 14 deletions api/shortener.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package api
import (
"net/http"

"github.com/doutorfinancas/pun-sho/api/response"
"github.com/gin-gonic/gin"
"github.com/google/uuid"

Expand All @@ -12,11 +13,13 @@ import (
)

type shortenerHandler struct {
service *service.ShortyService
shortySvc *service.ShortyService
}

func NewShortenerHandler(svc *service.ShortyService) HTTPHandler {
return &shortenerHandler{service: svc}
func NewShortenerHandler(shortySvc *service.ShortyService) HTTPHandler {
return &shortenerHandler{
shortySvc: shortySvc,
}
}

func (h *shortenerHandler) Routes(rg *gin.RouterGroup) {
Expand All @@ -35,11 +38,11 @@ func (h *shortenerHandler) GetLinkInformation(c *gin.Context) {
if id == "" {
c.JSON(
http.StatusBadRequest,
NewErrorResponse("no id provided"),
response.NewErrorResponse("no id provided"),
)
}
parsed := uuid.MustParse(id)
shorty, err := h.service.FindShortyByID(parsed)
shorty, err := h.shortySvc.FindShortyByID(parsed)
if err != nil {
c.JSON(http.StatusNotFound, "shorty not found")
return
Expand All @@ -56,16 +59,16 @@ func (h *shortenerHandler) ListLinks(c *gin.Context) {
if err != nil {
c.JSON(
http.StatusBadRequest,
NewErrorResponse(message),
response.NewErrorResponse(message),
)
return
}

links, err := h.service.List(limit, offset)
links, err := h.shortySvc.List(limit, offset)
if err != nil {
c.JSON(
http.StatusBadRequest,
NewErrorResponse("kaput, no links for you"),
response.NewErrorResponse("kaput, no links for you"),
)
return
}
Expand All @@ -80,15 +83,15 @@ func (h *shortenerHandler) CreateLink(c *gin.Context) {
if err != nil {
c.JSON(
http.StatusBadRequest,
NewErrorResponse("invalid payload"),
response.NewErrorResponse("invalid payload"),
)
return
}
s, err := h.service.Create(m)
s, err := h.shortySvc.Create(m)
if err != nil {
c.JSON(
http.StatusBadRequest,
NewErrorResponse("kaput, no save"),
response.NewErrorResponse("kaput, no save"),
)
return
}
Expand All @@ -101,15 +104,15 @@ func (h *shortenerHandler) RemoveLink(c *gin.Context) {
if id == "" {
c.JSON(
http.StatusBadRequest,
NewErrorResponse("no id provided"),
response.NewErrorResponse("no id provided"),
)
}
parsed := uuid.MustParse(id)
err := h.service.DeleteShortyByUUID(parsed)
err := h.shortySvc.DeleteShortyByUUID(parsed)
if err != nil {
c.JSON(
http.StatusBadRequest,
NewErrorResponse("kaput, no delete"),
response.NewErrorResponse("kaput, no delete"),
)
}
c.JSON(http.StatusOK, nil)
Expand Down
5 changes: 3 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ func main() {

shortyRepo := entity.NewShortyRepository(db, log)
shortyAccessRepo := entity.NewShortyAccessRepository(db, log)
shortySvc := service.NewShortyService(cfg.HostName, cfg.QRLogo, log, shortyRepo, shortyAccessRepo)
qrSvc := service.NewQRCodeService(cfg.QRLogo)
shortySvc := service.NewShortyService(cfg.HostName, cfg.QRLogo, log, shortyRepo, shortyAccessRepo, qrSvc)

a := api.NewAPI(log, cfg, shortySvc)
a := api.NewAPI(log, cfg, shortySvc, qrSvc)

a.Run()
}
Expand Down
Loading

0 comments on commit 3ea07dc

Please sign in to comment.