Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
7 changes: 7 additions & 0 deletions backend/cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,10 @@ func setupRouter(cfg *config.Config) *gin.Engine {

return router
}
func DebateWebsocketHandler(c *gin.Context) {
// TODO: implement real debate websocket logic.
// Temporary stub so the backend compiles and runs.
c.JSON(501, gin.H{
"error": "DebateWebsocketHandler not implemented yet",
})
}
108 changes: 52 additions & 56 deletions backend/config/config.go
Original file line number Diff line number Diff line change
@@ -1,76 +1,72 @@
package config

import (
"fmt"
"io/ioutil"
"fmt"
"io/ioutil"

"gopkg.in/yaml.v3"
"gopkg.in/yaml.v3"
)

type Config struct {
Server struct {
Port int `yaml:"port"`
} `yaml:"server"`
Server struct {
Port int `yaml:"port"`
} `yaml:"server"`

Cognito struct {
AppClientId string `yaml:"appClientId"`
AppClientSecret string `yaml:"appClientSecret"`
UserPoolId string `yaml:"userPoolId"`
Region string `yaml:"region"`
} `yaml:"cognito"`
Cognito struct {
AppClientId string `yaml:"appClientId"`
AppClientSecret string `yaml:"appClientSecret"`
UserPoolId string `yaml:"userPoolId"`
Region string `yaml:"region"`
} `yaml:"cognito"`

Openai struct {
GptApiKey string `yaml:"gptApiKey"`
} `yaml:"openai"`
Openai struct {
GptApiKey string `yaml:"gptApiKey"`
} `yaml:"openai"`

Gemini struct {
ApiKey string `yaml:"apiKey"`
} `yaml:"gemini"`
Gemini struct {
ApiKey string `yaml:"apiKey"`
} `yaml:"gemini"`

Database struct {
URI string `yaml:"uri"`
} `yaml:"database"`
Database struct {
URI string `yaml:"uri"`
} `yaml:"database"`

Redis struct {
Addr string `yaml:"addr"`
Password string `yaml:"password"`
DB int `yaml:"db"`
} `yaml:"redis"`
Redis struct {
URL string `yaml:"url"`
Password string `yaml:"password"`
DB int `yaml:"db"`
} `yaml:"redis"`

JWT struct {
Secret string `yaml:"secret"`
Expiry int `yaml:"expiry"`
}
JWT struct {
Secret string `yaml:"secret"`
Expiry int `yaml:"expiry"`
}

SMTP struct { // Add SMTP configuration
Host string
Port int
Username string // Gmail address
Password string // App Password
SenderEmail string // Same as Username for Gmail
SenderName string
}
GoogleOAuth struct {
ClientID string `yaml:"clientID"`
}
Redis struct {
URL string `yaml:"url"`
Password string `yaml:"password"`
DB int `yaml:"db"`
}
SMTP struct {
Host string
Port int
Username string
Password string
SenderEmail string
SenderName string
}

GoogleOAuth struct {
ClientID string `yaml:"clientID"`
}
}

// LoadConfig reads the configuration file
// LoadConfig reads config.yml
func LoadConfig(path string) (*Config, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("failed to read config file: %w", err)
}
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("failed to read config file: %w", err)
}

var cfg Config
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("failed to unmarshal yaml: %w", err)
}
var cfg Config
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("failed to unmarshal yaml: %w", err)
}

return &cfg, nil
return &cfg, nil
}
1 change: 1 addition & 0 deletions backend/controllers/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os"
"strings"
"time"
"log"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

PII logging creates compliance risk.

The log import enables logging statements in generateJWT (line 546) that log user email addresses. Logging PII such as emails may violate GDPR/CCPA requirements, especially if logs are retained, aggregated, or transmitted to third-party systems without proper safeguards.

Consider one of the following approaches:

  1. Remove email from log statements and use anonymized user IDs instead
  2. Implement structured logging with PII redaction/masking
  3. Ensure logs containing PII have appropriate retention policies and access controls

Apply this diff to remove email from the log statement:

-	log.Printf("JWT Generation - Email: %s, Now: %s, Expiry: %s (in %d minutes)", email, now.Format(time.RFC3339), expirationTime.Format(time.RFC3339), expiryMinutes)
+	log.Printf("JWT Generation - Now: %s, Expiry: %s (in %d minutes)", now.Format(time.RFC3339), expirationTime.Format(time.RFC3339), expiryMinutes)

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In backend/controllers/auth.go around lines 11 and 546, the file currently
imports the standard "log" (line 11) and later logs user email in generateJWT
(around line 546), which exposes PII; remove or change the log to avoid logging
the raw email — replace any email output with a non-PII identifier (e.g., user
ID or hashed/masked email) or remove the log entirely, and if the "log" import
becomes unused remove that import line; ensure any structured logging uses the
non-PII field and that the code still compiles after these changes.


"arguehub/config"
"arguehub/db"
Expand Down
15 changes: 2 additions & 13 deletions backend/controllers/team_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,15 +366,11 @@ func JoinTeam(c *gin.Context) {
for _, member := range team.Members {
totalElo += member.Elo
}
<<<<<<< HEAD
if len(team.Members) >= team.MaxSize {
=======
capacity := team.MaxSize
capacity = team.MaxSize
if capacity <= 0 {
capacity = 4
}
if len(team.Members) >= capacity {
>>>>>>> main
c.JSON(http.StatusBadRequest, gin.H{"error": "Team is already full"})
return
}
Expand All @@ -392,6 +388,7 @@ func JoinTeam(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "Successfully joined team"})
}


// LeaveTeam allows a user to leave a team
func LeaveTeam(c *gin.Context) {
teamID := c.Param("id")
Expand Down Expand Up @@ -630,19 +627,11 @@ func GetAvailableTeams(c *gin.Context) {
collection := db.GetCollection("teams")
cursor, err := collection.Find(context.Background(), bson.M{
"$expr": bson.M{
<<<<<<< HEAD
"$lt": []interface{}{
bson.M{"$size": "$members"},
"$maxSize",
},
},
=======
"$lt": bson.A{
bson.M{"$size": "$members"},
"$maxSize",
},
},
>>>>>>> main
})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve teams"})
Expand Down
2 changes: 1 addition & 1 deletion backend/controllers/transcript_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ func UpdatePendingTranscriptsHandler(c *gin.Context) {
c.JSON(401, gin.H{"error": "Invalid or expired token"})
return
}

email := "" // or load actual email
_ = email

err = services.UpdatePendingTranscripts()
Expand Down
3 changes: 2 additions & 1 deletion backend/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import (
"arguehub/models"
"context"
"fmt"
"log"
"net/url"
"time"

"github.com/redis/go-redis/v9"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/redis/go-redis/v9"
)

var MongoClient *mongo.Client
Expand Down
14 changes: 9 additions & 5 deletions backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ go 1.24
toolchain go1.24.4

require (
github.com/casbin/casbin/v2 v2.132.0
github.com/casbin/mongodb-adapter/v3 v3.7.0
github.com/gin-contrib/cors v1.7.2
github.com/gin-gonic/gin v1.10.0
github.com/golang-jwt/jwt/v5 v5.2.2
Expand All @@ -14,22 +16,21 @@ require (
go.mongodb.org/mongo-driver v1.17.3
golang.org/x/crypto v0.36.0
google.golang.org/api v0.228.0
google.golang.org/genai v1.34.0
google.golang.org/genai v1.37.0
gopkg.in/yaml.v3 v3.0.1
)

require (
cloud.google.com/go v0.116.0 // indirect
cloud.google.com/go/ai v0.8.0 // indirect
cloud.google.com/go/auth v0.15.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.6.0 // indirect
cloud.google.com/go/longrunning v0.5.7 // indirect
github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/casbin/casbin/v2 v2.132.0 // indirect
github.com/casbin/govaluate v1.3.0 // indirect
github.com/casbin/mongodb-adapter/v3 v3.7.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
Expand All @@ -44,6 +45,7 @@ require (
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/generative-ai-go v0.20.1 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
Expand All @@ -57,24 +59,26 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/montanaflynn/stats v0.7.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/redis/go-redis/v9 v9.16.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect
go.opentelemetry.io/otel v1.34.0 // indirect
go.opentelemetry.io/otel/metric v1.34.0 // indirect
go.opentelemetry.io/otel/trace v1.34.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/net v0.37.0 // indirect
golang.org/x/net v0.38.0 // indirect
golang.org/x/oauth2 v0.28.0 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
golang.org/x/time v0.11.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
google.golang.org/grpc v1.71.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
Expand Down
12 changes: 12 additions & 0 deletions backend/go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE=
cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U=
cloud.google.com/go/ai v0.8.0 h1:rXUEz8Wp2OlrM8r1bfmpF2+VKqc1VJpafE3HgzRnD/w=
cloud.google.com/go/ai v0.8.0/go.mod h1:t3Dfk4cM61sytiggo2UyGsDVW3RF1qGZaUKDrZFyqkE=
cloud.google.com/go/auth v0.15.0 h1:Ly0u4aA5vG/fsSsxu98qCQBemXtAtJf+95z9HK+cxps=
cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8=
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
Expand Down Expand Up @@ -62,11 +64,14 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/generative-ai-go v0.20.1 h1:6dEIujpgN2V0PgLhr6c/M1ynRdc7ARtiIDPFzj45uNQ=
github.com/google/generative-ai-go v0.20.1/go.mod h1:TjOnZJmZKzarWbjUJgy+r3Ee7HGBRVLhOIgupnwR4Bg=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
Expand Down Expand Up @@ -169,6 +174,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down Expand Up @@ -203,6 +210,11 @@ google.golang.org/api v0.228.0 h1:X2DJ/uoWGnY5obVjewbp8icSL5U4FzuCfy9OjbLSnLs=
google.golang.org/api v0.228.0/go.mod h1:wNvRS1Pbe8r4+IfBIniV8fwCpGwTrYa+kMUDiC5z5a4=
google.golang.org/genai v1.34.0 h1:lPRJRO+HqRX1SwFo1Xb/22nZ5MBEPUbXDl61OoDxlbY=
google.golang.org/genai v1.34.0/go.mod h1:7pAilaICJlQBonjKKJNhftDFv3SREhZcTe9F6nRcjbg=
google.golang.org/genai v1.37.0 h1:dgp71k1wQ+/+APdZrN3LFgAGnVnr5IdTF1Oj0Dg+BQc=
google.golang.org/genai v1.37.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk=
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 h1:BulPr26Jqjnd4eYDVe+YvyR7Yc2vJGkO5/0UxD0/jZU=
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 h1:GVIKPyP/kLIyVOgOnTwFOrvQaQUzOzGMCxgFUOEmm24=
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:iK2jbkWL86DXjEx0qiHcRE9dE4/Ahua5k6V8OWFb//c=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
Expand Down
35 changes: 10 additions & 25 deletions backend/models/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,19 @@ type Admin struct {

// Comment represents a comment that can be moderated
// This can be a TeamDebateMessage, TeamChatMessage, or other user-generated content
type Comment struct {
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
Type string `bson:"type" json:"type"` // "team_debate_message", "team_chat_message", "debate_vs_bot_message"
Content string `bson:"content" json:"content"`
UserID primitive.ObjectID `bson:"userId" json:"userId"`
UserEmail string `bson:"userEmail" json:"userEmail"`
DisplayName string `bson:"displayName" json:"displayName"`
DebateID primitive.ObjectID `bson:"debateId,omitempty" json:"debateId,omitempty"`
TeamID primitive.ObjectID `bson:"teamId,omitempty" json:"teamId,omitempty"`
CreatedAt time.Time `bson:"createdAt" json:"createdAt"`
IsDeleted bool `bson:"isDeleted" json:"isDeleted"`
DeletedAt *time.Time `bson:"deletedAt,omitempty" json:"deletedAt,omitempty"`
DeletedBy *primitive.ObjectID `bson:"deletedBy,omitempty" json:"deletedBy,omitempty"`
}

// AdminActionLog represents a log entry for admin actions
type AdminActionLog struct {
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
AdminID primitive.ObjectID `bson:"adminId" json:"adminId"`
AdminEmail string `bson:"adminEmail" json:"adminEmail"`
Action string `bson:"action" json:"action"` // "delete_debate", "delete_comment", etc.
ResourceType string `bson:"resourceType" json:"resourceType"` // "debate", "comment", etc.
ResourceID primitive.ObjectID `bson:"resourceId" json:"resourceId"`
IPAddress string `bson:"ipAddress" json:"ipAddress"`
UserAgent string `bson:"userAgent" json:"userAgent"`
DeviceInfo string `bson:"deviceInfo,omitempty" json:"deviceInfo,omitempty"`
Timestamp time.Time `bson:"timestamp" json:"timestamp"`
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
AdminID primitive.ObjectID `bson:"adminId" json:"adminId"`
AdminEmail string `bson:"adminEmail" json:"adminEmail"`
Action string `bson:"action" json:"action"` // "delete_debate", "delete_comment", etc.
ResourceType string `bson:"resourceType" json:"resourceType"` // "debate", "comment", etc.
ResourceID primitive.ObjectID `bson:"resourceId" json:"resourceId"`
IPAddress string `bson:"ipAddress" json:"ipAddress"`
UserAgent string `bson:"userAgent" json:"userAgent"`
DeviceInfo string `bson:"deviceInfo,omitempty" json:"deviceInfo,omitempty"`
Timestamp time.Time `bson:"timestamp" json:"timestamp"`
Details map[string]interface{} `bson:"details,omitempty" json:"details,omitempty"`
}

Expand All @@ -61,4 +47,3 @@ type AnalyticsSnapshot struct {
CommentsToday int64 `bson:"commentsToday" json:"commentsToday"`
NewUsersToday int64 `bson:"newUsersToday" json:"newUsersToday"`
}

Loading