Skip to content

Commit

Permalink
[api] bind req params to structs
Browse files Browse the repository at this point in the history
  • Loading branch information
beesaferoot committed Jul 14, 2024
1 parent c3ed3ea commit a6a7f5c
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 38 deletions.
31 changes: 19 additions & 12 deletions api/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"auxstream/db"
"fmt"
"net/http"
"strings"

"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
Expand All @@ -27,17 +26,26 @@ func CookieAuthMiddleware(c *gin.Context) {
c.Next()
}

type AuthForm struct {
Username string `form:"username" binding:"required"`
Password string `form:"password" binding:"required"`
}

func Signup(c *gin.Context) {
username := c.PostForm("username")
password := c.PostForm("password")
var form AuthForm

if err := c.ShouldBind(&form); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

pHash, err := hashPassword(password)
pHash, err := hashPassword(form.Password)
if err != nil {
fmt.Println("password hash failure: ", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to signup user"})
return
}
err = db.DAO.CreateUser(c, username, pHash)
err = db.DAO.CreateUser(c, form.Username, pHash)
if err != nil {
fmt.Println("CreateUser: ", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to signup user"})
Expand All @@ -49,22 +57,21 @@ func Signup(c *gin.Context) {

func Login(c *gin.Context) {
session := sessions.Default(c)
username := c.PostForm("username")
password := c.PostForm("password")

// Validate form input
if strings.Trim(username, "") == " " || strings.Trim(password, " ") == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "parameters can't be empty"})
var form AuthForm

if err := c.ShouldBind(&form); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

user, err := db.DAO.GetUserWithUsername(c, username)
user, err := db.DAO.GetUserWithUsername(c, form.Username)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "user not found"})
return
}

if !cmpHashString(user.PasswordHash, password) {
if !cmpHashString(user.PasswordHash, form.Password) {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid username or password"})
return
}
Expand Down
63 changes: 42 additions & 21 deletions api/track.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"github.com/gin-gonic/gin"
"mime/multipart"
"net/http"
"strconv"
)

// FetchTracksByArtistHandler fetch tracks by artist (limit results < 100)
Expand All @@ -25,15 +24,25 @@ func FetchTracksByArtistHandler(c *gin.Context) {

}

type FetchTrackQueryParams struct {
PageSize int8 `form:"pagesize" binding:"gte=0"`
PageNum int8 `form:"pagenumber" binding:"gte=1"`
}

// FetchTracksHandler fetch paginated tracks with limit on page size
func FetchTracksHandler(c *gin.Context) {
pagesize := c.Query("pagesize")
pagenumber := c.Query("pagenumber")
var reqParams FetchTrackQueryParams

limit, _ := strconv.Atoi(pagesize)
offset, _ := strconv.Atoi(pagenumber)
fmt.Printf("pagesize: %s\npagenum: %s\n ", c.Query("pagesize"), c.Query("pagenumber"))
if err := c.ShouldBindQuery(&reqParams); err != nil {
c.JSON(http.StatusBadRequest, errorResponse(err.Error()))
return
}

tracks, err := db.DAO.GetTracks(c, int32(limit), int32((offset-1)*limit))
limit := reqParams.PageSize
offset := (reqParams.PageNum - 1) * reqParams.PageSize

tracks, err := db.DAO.GetTracks(c, limit, offset)
if err != nil {
c.JSON(http.StatusInternalServerError, errorResponse(err.Error()))
return
Expand All @@ -45,16 +54,24 @@ func FetchTracksHandler(c *gin.Context) {

}

type AddTrackForm struct {
Title string `form:"title" binding:"required"`
ArtistId int `form:"artist_id" binding:"required"`
Audio *multipart.FileHeader `form:"audio" binding:"required"`
}

// AddTrackHandler add track to the system
func AddTrackHandler(c *gin.Context) {
form, _ := c.MultipartForm()
trackTittle := form.Value["title"][0]
trackArtistId, err := strconv.Atoi(form.Value["artist_id"][0])
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse("artistId should be a valid number"))
var reqForm AddTrackForm
if err := c.ShouldBind(&reqForm); err != nil {
c.JSON(http.StatusBadRequest, errorResponse(err.Error()))
return
}
file := form.File["audio"][0]

trackTittle := reqForm.Title
trackArtistId := reqForm.ArtistId
file := reqForm.Audio

if file.Size <= 0 {
c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse("audio for track not found"))
return
Expand All @@ -81,18 +98,22 @@ func AddTrackHandler(c *gin.Context) {
})
}

type BulkTrackUploadForm struct {
Titles []string `form:"track_titles" binding:"required"`
Files []*multipart.FileHeader `form:"track_files" binding:"required"`
ArtistId int `form:"artist_id" binding:"required"`
}

// BulkTrackUploadHandler enables bulk track uploads
func BulkTrackUploadHandler(c *gin.Context) {
form, _ := c.MultipartForm()
titles := form.Value["track_title"]
files := form.File["track_files"]
artistId, err := strconv.Atoi(form.Value["artist_id"][0])
var reqForm BulkTrackUploadForm

if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(fmt.Sprintf("invalid artist_id value: %s", err.Error())))
if err := c.ShouldBind(&reqForm); err != nil {
c.JSON(http.StatusBadRequest, errorResponse(err.Error()))
return
}

fileNames, err := processFiles(files)
fileNames, err := processFiles(reqForm.Files)

if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(fmt.Sprintf("audio upload failed: %s", err.Error())))
Expand All @@ -104,11 +125,11 @@ func BulkTrackUploadHandler(c *gin.Context) {
// filter tracks that failed to upload
for idx, fileName := range fileNames {
if fileName != "" {
trackTitles = append(trackTitles, titles[idx])
trackTitles = append(trackTitles, reqForm.Titles[idx])
filteredFileNames = append(filteredFileNames, fileName)
}
}
rows, err := db.DAO.BulkCreateTracks(c, trackTitles, artistId, filteredFileNames)
rows, err := db.DAO.BulkCreateTracks(c, trackTitles, reqForm.ArtistId, filteredFileNames)

if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(fmt.Sprintf("audio upload failed: %s", err.Error())))
Expand Down
2 changes: 1 addition & 1 deletion app.env
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
DATABASE_URL=postgresql://postgres:secret@127.0.0.1:5432/auxstreamdb?sslmode=disable
SESSION_STRING=test_random_string
GIN_MODE=release
GIN_MODE=debug
PORT=5009
Addr=127.0.0.1
2 changes: 1 addition & 1 deletion db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func (dao *DataBaseAccessObject) SearchTrackByArtist(ctx context.Context,
return GetTrackByArtist(ctx, artist)
}

func (dao *DataBaseAccessObject) GetTracks(ctx context.Context, limit int32, offset int32) (tracks []*Track, err error) {
func (dao *DataBaseAccessObject) GetTracks(ctx context.Context, limit int8, offset int8) (tracks []*Track, err error) {
return GetTracks(ctx, limit, offset)
}

Expand Down
4 changes: 3 additions & 1 deletion db/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package db

import (
"context"
"fmt"
"github.com/jackc/pgx/v5"
"time"
)
Expand Down Expand Up @@ -61,7 +62,8 @@ func (artist *Artist) Commit(ctx context.Context) (err error) {
return
}

func GetTracks(ctx context.Context, limit int32, offset int32) (tracks []*Track, err error) {
func GetTracks(ctx context.Context, limit int8, offset int8) (tracks []*Track, err error) {
fmt.Printf("GetTracks: limit: %d, offset: %d\n", limit, offset)
tracks = []*Track{}
stmt := `SELECT id, title, artist_id, file, created_at
FROM auxstream.tracks
Expand Down
4 changes: 2 additions & 2 deletions tests/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func TestHTTPTrackUploadBatch(t *testing.T) {
formData := url.Values{}
formData.Add("artist_id", strconv.Itoa(artistId))
for i := 0; i < testRecordCnt; i++ {
formData.Add("track_title", fmt.Sprintf("#%d", i))
formData.Add("track_titles", fmt.Sprintf("#%d", i))
}

post, err := req.Post(tserver.URL+"/upload_batch_track", formData, trackFiles)
Expand All @@ -155,7 +155,7 @@ func TestHTTPFetchTracks(t *testing.T) {
mockConn.ExpectQuery(`
SELECT id, title, artist_id, file, created_at
`).
WithArgs(int32(2), int32(0)).
WithArgs(int8(2), int8(0)).
WillReturnRows(pgxmock.NewRows(columns).
AddRow(1, "Title", 1, "Test file", time.Now()).
AddRow(1, "Title", 1, "Test file", time.Now()).
Expand Down

0 comments on commit a6a7f5c

Please sign in to comment.