package main import ( "crypto/tls" "encoding/json" "fmt" "io" "log" "net/http" "os" "os/exec" "strings" "time" "gopkg.in/gomail.v2" ) type TripEntry struct { Name string `json:"name"` Vehicle string `json:"vehicle"` Destination string `json:"destination"` DateStart string `json:"date_start"` TimeStart string `json:"time_start"` DateEnd string `json:"date_end"` TimeEnd string `json:"time_end"` Purpose string `json:"purpose"` KmStart int `json:"km_start"` KmEnd int `json:"km_end"` Coordinates *GeoCoords `json:"coordinates,omitempty"` } type GeoCoords struct { Lat string `json:"lat"` Lng string `json:"lng"` } func main() { log.SetFlags(log.LstdFlags | log.Lshortfile) http.HandleFunc("/submit", enableCORS(handleSubmit)) http.HandleFunc("/health", enableCORS(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"status":"ok"}`)) })) http.HandleFunc("/", enableCORS(func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "index.html") })) http.HandleFunc("/evidence-aut", enableCORS(func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "evidence-aut.html") })) // Add folder opener endpoint http.HandleFunc("/open", enableCORS(openFolderHandler)) port := os.Getenv("PORT") if port == "" { port = "8080" } log.Printf("Server běží na portu %s (včetně otevírání složek Windows)", port) err := http.ListenAndServe(":"+port, nil) if err != nil { log.Fatalf("Chyba při spuštění serveru: %v", err) } } func enableCORS(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") if r.Method == "OPTIONS" { w.WriteHeader(http.StatusOK) return } if next != nil { next(w, r) } } } func handleSubmit(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") if r.Method != http.MethodPost { if r.Method == http.MethodOptions { w.WriteHeader(http.StatusOK) return } w.WriteHeader(http.StatusMethodNotAllowed) w.Write([]byte(`{"error":"Only POST method is allowed"}`)) return } body, err := io.ReadAll(r.Body) if err != nil { log.Printf("Chyba při čtení těla požadavku: %v", err) w.WriteHeader(http.StatusBadRequest) w.Write([]byte(`{"error":"Failed to read request body"}`)) return } defer r.Body.Close() log.Printf("Přijatá data: %s", string(body)) var entry TripEntry err = json.Unmarshal(body, &entry) if err != nil { log.Printf("Chyba při parsování JSON: %v", err) w.WriteHeader(http.StatusBadRequest) w.Write([]byte(fmt.Sprintf(`{"error":"Failed to parse JSON: %v"}`, err))) return } if entry.Name == "" || entry.Destination == "" || entry.DateStart == "" || entry.DateEnd == "" || entry.Purpose == "" { log.Printf("Chybějící povinná pole: %+v", entry) w.WriteHeader(http.StatusBadRequest) w.Write([]byte(`{"error":"Missing required fields"}`)) return } if entry.KmEnd < entry.KmStart { log.Printf("Neplatný stav tachometru: %d -> %d", entry.KmStart, entry.KmEnd) w.WriteHeader(http.StatusBadRequest) w.Write([]byte(`{"error":"End kilometers must be greater than or equal to start kilometers"}`)) return } // Formátování dat do českého formátu czechMonths := []string{ "ledna", "února", "března", "dubna", "května", "června", "července", "srpna", "září", "října", "listopadu", "prosince", } // Zpracování začátku cesty parsedDateStart, err := time.Parse("2006-01-02", entry.DateStart) if err != nil { log.Printf("Chyba při parsování data začátku: %v", err) } // Zpracování konce cesty parsedDateEnd, err := time.Parse("2006-01-02", entry.DateEnd) if err != nil { log.Printf("Chyba při parsování data konce: %v", err) } err = sendEmail(entry, parsedDateStart, parsedDateEnd, czechMonths) if err != nil { log.Printf("Chyba při odesílání emailu: %v", err) w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf(`{"error":"Failed to send email: %v"}`, err))) return } w.WriteHeader(http.StatusOK) w.Write([]byte(`{"message":"Záznam byl úspěšně uložen a email odeslán"}`)) } // Handler pro otevírání Windows složek přímo z prohlížeče func openFolderHandler(w http.ResponseWriter, r *http.Request) { // Get the folder path from the query parameter folderPath := r.URL.Query().Get("path") if folderPath == "" { http.Error(w, "Missing path parameter", http.StatusBadRequest) return } // Log the request log.Printf("Otevírání složky: %s", folderPath) // Open the folder in Windows Explorer cmd := exec.Command("explorer.exe", folderPath) err := cmd.Start() if err != nil { // If there was an error, try to clean the path and retry cleanPath := strings.ReplaceAll(folderPath, "/", "\\") cmd = exec.Command("explorer.exe", cleanPath) err = cmd.Start() if err != nil { log.Printf("Chyba při otevírání složky: %v", err) http.Error(w, fmt.Sprintf("Error opening folder: %v", err), http.StatusInternalServerError) return } } // Return success response w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]string{"status": "success", "message": fmt.Sprintf("Opening folder: %s", folderPath)}) } func sendEmail(entry TripEntry, parsedDateStart, parsedDateEnd time.Time, czechMonths []string) error { smtpHost := "mail.pp-kunovice.cz" smtpPort := 465 sender := "sluzebnicek@pp-kunovice.cz" password := "7g}qznB5bj" recipient := "sluzebnicek@pp-kunovice.cz" m := gomail.NewMessage() m.SetHeader("From", sender) m.SetHeader("To", recipient) m.SetHeader("Subject", "Nový záznam o jízdě služebním autem") var htmlContent strings.Builder htmlContent.WriteString(` Záznam o jízdě služebním autem

Záznam o jízdě služebním autem

`) // Formátování dat a časů pro zobrazení formattedDateStart := "" if parsedDateStart.IsZero() == false { monthNameStart := czechMonths[parsedDateStart.Month()-1] formattedDateStart = fmt.Sprintf("%d. %s %d", parsedDateStart.Day(), monthNameStart, parsedDateStart.Year()) } else { formattedDateStart = entry.DateStart } formattedDateEnd := "" if !parsedDateEnd.IsZero() { monthNameEnd := czechMonths[parsedDateEnd.Month()-1] formattedDateEnd = fmt.Sprintf("%d. %s %d", parsedDateEnd.Day(), monthNameEnd, parsedDateEnd.Year()) } else { formattedDateEnd = entry.DateEnd } // Výpočet celkové doby jízdy startDateTime, startErr := time.Parse("2006-01-02T15:04", fmt.Sprintf("%sT%s", entry.DateStart, entry.TimeStart)) endDateTime, endErr := time.Parse("2006-01-02T15:04", fmt.Sprintf("%sT%s", entry.DateEnd, entry.TimeEnd)) totalDurationStr := "Neznámá" if startErr == nil && endErr == nil { diffMs := endDateTime.Sub(startDateTime) if diffMs >= 0 { diffDays := int(diffMs.Hours() / 24) diffHours := int(diffMs.Hours()) % 24 diffMinutes := int(diffMs.Minutes()) % 60 if diffDays > 0 { dayWord := "dní" if diffDays == 1 { dayWord = "den" } else if diffDays >= 2 && diffDays <= 4 { dayWord = "dny" } totalDurationStr = fmt.Sprintf("%d %s, %d h %d min", diffDays, dayWord, diffHours, diffMinutes) } else { totalDurationStr = fmt.Sprintf("%d h %d min", diffHours, diffMinutes) } } } // Vypsání informací o řidiči a vozidle htmlContent.WriteString(`
Informace o řidiči a vozidle
Řidič ` + entry.Name + `
Vozidlo ` + entry.Vehicle + `
`) // Vypsání informací o trase htmlContent.WriteString(`
Informace o trase
Cíl cesty ` + entry.Destination + `
Účel jízdy ` + entry.Purpose + `
`) // Vypsání informací o času htmlContent.WriteString(`
Časové údaje
Datum a čas odjezdu ` + formattedDateStart + `, ` + entry.TimeStart + `
Datum a čas příjezdu ` + formattedDateEnd + `, ` + entry.TimeEnd + `
Celková doba jízdy ` + totalDurationStr + `
`) // Vypsání informací o kilometrech htmlContent.WriteString(`
Stav tachometru
Stav na začátku ` + fmt.Sprintf("%d km", entry.KmStart) + `
Stav na konci ` + fmt.Sprintf("%d km", entry.KmEnd) + `
Celkem ujeto ` + fmt.Sprintf("%d km", entry.KmEnd-entry.KmStart) + `
`) if entry.Coordinates != nil { htmlContent.WriteString(`
GPS Souřadnice
Souřadnice ` + entry.Coordinates.Lat + `, ` + entry.Coordinates.Lng + `
Zobrazit na mapě
`) } htmlContent.WriteString(`
`) m.SetBody("text/html", htmlContent.String()) d := gomail.NewDialer(smtpHost, smtpPort, sender, password) d.TLSConfig = &tls.Config{InsecureSkipVerify: true} return d.DialAndSend(m) }