Initial commit: party-mix-app with prefetch cache, audio preload optimizations
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
173
apps/backend/internal/handlers/party.go
Normal file
173
apps/backend/internal/handlers/party.go
Normal file
@@ -0,0 +1,173 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"github.com/toyffee/party-mix/internal/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const codeChars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
|
||||
|
||||
func generateCode() string {
|
||||
b := make([]byte, 6)
|
||||
for i := range b {
|
||||
b[i] = codeChars[rand.Intn(len(codeChars))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
type createPartyReq struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
TelegramID int64 `json:"telegram_id"`
|
||||
}
|
||||
|
||||
func CreateParty(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var req createPartyReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
party := models.Party{
|
||||
ID: uuid.NewString(),
|
||||
Name: req.Name,
|
||||
Code: generateCode(),
|
||||
TelegramID: req.TelegramID,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
if err := db.Create(&party).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create party"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, party)
|
||||
}
|
||||
}
|
||||
|
||||
func GetParty(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var party models.Party
|
||||
err := db.Preload("Participants.Tracks").First(&party, "id = ?", c.Param("id")).Error
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "party not found"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, party)
|
||||
}
|
||||
}
|
||||
|
||||
func GetPartyByCode(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var party models.Party
|
||||
err := db.Preload("Participants.Tracks").First(&party, "code = ?", c.Param("code")).Error
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "party not found"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, party)
|
||||
}
|
||||
}
|
||||
|
||||
type addParticipantReq struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Tracks []string `json:"tracks" binding:"required"`
|
||||
ColorBg string `json:"color_bg"`
|
||||
ColorText string `json:"color_text"`
|
||||
}
|
||||
|
||||
func AddParticipant(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var req addParticipantReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
participant := models.Participant{
|
||||
ID: uuid.NewString(),
|
||||
PartyID: c.Param("id"),
|
||||
Name: req.Name,
|
||||
ColorBg: req.ColorBg,
|
||||
ColorText: req.ColorText,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
tracks := make([]models.Track, 0, len(req.Tracks))
|
||||
for i, title := range req.Tracks {
|
||||
tracks = append(tracks, models.Track{
|
||||
ID: uuid.NewString(),
|
||||
ParticipantID: participant.ID,
|
||||
Title: title,
|
||||
Position: i,
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
}
|
||||
participant.Tracks = tracks
|
||||
if err := db.Create(&participant).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to add participant"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, participant)
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveParticipant(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
pid := c.Param("pid")
|
||||
db.Where("participant_id = ?", pid).Delete(&models.Track{})
|
||||
if err := db.Delete(&models.Participant{}, "id = ?", pid).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to remove participant"})
|
||||
return
|
||||
}
|
||||
c.Status(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
type addHistoryReq struct {
|
||||
Title string `json:"title"`
|
||||
Artist string `json:"artist"`
|
||||
ImgURL string `json:"img_url"`
|
||||
OwnerName string `json:"owner_name"`
|
||||
OwnerColorBg string `json:"owner_color_bg"`
|
||||
OwnerColorText string `json:"owner_color_text"`
|
||||
}
|
||||
|
||||
func AddHistory(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var req addHistoryReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
item := models.HistoryItem{
|
||||
ID: uuid.NewString(),
|
||||
PartyID: c.Param("id"),
|
||||
Title: req.Title,
|
||||
Artist: req.Artist,
|
||||
ImgURL: req.ImgURL,
|
||||
OwnerName: req.OwnerName,
|
||||
OwnerColorBg: req.OwnerColorBg,
|
||||
OwnerColorText: req.OwnerColorText,
|
||||
PlayedAt: time.Now(),
|
||||
}
|
||||
db.Create(&item)
|
||||
c.JSON(http.StatusCreated, item)
|
||||
}
|
||||
}
|
||||
|
||||
func GetHistory(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var items []models.HistoryItem
|
||||
db.Where("party_id = ?", c.Param("id")).Order("played_at desc").Limit(100).Find(&items)
|
||||
c.JSON(http.StatusOK, items)
|
||||
}
|
||||
}
|
||||
|
||||
func ClearHistory(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
db.Where("party_id = ?", c.Param("id")).Delete(&models.HistoryItem{})
|
||||
c.Status(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user