feat: booking can only in between specified hours
every booking happening outside these hours will be clamped to the hours also added few more config options + regex filters
This commit is contained in:
@@ -39,6 +39,11 @@ type Booking struct {
|
||||
Valid bool `json:"valid"`
|
||||
}
|
||||
|
||||
type BookingOptions struct {
|
||||
AllowOutOfBounds bool
|
||||
AllowUnknownUser bool
|
||||
}
|
||||
|
||||
type IDatabase interface {
|
||||
Prepare(query string) (*sql.Stmt, error)
|
||||
Exec(query string, args ...any) (sql.Result, error)
|
||||
@@ -46,6 +51,8 @@ type IDatabase interface {
|
||||
|
||||
var DB IDatabase
|
||||
|
||||
var Options BookingOptions
|
||||
|
||||
func (b *Booking) NewBooking(cardUid string, gereatId int16, checkInOut int16, typeId int8) Booking {
|
||||
bookingType, err := GetBookingTypeById(typeId)
|
||||
if err != nil {
|
||||
@@ -92,10 +99,44 @@ func (b *Booking) Verify() bool {
|
||||
} else {
|
||||
b.BookingType.Name = bookingType.Name
|
||||
}
|
||||
|
||||
user, err := GetUserByCardUID(b.CardUID)
|
||||
if err == sql.ErrNoRows {
|
||||
log.Println("Cannot find user with given CardUID")
|
||||
return Options.AllowUnknownUser // if allow do not fail verify if not allow fail verify
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
slog.Error("Cannot get user from CardUID", "error", err)
|
||||
return false
|
||||
}
|
||||
|
||||
if bookingOutOfBounds(b, &user) {
|
||||
auditLog, closeLog := logs.NewAudit()
|
||||
defer closeLog()
|
||||
if !Options.AllowOutOfBounds {
|
||||
return false
|
||||
}
|
||||
|
||||
oldTime := b.Timestamp
|
||||
if oldTime.IsZero() {
|
||||
oldTime = time.Now()
|
||||
}
|
||||
if b.CheckInOut%2 == 1 && b.CheckInOut < 200 { //kommen Booking
|
||||
b.Timestamp = user.ArbeitMinStartTime(oldTime)
|
||||
} else {
|
||||
b.Timestamp = user.ArbeitMaxEndeTime(oldTime)
|
||||
}
|
||||
auditLog.Printf("Buchung (%s) von '%s' außerhalb der regulaeren Zeit. Verschieben der Zeit %s -> %s", b.GetBookingType(), user.CardUID, oldTime.Format(time.TimeOnly), b.Timestamp.Format(time.TimeOnly))
|
||||
slog.Info("Booking is out of work time bounds, setting time to match worktime bounds", "new_time", b.Timestamp.String(), "old_time", oldTime)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (b *Booking) Insert() error {
|
||||
if !b.Timestamp.IsZero() {
|
||||
return b.InsertWithTimestamp()
|
||||
}
|
||||
if !checkLastBooking(*b) {
|
||||
return SameBookingError{}
|
||||
}
|
||||
@@ -224,20 +265,21 @@ func (b *Booking) Update(nb Booking) {
|
||||
b.GeraetID = nb.GeraetID
|
||||
}
|
||||
if b.Timestamp != nb.Timestamp {
|
||||
auditLog.Printf("Änderung in Buchung %d von '%s': Buchungszeit (%s -> %s).", b.CounterId, b.CardUID, b.Timestamp.Format("15:04"), nb.Timestamp.Format("15:04)"))
|
||||
auditLog.Printf("Änderung in Buchung %d von '%s': Buchungszeit (%s -> %s).", b.CounterId, b.CardUID, b.Timestamp.Format(time.TimeOnly), nb.Timestamp.Format(time.TimeOnly))
|
||||
b.Timestamp = nb.Timestamp
|
||||
}
|
||||
}
|
||||
|
||||
func checkLastBooking(b Booking) bool {
|
||||
var check_in_out int
|
||||
slog.Info("Checking with timestamp:", "timestamp", b.Timestamp.String())
|
||||
stmt, err := DB.Prepare((`SELECT check_in_out FROM "anwesenheit" WHERE "card_uid" = $1 AND "timestamp" <= $2 ORDER BY "timestamp" DESC LIMIT 1;`))
|
||||
var timestamp time.Time
|
||||
slog.Debug("Checking with timestamp:", "timestamp", b.Timestamp)
|
||||
stmt, err := DB.Prepare((`SELECT check_in_out, timestamp FROM "anwesenheit" WHERE "card_uid" = $1 AND "timestamp" <= $2 ORDER BY "timestamp" DESC LIMIT 1;`))
|
||||
if err != nil {
|
||||
log.Fatalf("Error preparing query: %v", err)
|
||||
return false
|
||||
}
|
||||
err = stmt.QueryRow(b.CardUID, b.Timestamp).Scan(&check_in_out)
|
||||
err = stmt.QueryRow(b.CardUID, b.Timestamp).Scan(&check_in_out, ×tamp)
|
||||
slog.Info("Checking last bookings check_in_out", "Check", check_in_out)
|
||||
if err == sql.ErrNoRows {
|
||||
return true
|
||||
@@ -246,9 +288,13 @@ func checkLastBooking(b Booking) bool {
|
||||
log.Println("Error checking last booking: ", err)
|
||||
return false
|
||||
}
|
||||
|
||||
if int16(check_in_out)%2 == b.CheckInOut%2 {
|
||||
return false
|
||||
}
|
||||
if timestamp.Equal(b.Timestamp) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -257,8 +303,6 @@ func (b *Booking) UpdateTime(newTime time.Time) {
|
||||
if hour == b.Timestamp.Hour() && minute == b.Timestamp.Minute() {
|
||||
return
|
||||
}
|
||||
// TODO: add check for time overlap
|
||||
|
||||
var newBooking Booking
|
||||
newBooking.Timestamp = time.Date(b.Timestamp.Year(), b.Timestamp.Month(), b.Timestamp.Day(), hour, minute, 0, 0, b.Timestamp.Location())
|
||||
if b.CheckInOut < 3 {
|
||||
@@ -268,14 +312,11 @@ func (b *Booking) UpdateTime(newTime time.Time) {
|
||||
newBooking.CheckInOut = 4
|
||||
}
|
||||
b.Update(newBooking)
|
||||
// TODO Check verify
|
||||
if b.Verify() {
|
||||
b.Save()
|
||||
} else {
|
||||
log.Println("Cannot save updated booking!", b.ToString())
|
||||
}
|
||||
// b.Verify()
|
||||
// b.Save()
|
||||
}
|
||||
|
||||
func (b *Booking) ToString() string {
|
||||
@@ -327,3 +368,12 @@ func GetBookingTypesCached() []BookingType {
|
||||
}
|
||||
return types.([]BookingType)
|
||||
}
|
||||
|
||||
func bookingOutOfBounds(b *Booking, u *User) bool {
|
||||
bookingTime := b.Timestamp
|
||||
if b.Timestamp.IsZero() {
|
||||
bookingTime = time.Now()
|
||||
}
|
||||
res := bookingTime.Before(u.ArbeitMinStartTime(bookingTime)) || bookingTime.After(u.ArbeitMaxEndeTime(bookingTime))
|
||||
return res
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user