mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 02:32:57 +00:00
dev day #92
This commit is contained in:
@@ -2261,10 +2261,14 @@ func (bc *BaseController) GetAdminMatches(c *gin.Context) {
|
||||
m["venue"] = *ov.VenueOverride
|
||||
}
|
||||
if ov.DateTimeOverride != nil {
|
||||
// Keep a consistent ISO string for machines and Czech human-readable for display
|
||||
m["date_time"] = ov.DateTimeOverride.Format(time.RFC3339)
|
||||
m["date"] = ov.DateTimeOverride.Format("2006-01-02 15:04")
|
||||
m["date"] = ov.DateTimeOverride.Format("02.01.2006")
|
||||
m["time"] = ov.DateTimeOverride.Format("15:04")
|
||||
}
|
||||
if ov.ScoreOverride != nil {
|
||||
m["score"] = strings.TrimSpace(*ov.ScoreOverride)
|
||||
}
|
||||
if ov.HomeLogoURL != nil {
|
||||
m["home_logo_url"] = *ov.HomeLogoURL
|
||||
}
|
||||
@@ -2323,6 +2327,7 @@ func (bc *BaseController) PutMatchOverride(c *gin.Context) {
|
||||
AwayNameOverride *string `json:"away_name_override"`
|
||||
VenueOverride *string `json:"venue_override"`
|
||||
DateTimeOverride *time.Time `json:"date_time_override"`
|
||||
ScoreOverride *string `json:"score_override"`
|
||||
HomeLogoURL *string `json:"home_logo_url"`
|
||||
AwayLogoURL *string `json:"away_logo_url"`
|
||||
Notes *string `json:"notes"`
|
||||
@@ -2345,6 +2350,7 @@ func (bc *BaseController) PutMatchOverride(c *gin.Context) {
|
||||
item.AwayNameOverride = body.AwayNameOverride
|
||||
item.VenueOverride = body.VenueOverride
|
||||
item.DateTimeOverride = body.DateTimeOverride
|
||||
item.ScoreOverride = body.ScoreOverride
|
||||
item.HomeLogoURL = body.HomeLogoURL
|
||||
item.AwayLogoURL = body.AwayLogoURL
|
||||
if body.Notes != nil {
|
||||
@@ -2387,12 +2393,29 @@ func (bc *BaseController) PatchMatchOverride(c *gin.Context) {
|
||||
}
|
||||
// Prevent changing the key
|
||||
delete(body, "external_match_id")
|
||||
// Normalize date_time_override to *time.Time if provided as string
|
||||
if v, ok := body["date_time_override"]; ok {
|
||||
switch vv := v.(type) {
|
||||
case string:
|
||||
s := strings.TrimSpace(vv)
|
||||
if s == "" {
|
||||
body["date_time_override"] = nil
|
||||
} else {
|
||||
if t, err := time.Parse(time.RFC3339, s); err == nil {
|
||||
body["date_time_override"] = &t
|
||||
} else if t2, err2 := time.Parse("2006-01-02T15:04", s); err2 == nil {
|
||||
body["date_time_override"] = &t2
|
||||
} else {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Neplatný formát date_time_override"})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := bc.DB.Model(&item).Updates(body).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Nelze uložit změny"})
|
||||
return
|
||||
}
|
||||
// Best-effort: write JSON snapshot to cache
|
||||
go bc.writeTeamLogoOverridesCache()
|
||||
c.JSON(http.StatusOK, item)
|
||||
}
|
||||
|
||||
@@ -2413,34 +2436,34 @@ func (bc *BaseController) GetTeamLogoOverrides(c *gin.Context) {
|
||||
// "by_id": { "<external_team_id>": { "name": "Team Name", "logo_url": "https://.../logo.png" } }
|
||||
// }
|
||||
func (bc *BaseController) GetPublicTeamLogoOverrides(c *gin.Context) {
|
||||
var items []models.TeamLogoOverride
|
||||
if err := bc.DB.Find(&items).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Chyba databáze"})
|
||||
return
|
||||
}
|
||||
m := make(map[string]string, len(items))
|
||||
byID := make(map[string]any, len(items))
|
||||
for _, it := range items {
|
||||
if it.TeamName != "" && it.LogoURL != "" {
|
||||
// Primary exact key
|
||||
m[it.TeamName] = it.LogoURL
|
||||
// Add smart aliases so frontends can match sponsor-shortened variants
|
||||
for _, alias := range generateTeamNameAliases(it.TeamName) {
|
||||
if alias != "" {
|
||||
m[alias] = it.LogoURL
|
||||
}
|
||||
}
|
||||
}
|
||||
if it.ExternalTeamID != "" {
|
||||
byID[it.ExternalTeamID] = map[string]string{
|
||||
"name": it.TeamName,
|
||||
"logo_url": it.LogoURL,
|
||||
}
|
||||
}
|
||||
}
|
||||
// Public cacheable response
|
||||
c.Header("Cache-Control", "public, max-age=120")
|
||||
c.JSON(http.StatusOK, gin.H{"by_name": m, "by_id": byID})
|
||||
var items []models.TeamLogoOverride
|
||||
if err := bc.DB.Find(&items).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Chyba databáze"})
|
||||
return
|
||||
}
|
||||
m := make(map[string]string, len(items))
|
||||
byID := make(map[string]any, len(items))
|
||||
for _, it := range items {
|
||||
if it.TeamName != "" && it.LogoURL != "" {
|
||||
// Primary exact key
|
||||
m[it.TeamName] = it.LogoURL
|
||||
// Add smart aliases so frontends can match sponsor-shortened variants
|
||||
for _, alias := range generateTeamNameAliases(it.TeamName) {
|
||||
if alias != "" {
|
||||
m[alias] = it.LogoURL
|
||||
}
|
||||
}
|
||||
}
|
||||
if it.ExternalTeamID != "" {
|
||||
byID[it.ExternalTeamID] = map[string]string{
|
||||
"name": it.TeamName,
|
||||
"logo_url": it.LogoURL,
|
||||
}
|
||||
}
|
||||
}
|
||||
// Public cacheable response
|
||||
c.Header("Cache-Control", "public, max-age=120")
|
||||
c.JSON(http.StatusOK, gin.H{"by_name": m, "by_id": byID})
|
||||
}
|
||||
|
||||
// writeTeamLogoOverridesCache writes a JSON snapshot of team-logo overrides to cache/prefetch/team_logo_overrides.json
|
||||
|
||||
@@ -386,6 +386,7 @@ type commentOutput struct {
|
||||
TargetLabel string `json:"target_label,omitempty"`
|
||||
ParentID *uint `json:"parent_id,omitempty"`
|
||||
Content string `json:"content"`
|
||||
ContentHTML string `json:"content_html,omitempty"`
|
||||
Status string `json:"status"`
|
||||
IsEdited bool `json:"is_edited"`
|
||||
EditedAt *time.Time `json:"edited_at"`
|
||||
@@ -542,6 +543,9 @@ func (cc *CommentController) GetComments(c *gin.Context) {
|
||||
|
||||
for _, r := range rows {
|
||||
co := toOutput(r)
|
||||
if role != "admin" {
|
||||
co.ContentHTML = services.MaskBadWordsHTML(co.Content)
|
||||
}
|
||||
if co.User.ID != 0 {
|
||||
if p, ok := profByUser[co.User.ID]; ok {
|
||||
if strings.TrimSpace(p.Username) != "" { co.User.Username = p.Username }
|
||||
@@ -620,12 +624,11 @@ func (cc *CommentController) CreateComment(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Spam evaluation and bad words filtering
|
||||
// Spam evaluation and moderation (do not alter stored content)
|
||||
score, rules := services.EvaluateSpamScore(content)
|
||||
filtered, _ := services.FilterBadWords(content)
|
||||
status := "visible"
|
||||
// Moderation only if sensitive terms detected
|
||||
if ok, _ := services.ContainsSensitiveWords(filtered); ok {
|
||||
if ok, _ := services.ContainsSensitiveWords(content); ok {
|
||||
status = "hidden"
|
||||
}
|
||||
rulesJSON, _ := json.Marshal(rules)
|
||||
@@ -635,7 +638,7 @@ func (cc *CommentController) CreateComment(c *gin.Context) {
|
||||
TargetID: in.TargetID,
|
||||
UserID: userID,
|
||||
ParentID: in.ParentID,
|
||||
Content: filtered,
|
||||
Content: content,
|
||||
Status: status,
|
||||
SpamScore: float32(score),
|
||||
SpamRules: string(rulesJSON),
|
||||
@@ -701,11 +704,10 @@ func (cc *CommentController) UpdateComment(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Filter & re-evaluate basic spam (do not auto-hide unless sensitive)
|
||||
// Re-evaluate basic spam, keep original content (masking is done on output)
|
||||
score, rules := services.EvaluateSpamScore(content)
|
||||
filtered, _ := services.FilterBadWords(content)
|
||||
now := time.Now()
|
||||
cm.Content = filtered
|
||||
cm.Content = content
|
||||
cm.IsEdited = true
|
||||
cm.EditedAt = &now
|
||||
cm.SpamScore = float32(score)
|
||||
|
||||
Reference in New Issue
Block a user