refactor(log): prelazak sa log na log/slog (strukturisano logovanje)

Uveden podrazumevani slog logger u main.go (podesiLog): JSON u produkciji,
tekst u razvoju, nivo Info. Svih ~70 poziva log.Printf/Println/Fatalf zamenjeno
slog.Error/Warn/Info: greška se prosleđuje kao atribut "error", informativne
vrednosti kao imenovani atributi (port, broj, putanja...), Fatalf -> Error +
os.Exit(1). Upozorenja (inicijalizacija/čišćenje dozvola, migracija kolone) idu
kao slog.Warn.

Auth log (internal/auth/log.go) namerno NIJE diran — ostaje zaseban *log.Logger
u fail2ban formatu. (slog.SetDefault usput preusmerava i standardni log paket.)
This commit is contained in:
2026-06-12 22:33:42 +02:00
parent 47fab264b5
commit b77a8857e6
12 changed files with 99 additions and 84 deletions
+32 -18
View File
@@ -7,7 +7,7 @@ import (
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"io/fs" "io/fs"
"log" "log/slog"
"net/http" "net/http"
"os" "os"
"mime" "mime"
@@ -31,10 +31,24 @@ import (
// Verzija se postavlja pri produkcijskom buildu: go build -ldflags "-X main.Verzija=1.2.0" // Verzija se postavlja pri produkcijskom buildu: go build -ldflags "-X main.Verzija=1.2.0"
var Verzija = "dev" var Verzija = "dev"
// podesiLog postavlja podrazumevani slog logger: JSON u produkciji (za mašinsku
// obradu logova), tekst u razvoju (čitljivije). Nivo je Info.
func podesiLog() {
opcije := &slog.HandlerOptions{Level: slog.LevelInfo}
var handler slog.Handler
if os.Getenv("NTECH_ENV") == "production" {
handler = slog.NewJSONHandler(os.Stdout, opcije)
} else {
handler = slog.NewTextHandler(os.Stdout, opcije)
}
slog.SetDefault(slog.New(handler))
}
func main() { func main() {
mime.AddExtensionType(".js", "text/javascript") mime.AddExtensionType(".js", "text/javascript")
mime.AddExtensionType(".css", "text/css") mime.AddExtensionType(".css", "text/css")
godotenv.Load("ntech.env") godotenv.Load("ntech.env")
podesiLog()
auth.InitAuthLog() auth.InitAuthLog()
// disk-first logika: ako folder postoji pored binarnog fajla — koristi disk, inače embed. // disk-first logika: ako folder postoji pored binarnog fajla — koristi disk, inače embed.
@@ -73,38 +87,38 @@ func main() {
db, err := sqlite.OtvoriDB(putanjaBaze) db, err := sqlite.OtvoriDB(putanjaBaze)
if err != nil { if err != nil {
log.Fatalf("Greška pri otvaranju baze: %v", err) slog.Error("Greška pri otvaranju baze", "error", err); os.Exit(1)
} }
defer db.Close() defer db.Close()
if err := sqlite.PokreniMigracije(db, migrFS); err != nil { if err := sqlite.PokreniMigracije(db, migrFS); err != nil {
log.Fatalf("Greška pri migracijama: %v", err) slog.Error("Greška pri migracijama", "error", err); os.Exit(1)
} }
log.Println("Migracije uspešno izvršene") slog.Info("migracije uspešno izvršene")
// popuni tabelu dozvola podrazumevanim vrednostima ako je prazna // popuni tabelu dozvola podrazumevanim vrednostima ako je prazna
if err := sqlite.InicijalizujDozvole(context.Background(), db, ntechmw.ImaDozvolu, ntechmw.SveAkcije()); err != nil { if err := sqlite.InicijalizujDozvole(context.Background(), db, ntechmw.ImaDozvolu, ntechmw.SveAkcije()); err != nil {
log.Printf("Upozorenje: greška pri inicijalizaciji dozvola: %v", err) slog.Warn("greška pri inicijalizaciji dozvola", "error", err)
} }
// ukloni zastarele dozvole (siročiće) koje više ne postoje u kodu // ukloni zastarele dozvole (siročiće) koje više ne postoje u kodu
if br, err := sqlite.OcistiSirociceDoz(context.Background(), db, ntechmw.SveAkcije()); err != nil { if br, err := sqlite.OcistiSirociceDoz(context.Background(), db, ntechmw.SveAkcije()); err != nil {
log.Printf("Upozorenje: greška pri čišćenju dozvola: %v", err) slog.Warn("greška pri čišćenju dozvola", "error", err)
} else if br > 0 { } else if br > 0 {
log.Printf("Dozvole: uklonjeno %d zastarelih redova", br) slog.Info("uklonjene zastarele dozvole", "broj", br)
} }
// ključ za šifrovanje TOTP tajni u mirovanju (AES-256-GCM) // ključ za šifrovanje TOTP tajni u mirovanju (AES-256-GCM)
totpKljuc, err := ucitajTotpKljuc() totpKljuc, err := ucitajTotpKljuc()
if err != nil { if err != nil {
log.Fatalf("Greška pri učitavanju ključa za TOTP: %v", err) slog.Error("Greška pri učitavanju ključa za TOTP", "error", err); os.Exit(1)
} }
// jednokratno šifruj eventualne stare TOTP tajne koje su ostale kao čist tekst // jednokratno šifruj eventualne stare TOTP tajne koje su ostale kao čist tekst
if br, err := sqlite.ZasifrujPostojeceTotp(context.Background(), db, totpKljuc); err != nil { if br, err := sqlite.ZasifrujPostojeceTotp(context.Background(), db, totpKljuc); err != nil {
log.Printf("Upozorenje: greška pri šifrovanju postojećih TOTP tajni: %v", err) slog.Warn("greška pri šifrovanju postojećih TOTP tajni", "error", err)
} else if br > 0 { } else if br > 0 {
log.Printf("TOTP: šifrovano %d postojećih tajni", br) slog.Info("šifrovane postojeće TOTP tajne", "broj", br)
} }
napraviBackup(db, putanjaBaze) napraviBackup(db, putanjaBaze)
@@ -123,10 +137,10 @@ func main() {
if os.Getenv("NTECH_ENV") == "production" { if os.Getenv("NTECH_ENV") == "production" {
kes, err := handler.KreirajKes(templFS) kes, err := handler.KreirajKes(templFS)
if err != nil { if err != nil {
log.Fatalf("Greška pri kreiranju keša šablona: %v", err) slog.Error("Greška pri kreiranju keša šablona", "error", err); os.Exit(1)
} }
h.Templates = kes h.Templates = kes
log.Printf("Keš šablona kreiran: %d šablona", len(kes)) slog.Info("keš šablona kreiran", "broj", len(kes))
} }
// Pozadinske gorutine se pokreću posle kreiranja h i rade preko h.SaBazom, // Pozadinske gorutine se pokreću posle kreiranja h i rade preko h.SaBazom,
@@ -309,10 +323,10 @@ func main() {
r.With(doz("tema.lokalno")).Post("/profil/pozadina/stilovi", h.ProfilSacuvajPozadinuStilove) r.With(doz("tema.lokalno")).Post("/profil/pozadina/stilovi", h.ProfilSacuvajPozadinuStilove)
}) })
log.Printf("NTech pokrenut na portu %s", port) slog.Info("NTech pokrenut", "port", port)
err = http.ListenAndServe(":"+port, r) err = http.ListenAndServe(":"+port, r)
if err != nil { if err != nil {
log.Fatalf("Greška: port %s je zauzet ili nije dostupan", port) slog.Error("port je zauzet ili nije dostupan", "port", port); os.Exit(1)
} }
} }
@@ -350,7 +364,7 @@ func ucitajTotpKljuc() ([]byte, error) {
return nil, fmt.Errorf("upis ključa u ntech.env: %w", err) return nil, fmt.Errorf("upis ključa u ntech.env: %w", err)
} }
os.Setenv("NTECH_TOTP_KEY", enkodiran) os.Setenv("NTECH_TOTP_KEY", enkodiran)
log.Println("Generisan nov NTECH_TOTP_KEY i upisan u ntech.env") slog.Info("generisan nov NTECH_TOTP_KEY i upisan u ntech.env")
return kljuc, nil return kljuc, nil
} }
@@ -363,7 +377,7 @@ func napraviBackup(db *sql.DB, putanjaBaze string) {
folder := "backups" folder := "backups"
if err := os.MkdirAll(folder, 0755); err != nil { if err := os.MkdirAll(folder, 0755); err != nil {
log.Printf("backup: ne mogu kreirati folder: %v", err) slog.Error("backup: ne mogu kreirati folder", "error", err)
return return
} }
@@ -371,11 +385,11 @@ func napraviBackup(db *sql.DB, putanjaBaze string) {
odrediste := filepath.Join(folder, ime) odrediste := filepath.Join(folder, ime)
if _, err := db.ExecContext(context.Background(), "VACUUM INTO ?", odrediste); err != nil { if _, err := db.ExecContext(context.Background(), "VACUUM INTO ?", odrediste); err != nil {
log.Printf("backup: greška pri pravljenju backup-a: %v", err) slog.Error("backup: greška pri pravljenju backup-a", "error", err)
return return
} }
log.Printf("Backup kreiran: %s", odrediste) slog.Info("backup kreiran", "putanja", odrediste)
ocistiStareBackupe(folder, procitajIntPodesavanje(db, "backup_broj_kopija", 7)) ocistiStareBackupe(folder, procitajIntPodesavanje(db, "backup_broj_kopija", 7))
} }
+4 -3
View File
@@ -5,9 +5,10 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/fs" "io/fs"
"log" "log/slog"
"net" "net"
"net/http" "net/http"
"os"
"strings" "strings"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
@@ -48,7 +49,7 @@ func nadjiLokalneAdrese() []string {
func PokreniSetup(fsys fs.FS) { func PokreniSetup(fsys fs.FS) {
port := NadjiSlobodanPort() port := NadjiSlobodanPort()
if port == 0 { if port == 0 {
log.Fatal("ntech: setup: nije pronađen nijedan slobodan port") slog.Error("setup: nije pronađen nijedan slobodan port"); os.Exit(1)
} }
gotov := make(chan struct{}) gotov := make(chan struct{})
@@ -102,7 +103,7 @@ func PokreniSetup(fsys fs.FS) {
go func() { go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("ntech: setup server: %v", err) slog.Error("setup server", "error", err); os.Exit(1)
} }
}() }()
+2 -2
View File
@@ -4,7 +4,7 @@ import (
"database/sql" "database/sql"
"fmt" "fmt"
"io/fs" "io/fs"
"log" "log/slog"
"path" "path"
"sort" "sort"
"strings" "strings"
@@ -87,7 +87,7 @@ func PokreniMigracije(db *sql.DB, fsys fs.FS) error {
// "duplicate column name" znači da kolona već postoji — željeno stanje je ispunjeno, // "duplicate column name" znači da kolona već postoji — željeno stanje je ispunjeno,
// pa nastavljamo i beležimo migraciju kao izvršenu // pa nastavljamo i beležimo migraciju kao izvršenu
if strings.Contains(err.Error(), "duplicate column name") { if strings.Contains(err.Error(), "duplicate column name") {
log.Printf("Upozorenje: migration %s: kolona već postoji, preskačemo", naziv) slog.Warn("migracija: kolona već postoji, preskačemo", "migracija", naziv)
} else { } else {
return fmt.Errorf("ntech: PokreniMigracije: izvršavanje %s: %w", naziv, err) return fmt.Errorf("ntech: PokreniMigracije: izvršavanje %s: %w", naziv, err)
} }
+9 -9
View File
@@ -1,7 +1,7 @@
package handler package handler
import ( import (
"log" "log/slog"
"net/http" "net/http"
"time" "time"
@@ -39,14 +39,14 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
if err := h.DB.QueryRowContext(ctx, if err := h.DB.QueryRowContext(ctx,
"SELECT COUNT(*) FROM artikli", "SELECT COUNT(*) FROM artikli",
).Scan(&brojArtikala); err != nil { ).Scan(&brojArtikala); err != nil {
log.Printf("dashboard: broj artikala: %v", err) slog.Error("dashboard: broj artikala", "error", err)
} }
if err := h.DB.QueryRowContext(ctx, ` if err := h.DB.QueryRowContext(ctx, `
SELECT COUNT(*) FROM servisni_nalozi SELECT COUNT(*) FROM servisni_nalozi
WHERE status != 'Završeno'`, WHERE status != 'Završeno'`,
).Scan(&aktivniServisi); err != nil { ).Scan(&aktivniServisi); err != nil {
log.Printf("dashboard: aktivni servisi: %v", err) slog.Error("dashboard: aktivni servisi", "error", err)
} }
// prihod se dohvata samo ako korisnik ima dozvolu dashboard.prihod // prihod se dohvata samo ako korisnik ima dozvolu dashboard.prihod
@@ -56,14 +56,14 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
SELECT COALESCE(SUM(ukupno), 0) FROM prodajni_nalozi SELECT COALESCE(SUM(ukupno), 0) FROM prodajni_nalozi
WHERE substr(datum, 1, 7) = strftime('%Y-%m', 'now', 'localtime')`, WHERE substr(datum, 1, 7) = strftime('%Y-%m', 'now', 'localtime')`,
).Scan(&prihodOvogMeseca); err != nil { ).Scan(&prihodOvogMeseca); err != nil {
log.Printf("dashboard: prihod ovog meseca: %v", err) slog.Error("dashboard: prihod ovog meseca", "error", err)
} }
} }
if err := h.DB.QueryRowContext(ctx, if err := h.DB.QueryRowContext(ctx,
"SELECT COUNT(*) FROM artikli WHERE kolicina <= kolicina_min", "SELECT COUNT(*) FROM artikli WHERE kolicina <= kolicina_min",
).Scan(&kriticnaZaliha); err != nil { ).Scan(&kriticnaZaliha); err != nil {
log.Printf("dashboard: kriticna zaliha: %v", err) slog.Error("dashboard: kriticna zaliha", "error", err)
} }
korisnikFilter := appdb.PodsetnikFilter{} korisnikFilter := appdb.PodsetnikFilter{}
@@ -71,7 +71,7 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
korisnikFilter.KorisnikID = &korisnikDash.ID korisnikFilter.KorisnikID = &korisnikDash.ID
} }
if n, err := h.PodsetnikRepo.BrojAktivnih(ctx, korisnikFilter); err != nil { if n, err := h.PodsetnikRepo.BrojAktivnih(ctx, korisnikFilter); err != nil {
log.Printf("dashboard: aktivni podsetnici: %v", err) slog.Error("dashboard: aktivni podsetnici", "error", err)
} else { } else {
aktivniPodsetnici = n aktivniPodsetnici = n
} }
@@ -81,7 +81,7 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
SELECT uredjaj, status, datum_prijema FROM servisni_nalozi SELECT uredjaj, status, datum_prijema FROM servisni_nalozi
ORDER BY datum_prijema DESC LIMIT 5`) ORDER BY datum_prijema DESC LIMIT 5`)
if err != nil { if err != nil {
log.Printf("dashboard: poslednji servisi: %v", err) slog.Error("dashboard: poslednji servisi", "error", err)
} }
var poslednjiServisi []model.StavkaServisa var poslednjiServisi []model.StavkaServisa
@@ -104,7 +104,7 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
WHERE kolicina <= kolicina_min WHERE kolicina <= kolicina_min
ORDER BY kolicina ASC LIMIT 5`) ORDER BY kolicina ASC LIMIT 5`)
if err != nil { if err != nil {
log.Printf("dashboard: kriticne zalihe: %v", err) slog.Error("dashboard: kriticne zalihe", "error", err)
} }
var kriticneZalihe []model.StavkaZalihe var kriticneZalihe []model.StavkaZalihe
@@ -132,7 +132,7 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
LEFT JOIN klijent_prikaz kp ON kp.id = pn.klijent_id LEFT JOIN klijent_prikaz kp ON kp.id = pn.klijent_id
ORDER BY pn.datum DESC LIMIT 5`) ORDER BY pn.datum DESC LIMIT 5`)
if err != nil { if err != nil {
log.Printf("dashboard: poslednje prodaje: %v", err) slog.Error("dashboard: poslednje prodaje", "error", err)
} }
var poslednjeProdaje []model.StavkaProdajePregled var poslednjeProdaje []model.StavkaProdajePregled
+6 -6
View File
@@ -4,7 +4,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"html/template" "html/template"
"log" "log/slog"
"net/http" "net/http"
"time" "time"
@@ -92,7 +92,7 @@ func (h *Handler) Izvestaji(w http.ResponseWriter, r *http.Request) {
WHERE substr(datum, 1, 10) >= date('now', '-11 months', 'start of month') WHERE substr(datum, 1, 10) >= date('now', '-11 months', 'start of month')
GROUP BY substr(datum, 1, 7)`) GROUP BY substr(datum, 1, 7)`)
if err != nil { if err != nil {
log.Printf("izvestaji: prihod prodaja: %v", err) slog.Error("izvestaji: prihod prodaja", "error", err)
} else { } else {
defer prodajaRed.Close() defer prodajaRed.Close()
for prodajaRed.Next() { for prodajaRed.Next() {
@@ -113,7 +113,7 @@ func (h *Handler) Izvestaji(w http.ResponseWriter, r *http.Request) {
AND substr(datum_zavrsetka, 1, 10) >= date('now', '-11 months', 'start of month') AND substr(datum_zavrsetka, 1, 10) >= date('now', '-11 months', 'start of month')
GROUP BY substr(datum_zavrsetka, 1, 7)`) GROUP BY substr(datum_zavrsetka, 1, 7)`)
if err != nil { if err != nil {
log.Printf("izvestaji: prihod servis: %v", err) slog.Error("izvestaji: prihod servis", "error", err)
} else { } else {
defer servisRed.Close() defer servisRed.Close()
for servisRed.Next() { for servisRed.Next() {
@@ -171,7 +171,7 @@ func (h *Handler) Izvestaji(w http.ResponseWriter, r *http.Request) {
var stariNalozi []StariNalog var stariNalozi []StariNalog
if err != nil { if err != nil {
log.Printf("izvestaji: stari nalozi: %v", err) slog.Error("izvestaji: stari nalozi", "error", err)
} else { } else {
defer stariRed.Close() defer stariRed.Close()
for stariRed.Next() { for stariRed.Next() {
@@ -197,7 +197,7 @@ func (h *Handler) Izvestaji(w http.ResponseWriter, r *http.Request) {
var topArtikli []TopArtikal var topArtikli []TopArtikal
if err != nil { if err != nil {
log.Printf("izvestaji: top artikli: %v", err) slog.Error("izvestaji: top artikli", "error", err)
} else { } else {
defer artRed.Close() defer artRed.Close()
for artRed.Next() { for artRed.Next() {
@@ -231,7 +231,7 @@ func (h *Handler) Izvestaji(w http.ResponseWriter, r *http.Request) {
var topKlijenti []TopKlijent var topKlijenti []TopKlijent
if err != nil { if err != nil {
log.Printf("izvestaji: top klijenti: %v", err) slog.Error("izvestaji: top klijenti", "error", err)
} else { } else {
defer klijRed.Close() defer klijRed.Close()
for klijRed.Next() { for klijRed.Next() {
+7 -7
View File
@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"html/template" "html/template"
"io/fs" "io/fs"
"log" "log/slog"
"net/http" "net/http"
) )
@@ -90,7 +90,7 @@ func (h *Handler) renderujTemplate(w http.ResponseWriter, ime string, podaci any
if h.Templates != nil { if h.Templates != nil {
t, ok := h.Templates[ime] t, ok := h.Templates[ime]
if !ok { if !ok {
log.Printf("kes: šablon '%s' nije pronađen", ime) slog.Error("šablon nije pronađen", "ime", ime)
http.Error(w, "Greška pri učitavanju stranice", http.StatusInternalServerError) http.Error(w, "Greška pri učitavanju stranice", http.StatusInternalServerError)
return return
} }
@@ -101,14 +101,14 @@ func (h *Handler) renderujTemplate(w http.ResponseWriter, ime string, podaci any
fajlovi = append(fajlovi, "web/templates/stranice/"+ime+".html") fajlovi = append(fajlovi, "web/templates/stranice/"+ime+".html")
var err error var err error
if tmpl, err = template.New(ime).Funcs(sablonskeFunkcije).ParseFS(h.TemplatesFS, fajlovi...); err != nil { if tmpl, err = template.New(ime).Funcs(sablonskeFunkcije).ParseFS(h.TemplatesFS, fajlovi...); err != nil {
log.Printf("greška pri parsiranju šablona %s: %v", ime, err) slog.Error("greška pri parsiranju šablona", "ime", ime, "error", err)
http.Error(w, "Greška pri učitavanju stranice", http.StatusInternalServerError) http.Error(w, "Greška pri učitavanju stranice", http.StatusInternalServerError)
return return
} }
} }
if err := tmpl.ExecuteTemplate(w, "base", podaci); err != nil { if err := tmpl.ExecuteTemplate(w, "base", podaci); err != nil {
log.Printf("greška pri renderovanju šablona %s: %v", ime, err) slog.Error("greška pri renderovanju šablona", "ime", ime, "error", err)
http.Error(w, "Greška pri prikazu stranice", http.StatusInternalServerError) http.Error(w, "Greška pri prikazu stranice", http.StatusInternalServerError)
} }
} }
@@ -120,7 +120,7 @@ func (h *Handler) renderujStandalone(w http.ResponseWriter, ime string, podaci a
if h.Templates != nil { if h.Templates != nil {
t, ok := h.Templates[ime] t, ok := h.Templates[ime]
if !ok { if !ok {
log.Printf("kes: standalone šablon '%s' nije pronađen", ime) slog.Error("standalone šablon nije pronađen", "ime", ime)
http.Error(w, "Greška pri učitavanju stranice", http.StatusInternalServerError) http.Error(w, "Greška pri učitavanju stranice", http.StatusInternalServerError)
return return
} }
@@ -128,14 +128,14 @@ func (h *Handler) renderujStandalone(w http.ResponseWriter, ime string, podaci a
} else { } else {
var err error var err error
if tmpl, err = template.ParseFS(h.TemplatesFS, "web/templates/stranice/"+ime+".html"); err != nil { if tmpl, err = template.ParseFS(h.TemplatesFS, "web/templates/stranice/"+ime+".html"); err != nil {
log.Printf("greška pri parsiranju šablona %s: %v", ime, err) slog.Error("greška pri parsiranju šablona", "ime", ime, "error", err)
http.Error(w, "Greška pri učitavanju stranice", http.StatusInternalServerError) http.Error(w, "Greška pri učitavanju stranice", http.StatusInternalServerError)
return return
} }
} }
if err := tmpl.Execute(w, podaci); err != nil { if err := tmpl.Execute(w, podaci); err != nil {
log.Printf("greška pri renderovanju šablona %s: %v", ime, err) slog.Error("greška pri renderovanju šablona", "ime", ime, "error", err)
http.Error(w, "Greška pri prikazu stranice", http.StatusInternalServerError) http.Error(w, "Greška pri prikazu stranice", http.StatusInternalServerError)
} }
} }
+3 -3
View File
@@ -1,7 +1,7 @@
package handler package handler
import ( import (
"log" "log/slog"
"net/http" "net/http"
"strings" "strings"
@@ -101,7 +101,7 @@ func (h *Handler) SacuvajKlijenta(w http.ResponseWriter, r *http.Request) {
} }
if _, err := h.KlijentiRepo.Kreiraj(r.Context(), &klijent); err != nil { if _, err := h.KlijentiRepo.Kreiraj(r.Context(), &klijent); err != nil {
log.Printf("greška pri čuvanju klijenta: %v", err) slog.Error("greška pri čuvanju klijenta", "error", err)
podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB) podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB)
ps := h.popuniPodaciStranice(r, podesavanja) ps := h.popuniPodaciStranice(r, podesavanja)
ps.Stranica = "klijenti" ps.Stranica = "klijenti"
@@ -182,7 +182,7 @@ func (h *Handler) SacuvajIzmenuKlijenta(w http.ResponseWriter, r *http.Request)
klijent.ID = id klijent.ID = id
if err := h.KlijentiRepo.Izmeni(r.Context(), &klijent); err != nil { if err := h.KlijentiRepo.Izmeni(r.Context(), &klijent); err != nil {
log.Printf("greška pri čuvanju izmene klijenta: %v", err) slog.Error("greška pri čuvanju izmene klijenta", "error", err)
podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB) podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB)
ps := h.popuniPodaciStranice(r, podesavanja) ps := h.popuniPodaciStranice(r, podesavanja)
ps.Stranica = "klijenti" ps.Stranica = "klijenti"
+16 -16
View File
@@ -5,7 +5,7 @@ import (
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"io" "io"
"log" "log/slog"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
@@ -155,14 +155,14 @@ func (h *Handler) VratiBackup(w http.ResponseWriter, r *http.Request) {
// pre obnove, sačuvaj trenutno stanje baze // pre obnove, sačuvaj trenutno stanje baze
sigurnosni := filepath.Join("backups", fmt.Sprintf("ntech_%s_pred_vracanjem.db", time.Now().Format("20060102_150405"))) sigurnosni := filepath.Join("backups", fmt.Sprintf("ntech_%s_pred_vracanjem.db", time.Now().Format("20060102_150405")))
if _, err := h.DB.ExecContext(r.Context(), "VACUUM INTO ?", sigurnosni); err != nil { if _, err := h.DB.ExecContext(r.Context(), "VACUUM INTO ?", sigurnosni); err != nil {
log.Printf("vrati backup: greška pri kreiranju sigurnosne kopije: %v", err) slog.Error("vrati backup: greška pri kreiranju sigurnosne kopije", "error", err)
http.Redirect(w, r, "/podesavanja?backup_greska=Greška+pri+kreiranju+sigurnosne+kopije", http.StatusSeeOther) http.Redirect(w, r, "/podesavanja?backup_greska=Greška+pri+kreiranju+sigurnosne+kopije", http.StatusSeeOther)
return return
} }
// isprazni WAL u glavni fajl // isprazni WAL u glavni fajl
if _, err := h.DB.ExecContext(r.Context(), "PRAGMA wal_checkpoint(TRUNCATE)"); err != nil { if _, err := h.DB.ExecContext(r.Context(), "PRAGMA wal_checkpoint(TRUNCATE)"); err != nil {
log.Printf("vrati backup: wal_checkpoint greška: %v", err) slog.Error("vrati backup: wal_checkpoint greška", "error", err)
} }
// Sama zamena baze (zatvaranje stare, kopiranje, otvaranje nove) radi se u // Sama zamena baze (zatvaranje stare, kopiranje, otvaranje nove) radi se u
@@ -178,10 +178,10 @@ func (h *Handler) VratiBackup(w http.ResponseWriter, r *http.Request) {
defer h.mu.Unlock() defer h.mu.Unlock()
if err := h.DB.Close(); err != nil { if err := h.DB.Close(); err != nil {
log.Printf("vrati backup: greška pri zatvaranju baze: %v", err) slog.Error("vrati backup: greška pri zatvaranju baze", "error", err)
} }
if err := kopiraFajl(putanjaBackupa, h.PutanjaBaze); err != nil { if err := kopiraFajl(putanjaBackupa, h.PutanjaBaze); err != nil {
log.Printf("vrati backup: greška pri kopiranju (baza je zatvorena, potreban restart): %v", err) slog.Error("vrati backup: greška pri kopiranju (baza je zatvorena, potreban restart)", "error", err)
return return
} }
os.Remove(h.PutanjaBaze + "-wal") os.Remove(h.PutanjaBaze + "-wal")
@@ -189,11 +189,11 @@ func (h *Handler) VratiBackup(w http.ResponseWriter, r *http.Request) {
novaDB, err := ntechsqlite.OtvoriDB(h.PutanjaBaze) novaDB, err := ntechsqlite.OtvoriDB(h.PutanjaBaze)
if err != nil { if err != nil {
log.Printf("vrati backup: greška pri otvaranju nove baze (potreban restart): %v", err) slog.Error("vrati backup: greška pri otvaranju nove baze (potreban restart)", "error", err)
return return
} }
h.reinicijalizujRepozitorijume(novaDB) h.reinicijalizujRepozitorijume(novaDB)
log.Printf("Baza uspešno obnovljena iz: %s", ime) slog.Info("baza uspešno obnovljena", "izvor", ime)
}() }()
http.Redirect(w, r, "/podesavanja?sacuvano=vraceno", http.StatusSeeOther) http.Redirect(w, r, "/podesavanja?sacuvano=vraceno", http.StatusSeeOther)
@@ -364,14 +364,14 @@ func (h *Handler) OtpremiLogo(w http.ResponseWriter, r *http.Request) {
odrediste := "web/static/uploads/logo" + ext odrediste := "web/static/uploads/logo" + ext
dst, err := os.Create(odrediste) dst, err := os.Create(odrediste)
if err != nil { if err != nil {
log.Printf("upload loga: ne mogu kreirati fajl: %v", err) slog.Error("upload loga: ne mogu kreirati fajl", "error", err)
http.Redirect(w, r, "/podesavanja?logo_greska=Greška+pri+čuvanju+fajla", http.StatusSeeOther) http.Redirect(w, r, "/podesavanja?logo_greska=Greška+pri+čuvanju+fajla", http.StatusSeeOther)
return return
} }
defer dst.Close() defer dst.Close()
if _, err := io.Copy(dst, fajl); err != nil { if _, err := io.Copy(dst, fajl); err != nil {
log.Printf("upload loga: greška pri kopiranju: %v", err) slog.Error("upload loga: greška pri kopiranju", "error", err)
http.Redirect(w, r, "/podesavanja?logo_greska=Greška+pri+čuvanju+fajla", http.StatusSeeOther) http.Redirect(w, r, "/podesavanja?logo_greska=Greška+pri+čuvanju+fajla", http.StatusSeeOther)
return return
} }
@@ -379,7 +379,7 @@ func (h *Handler) OtpremiLogo(w http.ResponseWriter, r *http.Request) {
// timestamp u URL-u sprečava browser da koristi staru keširanu sliku // timestamp u URL-u sprečava browser da koristi staru keširanu sliku
putanja := fmt.Sprintf("/static/uploads/logo%s?v=%d", ext, time.Now().Unix()) putanja := fmt.Sprintf("/static/uploads/logo%s?v=%d", ext, time.Now().Unix())
if err := ntechsqlite.SacuvajPodesavanje(r.Context(), h.DB, "logo_putanja", putanja); err != nil { if err := ntechsqlite.SacuvajPodesavanje(r.Context(), h.DB, "logo_putanja", putanja); err != nil {
log.Printf("upload loga: greška pri čuvanju putanje: %v", err) slog.Error("upload loga: greška pri čuvanju putanje", "error", err)
http.Redirect(w, r, "/podesavanja?logo_greska=Greška+pri+čuvanju+podešavanja", http.StatusSeeOther) http.Redirect(w, r, "/podesavanja?logo_greska=Greška+pri+čuvanju+podešavanja", http.StatusSeeOther)
return return
} }
@@ -463,7 +463,7 @@ func (h *Handler) OtpremiLoginPozadinu(w http.ResponseWriter, r *http.Request) {
novoIme, err := generisiImeUploada(ext) novoIme, err := generisiImeUploada(ext)
if err != nil { if err != nil {
log.Printf("upload login pozadine: greška pri generisanju imena: %v", err) slog.Error("upload login pozadine: greška pri generisanju imena", "error", err)
middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju fajla.") middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju fajla.")
http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther) http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther)
return return
@@ -472,7 +472,7 @@ func (h *Handler) OtpremiLoginPozadinu(w http.ResponseWriter, r *http.Request) {
odrediste := filepath.Join("web/static/uploads", novoIme) odrediste := filepath.Join("web/static/uploads", novoIme)
dst, err := os.Create(odrediste) dst, err := os.Create(odrediste)
if err != nil { if err != nil {
log.Printf("upload login pozadine: ne mogu kreirati fajl: %v", err) slog.Error("upload login pozadine: ne mogu kreirati fajl", "error", err)
middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju fajla.") middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju fajla.")
http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther) http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther)
return return
@@ -480,7 +480,7 @@ func (h *Handler) OtpremiLoginPozadinu(w http.ResponseWriter, r *http.Request) {
defer dst.Close() defer dst.Close()
if _, err := io.Copy(dst, fajl); err != nil { if _, err := io.Copy(dst, fajl); err != nil {
log.Printf("upload login pozadine: greška pri kopiranju: %v", err) slog.Error("upload login pozadine: greška pri kopiranju", "error", err)
middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju fajla.") middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju fajla.")
http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther) http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther)
return return
@@ -488,7 +488,7 @@ func (h *Handler) OtpremiLoginPozadinu(w http.ResponseWriter, r *http.Request) {
putanja := fmt.Sprintf("/static/uploads/%s?v=%d", novoIme, time.Now().Unix()) putanja := fmt.Sprintf("/static/uploads/%s?v=%d", novoIme, time.Now().Unix())
if err := ntechsqlite.SacuvajPodesavanje(r.Context(), h.DB, "login_pozadina", putanja); err != nil { if err := ntechsqlite.SacuvajPodesavanje(r.Context(), h.DB, "login_pozadina", putanja); err != nil {
log.Printf("upload login pozadine: greška pri čuvanju putanje: %v", err) slog.Error("upload login pozadine: greška pri čuvanju putanje", "error", err)
middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju podešavanja.") middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju podešavanja.")
http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther) http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther)
return return
@@ -514,7 +514,7 @@ func (h *Handler) UkloniLoginPozadinu(w http.ResponseWriter, r *http.Request) {
} }
if err := ntechsqlite.SacuvajPodesavanje(r.Context(), h.DB, "login_pozadina", ""); err != nil { if err := ntechsqlite.SacuvajPodesavanje(r.Context(), h.DB, "login_pozadina", ""); err != nil {
log.Printf("ukloni login pozadinu: greška pri čuvanju: %v", err) slog.Error("ukloni login pozadinu: greška pri čuvanju", "error", err)
middleware.SetFlash(w, r, h.DB, "greska", "Greška pri uklanjanju slike.") middleware.SetFlash(w, r, h.DB, "greska", "Greška pri uklanjanju slike.")
http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther) http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther)
return return
@@ -572,7 +572,7 @@ func (h *Handler) SacuvajLoginPozadinaStilove(w http.ResponseWriter, r *http.Req
"login_pozadina_zatamnjenje_kartice": zatamnjenjeKarticeStr, "login_pozadina_zatamnjenje_kartice": zatamnjenjeKarticeStr,
} { } {
if err := ntechsqlite.SacuvajPodesavanje(r.Context(), h.DB, kljuc, vrednost); err != nil { if err := ntechsqlite.SacuvajPodesavanje(r.Context(), h.DB, kljuc, vrednost); err != nil {
log.Printf("stilovi login pozadine: greška pri čuvanju %s: %v", kljuc, err) slog.Error("greška pri čuvanju stila login pozadine", "kljuc", kljuc, "error", err)
middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju podešavanja.") middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju podešavanja.")
http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther) http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther)
return return
+3 -3
View File
@@ -1,7 +1,7 @@
package handler package handler
import ( import (
"log" "log/slog"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
@@ -116,7 +116,7 @@ func (h *Handler) SacuvajPodsetnik(w http.ResponseWriter, r *http.Request) {
} }
if _, err := h.PodsetnikRepo.Kreiraj(r.Context(), &podsetnik); err != nil { if _, err := h.PodsetnikRepo.Kreiraj(r.Context(), &podsetnik); err != nil {
log.Printf("greška pri čuvanju podsetnika: %v", err) slog.Error("greška pri čuvanju podsetnika", "error", err)
h.prikaziGreskuPodsetnika(w, r, k, podsetnik, "Došlo je do greške pri čuvanju. Pokušajte ponovo.", false) h.prikaziGreskuPodsetnika(w, r, k, podsetnik, "Došlo je do greške pri čuvanju. Pokušajte ponovo.", false)
return return
} }
@@ -187,7 +187,7 @@ func (h *Handler) SacuvajIzmenePodsetnika(w http.ResponseWriter, r *http.Request
} }
if err := h.PodsetnikRepo.Izmeni(r.Context(), &podsetnik); err != nil { if err := h.PodsetnikRepo.Izmeni(r.Context(), &podsetnik); err != nil {
log.Printf("greška pri čuvanju izmene podsetnika: %v", err) slog.Error("greška pri čuvanju izmene podsetnika", "error", err)
h.prikaziGreskuPodsetnika(w, r, k, podsetnik, "Došlo je do greške pri čuvanju. Pokušajte ponovo.", true) h.prikaziGreskuPodsetnika(w, r, k, podsetnik, "Došlo je do greške pri čuvanju. Pokušajte ponovo.", true)
return return
} }
+4 -4
View File
@@ -4,7 +4,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"html/template" "html/template"
"log" "log/slog"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
@@ -171,7 +171,7 @@ func (h *Handler) SacuvajProdaju(w http.ResponseWriter, r *http.Request) {
brojNaloga, err := h.ProdajaRepo.SledeciBroj(r.Context()) brojNaloga, err := h.ProdajaRepo.SledeciBroj(r.Context())
if err != nil { if err != nil {
log.Printf("greška pri generisanju broja naloga: %v", err) slog.Error("greška pri generisanju broja naloga", "error", err)
renderujGresku("Greška pri generisanju broja naloga.") renderujGresku("Greška pri generisanju broja naloga.")
return return
} }
@@ -191,7 +191,7 @@ func (h *Handler) SacuvajProdaju(w http.ResponseWriter, r *http.Request) {
if errors.As(err, &errStanje) { if errors.As(err, &errStanje) {
renderujGresku(errStanje.Error()) renderujGresku(errStanje.Error())
} else { } else {
log.Printf("greška pri čuvanju prodaje: %v", err) slog.Error("greška pri čuvanju prodaje", "error", err)
renderujGresku("Greška pri čuvanju prodajnog naloga.") renderujGresku("Greška pri čuvanju prodajnog naloga.")
} }
return return
@@ -403,7 +403,7 @@ func (h *Handler) StornoProdaje(w http.ResponseWriter, r *http.Request) {
} }
razlog := strings.TrimSpace(r.FormValue("razlog")) razlog := strings.TrimSpace(r.FormValue("razlog"))
if err := h.ProdajaRepo.Storno(r.Context(), id, razlog, &k.ID); err != nil { if err := h.ProdajaRepo.Storno(r.Context(), id, razlog, &k.ID); err != nil {
log.Printf("greška pri storniranju naloga: %v", err) slog.Error("greška pri storniranju naloga", "error", err)
middleware.SetFlash(w, r, h.DB, "greska", "Greška pri storniranju. Možda je nalog već storniran.") middleware.SetFlash(w, r, h.DB, "greska", "Greška pri storniranju. Možda je nalog već storniran.")
http.Redirect(w, r, "/prodaja/"+strconv.FormatInt(id, 10), http.StatusSeeOther) http.Redirect(w, r, "/prodaja/"+strconv.FormatInt(id, 10), http.StatusSeeOther)
return return
+6 -6
View File
@@ -3,7 +3,7 @@ package handler
import ( import (
"fmt" "fmt"
"io" "io"
"log" "log/slog"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
@@ -132,7 +132,7 @@ func (h *Handler) ProfilOtpremiPozadinu(w http.ResponseWriter, r *http.Request)
odrediste := filepath.Join("web/static/uploads", novoIme) odrediste := filepath.Join("web/static/uploads", novoIme)
dst, err := os.Create(odrediste) dst, err := os.Create(odrediste)
if err != nil { if err != nil {
log.Printf("ProfilOtpremiPozadinu: ne mogu kreirati fajl: %v", err) slog.Error("ProfilOtpremiPozadinu: ne mogu kreirati fajl", "error", err)
middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju fajla.") middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju fajla.")
http.Redirect(w, r, "/profil/tema", http.StatusSeeOther) http.Redirect(w, r, "/profil/tema", http.StatusSeeOther)
return return
@@ -140,7 +140,7 @@ func (h *Handler) ProfilOtpremiPozadinu(w http.ResponseWriter, r *http.Request)
defer dst.Close() defer dst.Close()
if _, err := io.Copy(dst, fajl); err != nil { if _, err := io.Copy(dst, fajl); err != nil {
log.Printf("ProfilOtpremiPozadinu: greška pri kopiranju: %v", err) slog.Error("ProfilOtpremiPozadinu: greška pri kopiranju", "error", err)
middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju fajla.") middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju fajla.")
http.Redirect(w, r, "/profil/tema", http.StatusSeeOther) http.Redirect(w, r, "/profil/tema", http.StatusSeeOther)
return return
@@ -168,7 +168,7 @@ func (h *Handler) ProfilOtpremiPozadinu(w http.ResponseWriter, r *http.Request)
} }
if err := h.KorisniciRepo.SacuvajLokalnuPozadinu(r.Context(), k.ID, putanja, opacity, blur, blurPozadine, glassOpacity); err != nil { if err := h.KorisniciRepo.SacuvajLokalnuPozadinu(r.Context(), k.ID, putanja, opacity, blur, blurPozadine, glassOpacity); err != nil {
log.Printf("ProfilOtpremiPozadinu: greška pri čuvanju: %v", err) slog.Error("ProfilOtpremiPozadinu: greška pri čuvanju", "error", err)
middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju podešavanja.") middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju podešavanja.")
http.Redirect(w, r, "/profil/tema", http.StatusSeeOther) http.Redirect(w, r, "/profil/tema", http.StatusSeeOther)
return return
@@ -193,7 +193,7 @@ func (h *Handler) ProfilUkloniPozadinu(w http.ResponseWriter, r *http.Request) {
} }
if err := h.KorisniciRepo.SacuvajLokalnuPozadinu(r.Context(), k.ID, "", "50", "12", "0", "10"); err != nil { if err := h.KorisniciRepo.SacuvajLokalnuPozadinu(r.Context(), k.ID, "", "50", "12", "0", "10"); err != nil {
log.Printf("ProfilUkloniPozadinu: %v", err) slog.Error("ProfilUkloniPozadinu", "error", err)
middleware.SetFlash(w, r, h.DB, "greska", "Greška pri uklanjanju slike.") middleware.SetFlash(w, r, h.DB, "greska", "Greška pri uklanjanju slike.")
http.Redirect(w, r, "/profil/tema", http.StatusSeeOther) http.Redirect(w, r, "/profil/tema", http.StatusSeeOther)
return return
@@ -241,7 +241,7 @@ func (h *Handler) ProfilSacuvajPozadinuStilove(w http.ResponseWriter, r *http.Re
} }
if err := h.KorisniciRepo.SacuvajLokalnuPozadinu(r.Context(), k.ID, pozadina, opacity, blur, blurPozadineSt, glassOpacitySt); err != nil { if err := h.KorisniciRepo.SacuvajLokalnuPozadinu(r.Context(), k.ID, pozadina, opacity, blur, blurPozadineSt, glassOpacitySt); err != nil {
log.Printf("ProfilSacuvajPozadinuStilove: %v", err) slog.Error("ProfilSacuvajPozadinuStilove", "error", err)
middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju podešavanja.") middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju podešavanja.")
http.Redirect(w, r, "/profil/tema", http.StatusSeeOther) http.Redirect(w, r, "/profil/tema", http.StatusSeeOther)
return return
+7 -7
View File
@@ -1,7 +1,7 @@
package handler package handler
import ( import (
"log" "log/slog"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
@@ -152,7 +152,7 @@ func (h *Handler) SacuvajNalog(w http.ResponseWriter, r *http.Request) {
id, err := h.ServisRepo.Kreiraj(r.Context(), &nalog) id, err := h.ServisRepo.Kreiraj(r.Context(), &nalog)
if err != nil { if err != nil {
log.Printf("greška pri čuvanju naloga: %v", err) slog.Error("greška pri čuvanju naloga", "error", err)
podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB) podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB)
klijenti, _ := h.KlijentiRepo.Lista(r.Context(), "") klijenti, _ := h.KlijentiRepo.Lista(r.Context(), "")
tehnicari, _ := h.KorisniciRepo.Lista(r.Context()) tehnicari, _ := h.KorisniciRepo.Lista(r.Context())
@@ -258,7 +258,7 @@ func (h *Handler) SacuvajIzmenaNaloga(w http.ResponseWriter, r *http.Request) {
nalog.ID = id nalog.ID = id
if err := h.ServisRepo.Izmeni(r.Context(), &nalog); err != nil { if err := h.ServisRepo.Izmeni(r.Context(), &nalog); err != nil {
log.Printf("greška pri čuvanju izmene naloga: %v", err) slog.Error("greška pri čuvanju izmene naloga", "error", err)
podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB) podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB)
klijenti, _ := h.KlijentiRepo.Lista(r.Context(), "") klijenti, _ := h.KlijentiRepo.Lista(r.Context(), "")
tehnicari, _ := h.KorisniciRepo.Lista(r.Context()) tehnicari, _ := h.KorisniciRepo.Lista(r.Context())
@@ -337,13 +337,13 @@ func (h *Handler) DetaljiNaloga(w http.ResponseWriter, r *http.Request) {
delovi, err := h.ServisniDeloviRepo.DohvatiZaNalog(r.Context(), id) delovi, err := h.ServisniDeloviRepo.DohvatiZaNalog(r.Context(), id)
if err != nil { if err != nil {
log.Printf("greška pri učitavanju delova: %v", err) slog.Error("greška pri učitavanju delova", "error", err)
} }
appdb := appdbPkg.ArtikalFilter{} appdb := appdbPkg.ArtikalFilter{}
artikli, err := h.Artikli.Lista(r.Context(), appdb) artikli, err := h.Artikli.Lista(r.Context(), appdb)
if err != nil { if err != nil {
log.Printf("greška pri učitavanju artikala: %v", err) slog.Error("greška pri učitavanju artikala", "error", err)
} }
ps := h.popuniPodaciStranice(r, podesavanja) ps := h.popuniPodaciStranice(r, podesavanja)
@@ -402,7 +402,7 @@ func (h *Handler) DodajDeloNalogu(w http.ResponseWriter, r *http.Request) {
} }
if _, err := h.ServisniDeloviRepo.Dodaj(r.Context(), nalogID, artikalID, kolicina, cena, &k.ID); err != nil { if _, err := h.ServisniDeloviRepo.Dodaj(r.Context(), nalogID, artikalID, kolicina, cena, &k.ID); err != nil {
log.Printf("greška pri dodavanju dela: %v", err) slog.Error("greška pri dodavanju dela", "error", err)
middleware.SetFlash(w, r, h.DB, "greska", "Greška pri dodavanju dela. Proverite stanje na magacinu.") middleware.SetFlash(w, r, h.DB, "greska", "Greška pri dodavanju dela. Proverite stanje na magacinu.")
http.Redirect(w, r, "/servis/"+strconv.FormatInt(nalogID, 10), http.StatusSeeOther) http.Redirect(w, r, "/servis/"+strconv.FormatInt(nalogID, 10), http.StatusSeeOther)
return return
@@ -432,7 +432,7 @@ func (h *Handler) ObrisiDeloNaloga(w http.ResponseWriter, r *http.Request) {
} }
if err := h.ServisniDeloviRepo.Obrisi(r.Context(), deoID, &k.ID); err != nil { if err := h.ServisniDeloviRepo.Obrisi(r.Context(), deoID, &k.ID); err != nil {
log.Printf("greška pri brisanju dela: %v", err) slog.Error("greška pri brisanju dela", "error", err)
middleware.SetFlash(w, r, h.DB, "greska", "Greška pri uklanjanju dela.") middleware.SetFlash(w, r, h.DB, "greska", "Greška pri uklanjanju dela.")
} else { } else {
middleware.SetFlash(w, r, h.DB, "uspeh", "Deo je uklonjen.") middleware.SetFlash(w, r, h.DB, "uspeh", "Deo je uklonjen.")