216 lines
6.5 KiB
Go
216 lines
6.5 KiB
Go
package handler
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"ntech/internal/db/sqlite"
|
|
"ntech/internal/model"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
)
|
|
|
|
// PodaciPodesavanja su podaci za stranicu podešavanja
|
|
type PodaciPodesavanja struct {
|
|
model.PodaciStranice
|
|
NazivFirme string
|
|
Podnazlov string
|
|
Adresa string
|
|
Telefon string
|
|
PIB string
|
|
LogoTip string
|
|
LogoPutanja string
|
|
Tema string
|
|
Sacuvano bool
|
|
Verzija string
|
|
LogoGreska string
|
|
}
|
|
|
|
// Podesavanja renderuje stranicu podešavanja
|
|
func (h *Handler) Podesavanja(w http.ResponseWriter, r *http.Request) {
|
|
podesavanja, err := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB)
|
|
if err != nil {
|
|
http.Error(w, "Greška pri učitavanju podešavanja", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
podaci := PodaciPodesavanja{
|
|
PodaciStranice: model.PodaciStranice{
|
|
Stranica: "podesavanja",
|
|
NaslovStranice: "Podešavanja",
|
|
Tema: podesavanja["tema"],
|
|
NazivFirme: podesavanja["naziv_firme"],
|
|
Podnazlov: podesavanja["podnazlov"],
|
|
LogoTip: podesavanja["logo_tip"],
|
|
LogoPutanja: podesavanja["logo_putanja"],
|
|
Korisnik: "Admin",
|
|
},
|
|
NazivFirme: podesavanja["naziv_firme"],
|
|
Podnazlov: podesavanja["podnazlov"],
|
|
Adresa: podesavanja["adresa"],
|
|
Telefon: podesavanja["telefon"],
|
|
PIB: podesavanja["pib"],
|
|
LogoTip: podesavanja["logo_tip"],
|
|
LogoPutanja: podesavanja["logo_putanja"],
|
|
Tema: podesavanja["tema"],
|
|
Sacuvano: r.URL.Query().Get("sacuvano") == "1",
|
|
Verzija: h.Verzija,
|
|
LogoGreska: r.URL.Query().Get("logo_greska"),
|
|
}
|
|
|
|
h.renderujTemplate(w, "podesavanja", podaci)
|
|
}
|
|
|
|
// SacuvajPodesavanja prima POST i čuva podešavanja u bazu
|
|
func (h *Handler) SacuvajPodesavanja(w http.ResponseWriter, r *http.Request) {
|
|
if err := r.ParseForm(); err != nil {
|
|
http.Error(w, "Greška pri čitanju forme", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
polja := map[string]string{
|
|
"naziv_firme": r.FormValue("naziv_firme"),
|
|
"podnazlov": r.FormValue("podnazlov"),
|
|
"adresa": r.FormValue("adresa"),
|
|
"telefon": r.FormValue("telefon"),
|
|
"pib": r.FormValue("pib"),
|
|
"logo_tip": r.FormValue("logo_tip"),
|
|
"tema": r.FormValue("tema"),
|
|
}
|
|
|
|
for kljuc, vrednost := range polja {
|
|
if vrednost == "" {
|
|
continue
|
|
}
|
|
if err := sqlite.SacuvajPodesavanje(r.Context(), h.DB, kljuc, vrednost); err != nil {
|
|
http.Error(w, "Greška pri čuvanju podešavanja", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|
|
|
|
http.Redirect(w, r, "/podesavanja?sacuvano=1", http.StatusSeeOther)
|
|
}
|
|
|
|
// BackupBaze kreira konzistentnu kopiju baze i šalje je kao attachment
|
|
func (h *Handler) BackupBaze(w http.ResponseWriter, r *http.Request) {
|
|
privremeni := fmt.Sprintf("%s/ntech_backup_%s.db", os.TempDir(), time.Now().Format("20060102_150405"))
|
|
|
|
if _, err := h.DB.ExecContext(r.Context(), "VACUUM INTO ?", privremeni); err != nil {
|
|
http.Error(w, "Greška pri kreiranju rezervne kopije", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
defer os.Remove(privremeni)
|
|
|
|
ime := fmt.Sprintf("ntech_backup_%s.db", time.Now().Format("20060102"))
|
|
w.Header().Set("Content-Disposition", "attachment; filename=\""+ime+"\"")
|
|
w.Header().Set("Content-Type", "application/octet-stream")
|
|
http.ServeFile(w, r, privremeni)
|
|
}
|
|
|
|
// OtpremiLogo prima multipart upload slike loga i čuva je u web/static/uploads/
|
|
func (h *Handler) OtpremiLogo(w http.ResponseWriter, r *http.Request) {
|
|
if err := r.ParseMultipartForm(2 << 20); err != nil {
|
|
http.Redirect(w, r, "/podesavanja?logo_greska=Fajl+je+prevelik+%28maksimum+2+MB%29", http.StatusSeeOther)
|
|
return
|
|
}
|
|
|
|
fajl, zaglavlje, err := r.FormFile("logo")
|
|
if err != nil {
|
|
http.Redirect(w, r, "/podesavanja?logo_greska=Nije+odabran+fajl", http.StatusSeeOther)
|
|
return
|
|
}
|
|
defer fajl.Close()
|
|
|
|
// proveravamo ekstenziju
|
|
ext := strings.ToLower(filepath.Ext(zaglavlje.Filename))
|
|
dozvoljenoExt := map[string]string{
|
|
".png": "image/png",
|
|
".jpg": "image/jpeg",
|
|
".jpeg": "image/jpeg",
|
|
".svg": "image/svg+xml",
|
|
}
|
|
ocekivaniMime, ok := dozvoljenoExt[ext]
|
|
if !ok {
|
|
http.Redirect(w, r, "/podesavanja?logo_greska=Dozvoljeni+formati+su+PNG%2C+JPG+i+SVG", http.StatusSeeOther)
|
|
return
|
|
}
|
|
|
|
// za binarne formate proveravamo i stvarni tip fajla (SVG je tekstualni, preskačemo)
|
|
if ext != ".svg" {
|
|
buf := make([]byte, 512)
|
|
n, _ := fajl.Read(buf)
|
|
stvarniMime := http.DetectContentType(buf[:n])
|
|
if !strings.HasPrefix(stvarniMime, ocekivaniMime) {
|
|
http.Redirect(w, r, "/podesavanja?logo_greska=Sadržaj+fajla+ne+odgovara+odabranoj+ekstenziji", http.StatusSeeOther)
|
|
return
|
|
}
|
|
// vraćamo kursor na početak
|
|
if _, err := fajl.Seek(0, io.SeekStart); err != nil {
|
|
http.Redirect(w, r, "/podesavanja?logo_greska=Greška+pri+obradi+fajla", http.StatusSeeOther)
|
|
return
|
|
}
|
|
}
|
|
|
|
// brišemo stare logo fajlove
|
|
stari, _ := filepath.Glob("web/static/uploads/logo.*")
|
|
for _, s := range stari {
|
|
os.Remove(s)
|
|
}
|
|
|
|
odrediste := "web/static/uploads/logo" + ext
|
|
dst, err := os.Create(odrediste)
|
|
if err != nil {
|
|
log.Printf("upload loga: ne mogu kreirati fajl: %v", err)
|
|
http.Redirect(w, r, "/podesavanja?logo_greska=Greška+pri+čuvanju+fajla", http.StatusSeeOther)
|
|
return
|
|
}
|
|
defer dst.Close()
|
|
|
|
if _, err := io.Copy(dst, fajl); err != nil {
|
|
log.Printf("upload loga: greška pri kopiranju: %v", err)
|
|
http.Redirect(w, r, "/podesavanja?logo_greska=Greška+pri+čuvanju+fajla", http.StatusSeeOther)
|
|
return
|
|
}
|
|
|
|
putanja := "/static/uploads/logo" + ext
|
|
if err := sqlite.SacuvajPodesavanje(r.Context(), h.DB, "logo_putanja", putanja); err != nil {
|
|
log.Printf("upload loga: greška pri čuvanju putanje: %v", err)
|
|
http.Redirect(w, r, "/podesavanja?logo_greska=Greška+pri+čuvanju+podešavanja", http.StatusSeeOther)
|
|
return
|
|
}
|
|
|
|
http.Redirect(w, r, "/podesavanja?sacuvano=1", http.StatusSeeOther)
|
|
}
|
|
|
|
// PromeniTemu menja aktivnu temu i vraća na prethodnu stranicu
|
|
func (h *Handler) PromeniTemu(w http.ResponseWriter, r *http.Request) {
|
|
tema := chi.URLParam(r, "tema")
|
|
|
|
// proveravamo da li je validna tema
|
|
validne := map[string]bool{
|
|
"tamna": true, "svetla": true,
|
|
}
|
|
if !validne[tema] {
|
|
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
|
|
return
|
|
}
|
|
|
|
if err := sqlite.SacuvajPodesavanje(r.Context(), h.DB, "tema", tema); err != nil {
|
|
http.Error(w, "Greška pri promeni teme", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// vraćamo se na stranicu sa koje je kliknut dugmić
|
|
referer := r.Header.Get("Referer")
|
|
if referer == "" {
|
|
referer = "/dashboard"
|
|
}
|
|
http.Redirect(w, r, referer, http.StatusSeeOther)
|
|
}
|