53432c8c41
Magacin:
- Dodato premeštanje artikla u drugu kategoriju (dugme + nativni
<details> meni, bez JS-a; radi na desktopu i mobilnom)
- Endpoint POST /magacin/premesti/{id} uz proveru dozvole artikal.premesti
Backup:
- Nova podešavanja: interval automatskog backupa i broj kopija (rotacija)
- Periodični backup uz onaj pri pokretanju; interval se čita iz baze
- Migracija 037_backup_podesavanja.sql
Dozvole (RBAC):
- Dodate kartice koje su nedostajale (dashboard.prihod, prodaja.storno,
podesavanja.login_pozadina, tema.lokalno) — popravljen i bug gde su se
gasile pri svakom čuvanju matrice
- Aktivirana kontrola pregleda za prodaju, servis, klijente i dobavljače
(provera u handlerima + skrivanje iz sidebara)
- Uklonjene mrtve/obmanjujuće dozvole iz matrice i sveAkcije (korisnici,
podsetnici, artikal.pregled, kategorija.izmeni, tema.globalno,
podesavanja.app_pozadina); sveAkcije 47 -> 34
- Čišćenje zastarelih redova (siročića) u tabeli dozvola pri startu
Ostalo:
- Statički fajlovi: embed celog web/static i ispravan MIME za .js/.css
- Keš šablona: dodat admin_dozvole (stranica Dozvole se nije otvarala)
- Sidebar accordion: radi i skupljen i proširen, međusobno isključiv
133 lines
4.1 KiB
Go
133 lines
4.1 KiB
Go
package sqlite
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type sqliteDozvoleRepo struct {
|
|
db *sql.DB
|
|
defaultFn func(uloga, akcija string) bool // podrazumevane vrednosti iz middleware/dozvole.go
|
|
sveAkcije []string
|
|
}
|
|
|
|
// NoviDozvoleRepo kreira SQLite implementaciju DozvoleRepository
|
|
func NoviDozvoleRepo(db *sql.DB, defaultFn func(uloga, akcija string) bool, sveAkcije []string) *sqliteDozvoleRepo {
|
|
return &sqliteDozvoleRepo{db: db, defaultFn: defaultFn, sveAkcije: sveAkcije}
|
|
}
|
|
|
|
// InicijalizujDozvole popunjava tabelu podrazumevanim vrednostima ako je prazna
|
|
func InicijalizujDozvole(ctx context.Context, db *sql.DB, defaultFn func(uloga, akcija string) bool, sveAkcije []string) error {
|
|
var br int
|
|
_ = db.QueryRowContext(ctx, `SELECT COUNT(*) FROM dozvole`).Scan(&br)
|
|
if br > 0 {
|
|
return nil
|
|
}
|
|
return popuniPodrazumevano(ctx, db, defaultFn, sveAkcije)
|
|
}
|
|
|
|
// OcistiSirociceDoz briše iz tabele dozvola redove čija akcija više ne postoji
|
|
// u sveAkcije (npr. nakon uklanjanja zastarele dozvole iz koda). Vraća broj obrisanih.
|
|
func OcistiSirociceDoz(ctx context.Context, db *sql.DB, sveAkcije []string) (int64, error) {
|
|
if len(sveAkcije) == 0 {
|
|
// sigurnosna brana — bez liste bismo obrisali sve, što ne želimo
|
|
return 0, nil
|
|
}
|
|
placeholders := strings.Repeat("?,", len(sveAkcije))
|
|
placeholders = strings.TrimSuffix(placeholders, ",")
|
|
args := make([]any, len(sveAkcije))
|
|
for i, a := range sveAkcije {
|
|
args[i] = a
|
|
}
|
|
rezultat, err := db.ExecContext(ctx,
|
|
`DELETE FROM dozvole WHERE akcija NOT IN (`+placeholders+`)`, args...)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("ntech: dozvole.OcistiSirocice: %w", err)
|
|
}
|
|
br, _ := rezultat.RowsAffected()
|
|
return br, nil
|
|
}
|
|
|
|
// popuniPodrazumevano upisuje sve podrazumevane dozvole u bazu
|
|
func popuniPodrazumevano(ctx context.Context, db *sql.DB, defaultFn func(uloga, akcija string) bool, sveAkcije []string) error {
|
|
for _, uloga := range []string{"radnik", "admin", "superadmin"} {
|
|
for _, akcija := range sveAkcije {
|
|
dozvoljeno := 0
|
|
if defaultFn(uloga, akcija) {
|
|
dozvoljeno = 1
|
|
}
|
|
if _, err := db.ExecContext(ctx,
|
|
`INSERT OR IGNORE INTO dozvole (uloga, akcija, dozvoljeno) VALUES (?, ?, ?)`,
|
|
uloga, akcija, dozvoljeno); err != nil {
|
|
return fmt.Errorf("ntech: dozvole.Inicijalizuj: %w", err)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *sqliteDozvoleRepo) ImaDozvolu(ctx context.Context, uloga, akcija string) bool {
|
|
var dozvoljeno int
|
|
err := r.db.QueryRowContext(ctx,
|
|
`SELECT dozvoljeno FROM dozvole WHERE uloga = ? AND akcija = ?`, uloga, akcija).Scan(&dozvoljeno)
|
|
if err != nil {
|
|
// fallback na podrazumevano ako red nije pronađen
|
|
return r.defaultFn(uloga, akcija)
|
|
}
|
|
return dozvoljeno == 1
|
|
}
|
|
|
|
func (r *sqliteDozvoleRepo) SveDozvole(ctx context.Context, uloga string) map[string]bool {
|
|
rows, err := r.db.QueryContext(ctx,
|
|
`SELECT akcija, dozvoljeno FROM dozvole WHERE uloga = ?`, uloga)
|
|
if err != nil {
|
|
// fallback na podrazumevano
|
|
m := make(map[string]bool, len(r.sveAkcije))
|
|
for _, a := range r.sveAkcije {
|
|
m[a] = r.defaultFn(uloga, a)
|
|
}
|
|
return m
|
|
}
|
|
defer rows.Close()
|
|
|
|
m := make(map[string]bool, len(r.sveAkcije))
|
|
for rows.Next() {
|
|
var akcija string
|
|
var dozvoljeno int
|
|
if err := rows.Scan(&akcija, &dozvoljeno); err == nil {
|
|
m[akcija] = dozvoljeno == 1
|
|
}
|
|
}
|
|
// popuni eventualno nedostajuće akcije podrazumevanim vrednostima
|
|
for _, a := range r.sveAkcije {
|
|
if _, ok := m[a]; !ok {
|
|
m[a] = r.defaultFn(uloga, a)
|
|
}
|
|
}
|
|
return m
|
|
}
|
|
|
|
func (r *sqliteDozvoleRepo) Sacuvaj(ctx context.Context, uloga, akcija string, dozvoljeno bool) error {
|
|
d := 0
|
|
if dozvoljeno {
|
|
d = 1
|
|
}
|
|
_, err := r.db.ExecContext(ctx,
|
|
`INSERT INTO dozvole (uloga, akcija, dozvoljeno) VALUES (?, ?, ?)
|
|
ON CONFLICT (uloga, akcija) DO UPDATE SET dozvoljeno = excluded.dozvoljeno`,
|
|
uloga, akcija, d)
|
|
if err != nil {
|
|
return fmt.Errorf("ntech: dozvole.Sacuvaj: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *sqliteDozvoleRepo) Reset(ctx context.Context) error {
|
|
if _, err := r.db.ExecContext(ctx, `DELETE FROM dozvole`); err != nil {
|
|
return fmt.Errorf("ntech: dozvole.Reset: %w", err)
|
|
}
|
|
return popuniPodrazumevano(ctx, r.db, r.defaultFn, r.sveAkcije)
|
|
}
|