Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion backend/controllers/team_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,10 @@ func JoinTeam(c *gin.Context) {
for _, member := range team.Members {
totalElo += member.Elo
}
if len(team.Members) >= team.MaxSize {
c.JSON(http.StatusBadRequest, gin.H{"error": "Team is already full"})
return
}
totalElo += newMember.Elo
newAverageElo := totalElo / float64(len(team.Members)+1)

Expand Down Expand Up @@ -591,7 +595,12 @@ func GetTeamMemberProfile(c *gin.Context) {
func GetAvailableTeams(c *gin.Context) {
collection := db.GetCollection("teams")
cursor, err := collection.Find(context.Background(), bson.M{
"$expr": bson.M{"$lt": []interface{}{bson.M{"$size": "$members"}, 4}}, // Teams with less than 4 members
"$expr": bson.M{
"$lt": []interface{}{
bson.M{"$size": "$members"},
"$maxSize",
},
},
})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve teams"})
Expand Down
11 changes: 8 additions & 3 deletions backend/controllers/team_matchmaking.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package controllers
import (
"context"
"net/http"
"time"

"arguehub/db"
"arguehub/models"
Expand Down Expand Up @@ -32,7 +33,9 @@ func JoinMatchmaking(c *gin.Context) {
// Get team
collection := db.GetCollection("teams")
var team models.Team
err = collection.FindOne(context.Background(), bson.M{"_id": objectID}).Decode(&team)
ctx, cancel := context.WithTimeout(c.Request.Context(), 5*time.Second)
defer cancel()
err = collection.FindOne(ctx, bson.M{"_id": objectID}).Decode(&team)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Team not found"})
return
Expand Down Expand Up @@ -85,14 +88,16 @@ func LeaveMatchmaking(c *gin.Context) {

collection := db.GetCollection("teams")
var team models.Team
if err := collection.FindOne(context.Background(), bson.M{"_id": objectID}).Decode(&team); err != nil {
ctxLeave, cancelLeave := context.WithTimeout(c.Request.Context(), 5*time.Second)
defer cancelLeave()
if err := collection.FindOne(ctxLeave, bson.M{"_id": objectID}).Decode(&team); err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Team not found"})
return
}

userObjectID, ok := userID.(primitive.ObjectID)
if !ok || team.CaptainID != userObjectID {
c.JSON(http.StatusForbidden, gin.H{"error": "Only the captain can remove the team from matchmaking"})
c.JSON(http.StatusForbidden, gin.H{"error": "Only the captain can leave matchmaking"})
return
}

Expand Down
20 changes: 17 additions & 3 deletions backend/middlewares/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ import (
"arguehub/db"
"arguehub/models"
"context"
"errors"
"fmt"
"log"
"net/http"
"strings"
"time"

"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)

func AuthMiddleware(configPath string) gin.HandlerFunc {
Expand Down Expand Up @@ -46,10 +49,16 @@ func AuthMiddleware(configPath string) gin.HandlerFunc {
return
}

email := claims["sub"].(string)
email, ok := claims["sub"].(string)
if !ok || email == "" {
log.Printf("Invalid or missing 'sub' claim in JWT")
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token claims"})
c.Abort()
return
}

// Fetch user from database
dbCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
dbCtx, cancel := context.WithTimeout(c.Request.Context(), 5*time.Second)
defer cancel()

if db.MongoDatabase == nil {
Expand All @@ -61,7 +70,12 @@ func AuthMiddleware(configPath string) gin.HandlerFunc {
var user models.User
err = db.MongoDatabase.Collection("users").FindOne(dbCtx, bson.M{"email": email}).Decode(&user)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"})
if errors.Is(err, mongo.ErrNoDocuments) {
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"})
} else {
log.Printf("Failed to load user %s: %v", email, err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "Authentication lookup failed"})
}
c.Abort()
return
}
Expand Down
20 changes: 10 additions & 10 deletions backend/models/team.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,22 +108,22 @@ type TeamChatMessage struct {
// MarshalJSON customizes JSON serialization for TeamDebate to convert ObjectIDs to hex strings
func (td TeamDebate) MarshalJSON() ([]byte, error) {
type Alias TeamDebate
var currentUserHex *string
if !td.CurrentUserID.IsZero() {
hex := td.CurrentUserID.Hex()
currentUserHex = &hex
}
return json.Marshal(&struct {
ID string `json:"id,omitempty"`
Team1ID string `json:"team1Id"`
Team2ID string `json:"team2Id"`
CurrentUserID string `json:"currentUserId,omitempty"`
ID string `json:"id,omitempty"`
Team1ID string `json:"team1Id"`
Team2ID string `json:"team2Id"`
CurrentUserID *string `json:"currentUserId,omitempty"`
*Alias
}{
ID: td.ID.Hex(),
Team1ID: td.Team1ID.Hex(),
Team2ID: td.Team2ID.Hex(),
CurrentUserID: func() string {
if td.CurrentUserID.IsZero() {
return ""
}
return td.CurrentUserID.Hex()
}(),
CurrentUserID: currentUserHex,
Alias: (*Alias)(&td),
})
}
Expand Down
11 changes: 7 additions & 4 deletions backend/services/team_matchmaking.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ func StartTeamMatchmaking(teamID primitive.ObjectID) error {
// Get team details
collection := db.GetCollection("teams")
var team models.Team
err := collection.FindOne(context.Background(), bson.M{"_id": teamID}).Decode(&team)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
err := collection.FindOne(ctx, bson.M{"_id": teamID}).Decode(&team)
if err != nil {
return err
}
Expand Down Expand Up @@ -66,7 +68,7 @@ func FindMatchingTeam(lookingTeamID primitive.ObjectID) (*models.Team, error) {
defer teamMatchmakingMutex.RUnlock()

if teamMatchmakingPool == nil {
teamMatchmakingPool = make(map[string]*TeamMatchmakingEntry)
return nil, mongo.ErrNoDocuments
}

lookingEntry, exists := teamMatchmakingPool[lookingTeamID.Hex()]
Expand Down Expand Up @@ -116,8 +118,9 @@ func GetMatchmakingPool() map[string]*TeamMatchmakingEntry {
return make(map[string]*TeamMatchmakingEntry)
}
snapshot := make(map[string]*TeamMatchmakingEntry, len(teamMatchmakingPool))
for id, entry := range teamMatchmakingPool {
snapshot[id] = entry
for teamID, entry := range teamMatchmakingPool {
clone := *entry
snapshot[teamID] = &clone
}
return snapshot
}
4 changes: 2 additions & 2 deletions backend/services/team_turn_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ func (tbs *TokenBucketService) GetRemainingTokens(teamID, userID primitive.Objec
return 0
}

bucket.Mutex.RLock()
defer bucket.Mutex.RUnlock()
bucket.Mutex.Lock()
defer bucket.Mutex.Unlock()

// Refill tokens based on time elapsed
tbs.refillTokens(bucket)
Expand Down
6 changes: 3 additions & 3 deletions backend/websocket/team_debate_handler.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package websocket

import (
"context"
"encoding/json"
"time"

Expand Down Expand Up @@ -61,7 +62,7 @@ func TeamDebateHubRun() {
// Load debate from database
collection := db.GetCollection("team_debates")
var debate models.TeamDebate
err := collection.FindOne(nil, bson.M{"_id": client.debateID}).Decode(&debate)
err := collection.FindOne(context.Background(), bson.M{"_id": client.debateID}).Decode(&debate)
if err == nil {
room = &TeamDebateRoom{
debate: debate,
Expand All @@ -79,7 +80,6 @@ func TeamDebateHubRun() {
room.team2Clients[client] = true
}

// Send current debate state to new client
room.broadcastToTeam(client, TeamDebateMessage{
Type: "state",
Data: room.debate,
Expand Down Expand Up @@ -194,7 +194,7 @@ func (c *TeamDebateClient) readPump() {
Timestamp: time.Now(),
}

_, err := collection.InsertOne(nil, msg)
_, err := collection.InsertOne(context.Background(), msg)
if err != nil {
}

Expand Down
Loading