Skip to content

Commit

Permalink
fix: adds proper counters to list shorties (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
bolovsky authored Nov 15, 2024
1 parent 5b0aded commit 964c5e4
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,5 @@ docs:

.PHONY: postgres
postgres:
@docker-compose -f docker-compose.yml up -d
@docker-compose -f docker-compose.yml up -d
@sleep 5
2 changes: 2 additions & 0 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ func (a *API) Run() {
a.PushHandlerWithGroup(NewShortenerHandler(a.shortySvc), apiGroup)
a.PushHandlerWithGroup(NewPreviewHandler(a.qrSvc), apiGroup)

a.log.Info("API Starting", zap.Int("port", a.config.Port))

if err := g.Run(fmt.Sprintf(":%d", a.config.Port)); err != nil {
a.log.Fatal(err.Error())
}
Expand Down
7 changes: 6 additions & 1 deletion api/shortener.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,18 @@ func (h *shortenerHandler) GetLinkInformation(c *gin.Context) {
// @Schemes
// @Description Lists all the shortlinks available
// @Param token header string false "Authorization token"
// @Param limit query int false "limit"
// @Param offset query int false "offset"
// @Param with_qr query bool false "include qr code"
// @Produce json
// @Success 200 {object} []entity.Shorty "response"
// @Failure 400 {object} response.FailureResponse "error"
// @Router /short [get]
func (h *shortenerHandler) ListLinks(c *gin.Context) {
limitStr := c.Query("limit")
offsetStr := c.Query("offset")
withQRStr := c.Query("with_qr")
withQR := withQRStr != "false"

limit, offset, message, err := validateLimitAndOffset(limitStr, offsetStr)
if err != nil {
Expand All @@ -103,7 +108,7 @@ func (h *shortenerHandler) ListLinks(c *gin.Context) {
return
}

links, err := h.shortySvc.List(limit, offset)
links, err := h.shortySvc.List(withQR, limit, offset)
if err != nil {
c.JSON(
http.StatusBadRequest,
Expand Down
2 changes: 1 addition & 1 deletion database/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (c *Config) ConnectionString() *string {
connString = postGreConnection
sslMode = c.SSLMode
if c.SSLMode == "" {
sslMode = "full-verify"
sslMode = "verify-full"
}
case MySQLType:
connString = mySQLConnection
Expand Down
18 changes: 18 additions & 0 deletions docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,24 @@
"description": "Authorization token",
"name": "token",
"in": "header"
},
{
"type": "integer",
"description": "limit",
"name": "limit",
"in": "query"
},
{
"type": "integer",
"description": "offset",
"name": "offset",
"in": "query"
},
{
"type": "boolean",
"description": "include qr code",
"name": "with_qr",
"in": "query"
}
],
"responses": {
Expand Down
12 changes: 12 additions & 0 deletions docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,18 @@ paths:
in: header
name: token
type: string
- description: limit
in: query
name: limit
type: integer
- description: offset
in: query
name: offset
type: integer
- description: include qr code
in: query
name: with_qr
type: boolean
produces:
- application/json
responses:
Expand Down
15 changes: 15 additions & 0 deletions entity/shorty_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,18 @@ type Shorty struct {
func (*Shorty) TableName() string {
return "shorties"
}

type ShortyForList struct {
ID uuid.UUID `json:"id" gorm:"column:id;type:uuid;default:uuid_generate_v4()"`
PublicID string `json:"public_id" gorm:"column:public_id"`
Link string `json:"link" gorm:"column:link"`
TTL *time.Time `json:"TTL,omitempty" gorm:"column:ttl"`
RedirectionLimit *int `json:"redirection_limit,omitempty" gorm:"column:redirection_limit"`
CreatedAt *time.Time `json:"created_at" gorm:"column:created_at"`
DeletedAt *time.Time `json:"deleted_at" gorm:"column:deleted_at"`
ShortyAccesses []ShortyAccess `json:"accesses,omitempty" gorm:"-"`
ShortLink string `json:"short_link,omitempty" gorm:"-"`
Visits int `json:"visits" gorm:"visits"`
Redirects int `json:"redirects" gorm:"redirects"`
QRCode string `json:"qr_code,omitempty" gorm:"column:qr_code"`
}
35 changes: 35 additions & 0 deletions entity/shorty_repository.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package entity

import (
"fmt"
"strings"
"time"

"github.com/google/uuid"
Expand Down Expand Up @@ -37,6 +39,39 @@ func (r *ShortyRepository) List(limit, offset int) ([]*Shorty, error) {
return rows, nil
}

func (r *ShortyRepository) ListWithAccessData(listWithQRCode bool, limit, offset int) ([]*ShortyForList, error) {
rows := make([]*ShortyForList, 0)

fields := []string{
"s.id",
"s.created_at",
"s.deleted_at",
"s.public_id",
"s.link",
"s.ttl",
"s.redirection_limit",
}

if listWithQRCode {
fields = append(fields, "qr_code")
}

fieldlist := strings.Join(fields, ", ")

query := fmt.Sprintf(
`SELECT %s, count(sa.id) as visits, sum(CASE WHEN sa.status = 'redirected' THEN 1 ELSE 0 END) as redirects FROM shorties s
INNER JOIN shorty_accesses sa
ON s.id = sa.shorty_id
GROUP BY s.id, s.created_at, s.deleted_at, s.public_id, s.link, s.qr_code, s.ttl, s.redirection_limit
LIMIT ? OFFSET ?`, fieldlist)

if err := r.Database.Orm.Raw(query, limit, offset).Scan(&rows).Error; err != nil {
return nil, err
}

return rows, nil
}

func (r *ShortyRepository) Delete(id uuid.UUID) error {
m := Shorty{ID: id}
return r.Database.Orm.Model(m).
Expand Down
3 changes: 2 additions & 1 deletion http-requests/http-client.env.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"development": {
"host": "http://localhost:8080"
"host": "http://localhost:8080",
"token": "ThisIsA5uper$ecureAPIToken"
}
}
13 changes: 10 additions & 3 deletions http-requests/rest-api.http
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
### Create a short link

< {%
var currentDate = new Date(new Date().getTime() + 24 * 60 * 60 * 1000);
var day = currentDate.getDate()
var month = currentDate.getMonth() + 1
var year = currentDate.getFullYear()
client.global.set('date', year + '-' + month + '-' + day + 'T23:59:59Z');
%}

# curl -XPOST {{host}}/api/v1/short
# -H 'token: {{token}}'
# -H 'Content-Type: application/json'
Expand All @@ -10,7 +18,7 @@ Content-Type: application/json

{
"link": "https://www.brave.com/",
"TTL": "2023-05-25T23:59:59Z",
"TTL": "{{date}}",
"redirection_limit": 5,
"qr_code": {
"create": true,
Expand Down Expand Up @@ -56,7 +64,7 @@ token: {{token}}
### Get a list of links

# curl -H 'token: {{token}}' {{host}}/api/v1/short/?limit=20&offset=0
GET {{host}}/api/v1/short/?limit=20&offset=0
GET {{host}}/api/v1/short/?limit=20&offset=0&with_qr=false
token: {{token}}

> {%
Expand All @@ -71,4 +79,3 @@ token: {{token}}
%}

###

6 changes: 3 additions & 3 deletions service/shorty.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,10 @@ func (s *ShortyService) CreateVisit(publicID string, req *request.Redirect) (*en
return sh, nil
}

func (s *ShortyService) List(limit, offset int) ([]*entity.Shorty, error) {
shorties, err := s.shortyRepository.List(limit, offset)
func (s *ShortyService) List(withQR bool, limit, offset int) ([]*entity.ShortyForList, error) {
shorties, err := s.shortyRepository.ListWithAccessData(withQR, limit, offset)
if err != nil {
return []*entity.Shorty{}, err
return nil, err
}

return shorties, nil
Expand Down

0 comments on commit 964c5e4

Please sign in to comment.