package server import ( "fmt" "html/template" "log" "net/http" "strings" "github.com/go-chi/chi/v5" gossh "golang.org/x/crypto/ssh" "battleship-arena/internal/storage" ) func HandleUserProfile(w http.ResponseWriter, r *http.Request) { username := chi.URLParam(r, "username") if username == "" { http.Redirect(w, r, "/", http.StatusSeeOther) return } user, err := storage.GetUserByUsername(username) if err != nil { http.Error(w, "Error loading user", http.StatusInternalServerError) return } if user == nil { http.Error(w, "User not found", http.StatusNotFound) return } // Get user's submission stats entries, _ := storage.GetLeaderboard(100) var userEntry *storage.LeaderboardEntry for _, e := range entries { if e.Username == username { userEntry = &e break } } // Get user's submissions with stats submissions, err := storage.GetUserSubmissionsWithStats(username) if err != nil { log.Printf("Error getting submissions for %s: %v", username, err) submissions = []storage.SubmissionWithStats{} } if submissions == nil { submissions = []storage.SubmissionWithStats{} } log.Printf("Found %d submissions for %s", len(submissions), username) // Parse public key for display publicKeyDisplay := formatPublicKey(user.PublicKey) tmpl := template.Must(template.New("user").Parse(userProfileHTML)) data := struct { User *storage.User Entry *storage.LeaderboardEntry Submissions []storage.SubmissionWithStats PublicKeyDisplay string ServerURL string }{ User: user, Entry: userEntry, Submissions: submissions, PublicKeyDisplay: publicKeyDisplay, ServerURL: GetServerURL(), } tmpl.Execute(w, data) } func HandleUsers(w http.ResponseWriter, r *http.Request) { users, err := storage.GetAllUsers() if err != nil { http.Error(w, "Error loading users", http.StatusInternalServerError) return } data := struct { Users []storage.User ServerURL string }{ Users: users, ServerURL: GetServerURL(), } tmpl := template.Must(template.New("users").Parse(usersListHTML)) tmpl.Execute(w, data) } func formatPublicKey(key string) string { key = strings.TrimSpace(key) parts := strings.Fields(key) if len(parts) < 2 { return key } // Parse the key to get fingerprint pubKey, _, _, _, err := gossh.ParseAuthorizedKey([]byte(key)) if err != nil { return key } fingerprint := gossh.FingerprintSHA256(pubKey) return fmt.Sprintf("%s %s", parts[0], fingerprint) } const userProfileHTML = `
| Filename | Uploaded | Rating | Wins | Losses | Win Rate | Avg Moves | Status | Active |
|---|---|---|---|---|---|---|---|---|
| {{.Filename}} | {{.UploadTime.Format "Jan 2, 3:04 PM"}} | {{if .HasMatches}}{{.Rating}} ±{{.RD}}{{else}}-{{end}} | {{if .HasMatches}}{{.Wins}}{{else}}-{{end}} | {{if .HasMatches}}{{.Losses}}{{else}}-{{end}} | {{if .HasMatches}} {{if ge .WinPct 60.0}}{{printf "%.1f" .WinPct}}%{{end}} {{if and (lt .WinPct 60.0) (ge .WinPct 40.0)}}{{printf "%.1f" .WinPct}}%{{end}} {{if lt .WinPct 40.0}}{{printf "%.1f" .WinPct}}%{{end}} {{else}}-{{end}} | {{if .HasMatches}}{{printf "%.1f" .AvgMoves}}{{else}}-{{end}} | {{if eq .Status "completed"}}✓{{end}} {{if eq .Status "pending"}}⏳{{end}} {{if eq .Status "testing"}}⚙️{{end}} {{if eq .Status "failed"}}✗{{end}} | {{if .IsActive}}●{{else}}○{{end}} |
{{len .Users}} registered users