From 3439fff841c3c68a0d5f992904f1bc037598e141 Mon Sep 17 00:00:00 2001 From: tom_trgr Date: Tue, 23 Dec 2025 12:21:03 +0100 Subject: [PATCH] added feiertage to database + endpoint to insert every year --- Backend/endpoints/auto-feiertage.go | 33 ++++++- Backend/models/absence.go | 4 + Backend/models/iworkday.go | 22 +++++ Backend/models/publicHoliday.go | 105 ++++++++++++++++++--- Backend/models/workDay.go | 10 +- Backend/templates/timePage.templ | 43 ++++----- Backend/templates/timePage_templ.go | 103 +++++++++++--------- DB/initdb/01_schema.sql | 4 +- DB/initdb/03_create_user.sh | 4 +- Docker/env.example | 3 +- migrations/20251217215955_feiertage.up.sql | 2 + 11 files changed, 245 insertions(+), 88 deletions(-) diff --git a/Backend/endpoints/auto-feiertage.go b/Backend/endpoints/auto-feiertage.go index 7079a36..6f32bca 100644 --- a/Backend/endpoints/auto-feiertage.go +++ b/Backend/endpoints/auto-feiertage.go @@ -1,6 +1,8 @@ package endpoints import ( + "arbeitszeitmessung/helper/paramParser" + "arbeitszeitmessung/models" "log/slog" "net/http" "time" @@ -9,6 +11,33 @@ import ( ) func FeiertagsHandler(w http.ResponseWriter, r *http.Request) { - feiertage := feiertage.Sachsen(time.Now().Year(), true) - slog.Info("Hier sind die Feiertage", "Feiertage", feiertage) + pp := paramParser.New(r.URL.Query()) + slog.Debug("Generating Holidays") + from := pp.ParseTimestampFallback("from", "2006", time.Now().AddDate(-1, 0, -time.Now().YearDay())) + to := pp.ParseTimestampFallback("to", "2006", time.Now().AddDate(0, 0, -time.Now().YearDay()+1)) + + var publicHolidays map[string]models.PublicHoliday = make(map[string]models.PublicHoliday) + + yearDelta := to.Year() - from.Year() + var holidays = feiertage.Sachsen(to.Year(), true) + for _, f := range holidays.Feiertage { + publicHolidays[f.Time.Format(time.DateOnly)] = models.NewHolidayFromFeiertag(f) + } + + repeatingHolidays, err := models.GetRepeatingHolidays(from, to.AddDate(0, 0, -1)) + if err != nil { + slog.Warn("Error getting holidays", slog.Any("Error", err)) + } + slog.Debug("Found repeating Holidays", "num", len(repeatingHolidays), "from", from, "to", to, "yeardelta", yearDelta) + for _, day := range repeatingHolidays { + day.Time = day.Time.AddDate(yearDelta, 0, 0) + publicHolidays[day.Date().Format(time.DateOnly)] = day + } + slog.Debug("Added repeating holidays", "num", len(holidays.Feiertage)) + for _, feiertag := range publicHolidays { + slog.Debug("Found holiday", "holiday", feiertag) + if err := feiertag.Insert(); err != nil { + slog.Warn("Error inserting Feiertag", slog.Any("Error", err)) + } + } } diff --git a/Backend/models/absence.go b/Backend/models/absence.go index 0086337..afeb79e 100644 --- a/Backend/models/absence.go +++ b/Backend/models/absence.go @@ -45,6 +45,10 @@ func (a *Absence) Date() time.Time { return a.Day.Truncate(24 * time.Hour) } +func (a *Absence) Type() DayType { + return DayTypeAbsence +} + func (a *Absence) IsMultiDay() bool { return !a.DateFrom.Equal(a.DateTo) } diff --git a/Backend/models/iworkday.go b/Backend/models/iworkday.go index 4970ba6..aff96ba 100644 --- a/Backend/models/iworkday.go +++ b/Backend/models/iworkday.go @@ -3,12 +3,14 @@ package models import ( "arbeitszeitmessung/helper" "log" + "log/slog" "time" ) type IWorkDay interface { Date() time.Time ToString() string + Type() DayType IsWorkDay() bool IsKurzArbeit() bool GetDayProgress(User) int8 @@ -19,6 +21,14 @@ type IWorkDay interface { GetOvertime(User, WorktimeBase, bool) time.Duration } +type DayType int + +const ( + DayTypeWorkday DayType = 1 + DayTypeAbsence DayType = 2 + DayTypeHoliday DayType = 3 +) + func GetDays(user User, tsFrom, tsTo time.Time, orderedForward bool) []IWorkDay { var allDays map[string]IWorkDay = make(map[string]IWorkDay) @@ -30,6 +40,10 @@ func GetDays(user User, tsFrom, tsTo time.Time, orderedForward bool) []IWorkDay log.Println("Error gettings absences for all Days!", err) return nil } + holidays, err := GetHolidaysFromTo(tsFrom, tsTo) + if err != nil { + slog.Warn("Error getting holidays from DB!", slog.Any("Error", err)) + } for _, day := range absences { if helper.IsWeekend(day.Date()) { continue @@ -50,6 +64,14 @@ func GetDays(user User, tsFrom, tsTo time.Time, orderedForward bool) []IWorkDay } } + for _, day := range holidays { + if helper.IsWeekend(day.Date()) { + continue + } + allDays[day.Date().Format(time.DateOnly)] = &day + slog.Debug("Logging Holiday: ", slog.String("HolidayName", allDays[day.Date().Format(time.DateOnly)].ToString()), slog.Any("Overtime", day.GetOvertime(user, WorktimeBaseDay, false).String()), "wokrtie", float32(day.worktime)/100) + } + sortedDays := sortDays(allDays, orderedForward) return sortedDays } diff --git a/Backend/models/publicHoliday.go b/Backend/models/publicHoliday.go index 351ae6a..97dce3e 100644 --- a/Backend/models/publicHoliday.go +++ b/Backend/models/publicHoliday.go @@ -1,23 +1,90 @@ package models -import "time" +import ( + "time" + + "github.com/wlbr/feiertage" +) + +// type PublicHoliday feiertage.Feiertag type PublicHoliday struct { - name string - date time.Time + feiertage.Feiertag + repeat int8 + worktime int8 +} + +func NewHolidayFromFeiertag(f feiertage.Feiertag) PublicHoliday { + return PublicHoliday{ + Feiertag: f, + repeat: 0, + worktime: 100, + } } func GetHolidaysFromTo(tsFrom, tsTo time.Time) ([]PublicHoliday, error) { - return make([]PublicHoliday, 0), nil + var publicHolidays []PublicHoliday + qStr, err := DB.Prepare(`SELECT datum, name, wiederholen, arbeitszeit_equivalent FROM s_feiertage WHERE datum::DATE >= $1::DATE AND datum::DATE <= $2::DATE;`) + if err != nil { + return publicHolidays, err + } + + rows, err := qStr.Query(tsFrom, tsTo) + if err != nil { + return publicHolidays, err + } + defer rows.Close() + for rows.Next() { + var publicHoliday PublicHoliday + if err := rows.Scan(&publicHoliday.Time, &publicHoliday.Text, &publicHoliday.repeat, &publicHoliday.worktime); err != nil { + return publicHolidays, err + } + publicHolidays = append(publicHolidays, publicHoliday) + } + return publicHolidays, nil +} + +func GetRepeatingHolidays(tsFrom, tsTo time.Time) ([]PublicHoliday, error) { + var publicHolidays []PublicHoliday + qStr, err := DB.Prepare(`SELECT datum, name, wiederholen, arbeitszeit_equivalent FROM s_feiertage WHERE wiederholen = 1 AND datum::DATE >= $1::DATE AND datum::DATE <= $2::DATE;`) + if err != nil { + return publicHolidays, err + } + rows, err := qStr.Query(tsFrom, tsTo) + if err != nil { + return publicHolidays, err + } + defer rows.Close() + for rows.Next() { + var publicHoliday PublicHoliday + if err := rows.Scan(&publicHoliday.Time, &publicHoliday.Text, &publicHoliday.repeat, &publicHoliday.worktime); err != nil { + return publicHolidays, err + } + publicHolidays = append(publicHolidays, publicHoliday) + } + return publicHolidays, nil + +} +func (p *PublicHoliday) Insert() error { + qStr, err := DB.Prepare(`INSERT INTO s_feiertage(name, datum, wiederholen, arbeitszeit_equivalent) VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING;`) + if err != nil { + return err + } + _, err = qStr.Exec(p.Text, p.Time, p.repeat, p.worktime) + return err +} + +func (p *PublicHoliday) Type() DayType { + return DayTypeHoliday } // Interface implementation func (p *PublicHoliday) Date() time.Time { - return time.Now() + return p.Time } func (p *PublicHoliday) ToString() string { - return "" + return p.Text } func (p *PublicHoliday) IsWorkDay() bool { @@ -29,14 +96,20 @@ func (p *PublicHoliday) IsKurzArbeit() bool { } func (p *PublicHoliday) GetDayProgress(User) int8 { - return 0 + return p.worktime } func (p *PublicHoliday) RequiresAction() bool { return false } -func (p *PublicHoliday) GetWorktime(User, WorktimeBase, bool) time.Duration { +func (p *PublicHoliday) GetWorktime(u User, base WorktimeBase, includeKurzarbeit bool) time.Duration { + switch base { + case WorktimeBaseDay: + return u.ArbeitszeitProTagFrac(float32(p.worktime / 100)) + case WorktimeBaseWeek: + return u.ArbeitszeitProWocheFrac(float32(p.worktime/100) * 0.2) + } return 0 } @@ -44,10 +117,16 @@ func (p *PublicHoliday) GetPausetime(User, WorktimeBase, bool) time.Duration { return 0 } -func (p *PublicHoliday) GetTimes(User, WorktimeBase, bool) (work, pause, overtime time.Duration) { - return 0, 0, 0 -} - -func (p *PublicHoliday) GetOvertime(User, WorktimeBase, bool) time.Duration { +func (p *PublicHoliday) GetOvertime(u User, base WorktimeBase, includeKurzarbeit bool) time.Duration { + switch base { + case WorktimeBaseDay: + return u.ArbeitszeitProTagFrac(float32(p.worktime)/100) - u.ArbeitszeitProTagFrac(1) + case WorktimeBaseWeek: + return u.ArbeitszeitProWocheFrac(float32(p.worktime)/500) - u.ArbeitszeitProWocheFrac(0.2) + } return 0 } + +func (p *PublicHoliday) GetTimes(u User, base WorktimeBase, includeKurzarbeit bool) (work, pause, overtime time.Duration) { + return p.GetWorktime(u, base, includeKurzarbeit), 0, 0 +} diff --git a/Backend/models/workDay.go b/Backend/models/workDay.go index e8f1bd6..afdcdc9 100644 --- a/Backend/models/workDay.go +++ b/Backend/models/workDay.go @@ -23,11 +23,11 @@ type WorkDay struct { worktimeAbsece Absence } -type WorktimeBase string +type WorktimeBase int const ( - WorktimeBaseWeek WorktimeBase = "week" - WorktimeBaseDay WorktimeBase = "day" + WorktimeBaseWeek WorktimeBase = 5 + WorktimeBaseDay WorktimeBase = 1 ) func (d *WorkDay) GetWorktimeAbsence() Absence { @@ -126,6 +126,10 @@ func (d *WorkDay) Date() time.Time { return d.Day } +func (d *WorkDay) Type() DayType { + return DayTypeWorkday +} + func (d *WorkDay) GenerateKurzArbeitBookings(u User) (time.Time, time.Time) { var timeFrom, timeTo time.Time if d.GetWorktime(u, WorktimeBaseDay, false) >= u.ArbeitszeitProTag() { diff --git a/Backend/templates/timePage.templ b/Backend/templates/timePage.templ index 92cb0a2..3e8723c 100644 --- a/Backend/templates/timePage.templ +++ b/Backend/templates/timePage.templ @@ -9,9 +9,7 @@ import ( ) templ TimePage(workDays []models.WorkDay, lastSub time.Time) { - {{ - allDays := ctx.Value("days").([]models.IWorkDay) - }} + {{ allDays := ctx.Value("days").([]models.IWorkDay) }} @Base() @headerComponent()
@@ -129,26 +127,25 @@ templ defaultDayComponent(day models.IWorkDay) {
@lineComponent()
- if day.IsWorkDay() { - {{ - workDay, _ := day.(*models.WorkDay) - }} - @newAbsenceComponent() - if len(workDay.Bookings) < 1 { -

Keine Buchung gefunden. Bitte Arbeitsstunden oder Grund der Abwesenheit eingeben!

- } - if workDay.IsKurzArbeit() && len(workDay.Bookings) > 0 { - @absenceComponent(workDay.GetKurzArbeit(), true) - } - for _, booking := range workDay.Bookings { - @bookingComponent(booking) - } - @newBookingComponent(workDay) - } else { - {{ - absentDay, _ := day.(*models.Absence) - }} - @absenceComponent(absentDay, false) + switch day.Type() { + case models.DayTypeWorkday: + {{ workDay, _ := day.(*models.WorkDay) }} + @newAbsenceComponent() + if len(workDay.Bookings) < 1 { +

Keine Buchung gefunden. Bitte Arbeitsstunden oder Grund der Abwesenheit eingeben!

+ } + if workDay.IsKurzArbeit() && len(workDay.Bookings) > 0 { + @absenceComponent(workDay.GetKurzArbeit(), true) + } + for _, booking := range workDay.Bookings { + @bookingComponent(booking) + } + @newBookingComponent(workDay) + case models.DayTypeAbsence: + {{ absentDay, _ := day.(*models.Absence) }} + @absenceComponent(absentDay, false) + default: +

{ day.ToString() }

}
diff --git a/Backend/templates/timePage_templ.go b/Backend/templates/timePage_templ.go index 001a6ee..d6c1520 100644 --- a/Backend/templates/timePage_templ.go +++ b/Backend/templates/timePage_templ.go @@ -112,7 +112,7 @@ func inputForm() templ.Component { var templ_7745c5c3_Var3 string templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(user.Vorname + " " + user.Name) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 36, Col: 66} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 34, Col: 66} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { @@ -125,7 +125,7 @@ func inputForm() templ.Component { var templ_7745c5c3_Var4 string templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(user.Overtime) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 39, Col: 42} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 37, Col: 42} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { @@ -146,7 +146,7 @@ func inputForm() templ.Component { var templ_7745c5c3_Var5 string templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(urlParams.Get("time_from")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 45, Col: 57} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 43, Col: 57} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) if templ_7745c5c3_Err != nil { @@ -159,7 +159,7 @@ func inputForm() templ.Component { var templ_7745c5c3_Var6 string templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(urlParams.Get("time_to")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 46, Col: 55} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 44, Col: 55} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) if templ_7745c5c3_Err != nil { @@ -177,7 +177,7 @@ func inputForm() templ.Component { var templ_7745c5c3_Var7 string templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(int(absence.Id))) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 63, Col: 51} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 61, Col: 51} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) if templ_7745c5c3_Err != nil { @@ -190,7 +190,7 @@ func inputForm() templ.Component { var templ_7745c5c3_Var8 string templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(absence.Name) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 63, Col: 68} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 61, Col: 68} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) if templ_7745c5c3_Err != nil { @@ -268,7 +268,7 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { var templ_7745c5c3_Var12 string templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(helper.FormatGermanDayOfWeek(day.Date())) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 101, Col: 98} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 99, Col: 98} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) if templ_7745c5c3_Err != nil { @@ -281,7 +281,7 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { var templ_7745c5c3_Var13 string templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(day.Date().Format("02.01.2006")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 101, Col: 142} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 99, Col: 142} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) if templ_7745c5c3_Err != nil { @@ -309,7 +309,7 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { var templ_7745c5c3_Var14 string templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(helper.FormatDuration(work)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 114, Col: 155} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 112, Col: 155} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) if templ_7745c5c3_Err != nil { @@ -332,7 +332,7 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { var templ_7745c5c3_Var15 string templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(helper.FormatDuration(pause)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 117, Col: 173} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 115, Col: 173} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) if templ_7745c5c3_Err != nil { @@ -355,7 +355,7 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { var templ_7745c5c3_Var16 string templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(helper.FormatDuration(overtime)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 122, Col: 41} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 120, Col: 41} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) if templ_7745c5c3_Err != nil { @@ -388,7 +388,7 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { var templ_7745c5c3_Var18 string templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs("time-" + day.Date().Format(time.DateOnly)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 131, Col: 56} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 129, Col: 56} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) if templ_7745c5c3_Err != nil { @@ -411,7 +411,8 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - if day.IsWorkDay() { + switch day.Type() { + case models.DayTypeWorkday: workDay, _ := day.(*models.WorkDay) templ_7745c5c3_Err = newAbsenceComponent().Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { @@ -451,14 +452,32 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - } else { + case models.DayTypeAbsence: absentDay, _ := day.(*models.Absence) templ_7745c5c3_Err = absenceComponent(absentDay, false).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } + default: + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var20 string + templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(day.ToString()) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 148, Col: 25} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -466,7 +485,7 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -490,64 +509,64 @@ func absentInput(a models.Absence) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var20 := templ.GetChildren(ctx) - if templ_7745c5c3_Var20 == nil { - templ_7745c5c3_Var20 = templ.NopComponent + templ_7745c5c3_Var21 := templ.GetChildren(ctx) + if templ_7745c5c3_Var21 == nil { + templ_7745c5c3_Var21 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "\"> ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/DB/initdb/01_schema.sql b/DB/initdb/01_schema.sql index 978d7c9..6e18e78 100755 --- a/DB/initdb/01_schema.sql +++ b/DB/initdb/01_schema.sql @@ -109,7 +109,9 @@ DROP TABLE IF EXISTS "s_feiertage"; CREATE TABLE "s_feiertage" ( "counter_id" serial PRIMARY KEY NOT NULL, "datum" date NOT NULL, - "name" varchar(100) NOT NULL + "name" varchar(100) NOT NULL, + "wiederholen" smallint NOT NULL DEFAULT 0, + "arbeitszeit_equivalent" smallint NOT NULL DEFAULT 100 ); CREATE UNIQUE index feiertage_unique_pro_jahr on s_feiertage ( diff --git a/DB/initdb/03_create_user.sh b/DB/initdb/03_create_user.sh index c850d00..fa78f94 100755 --- a/DB/initdb/03_create_user.sh +++ b/DB/initdb/03_create_user.sh @@ -7,8 +7,8 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E CREATE USER $POSTGRES_API_USER WITH ENCRYPTED PASSWORD '$POSTGRES_API_PASS'; GRANT CONNECT ON DATABASE $POSTGRES_DB TO $POSTGRES_API_USER; GRANT USAGE ON SCHEMA public TO $POSTGRES_API_USER; - GRANT SELECT, INSERT, UPDATE ON anwesenheit, abwesenheit, user_password, wochen_report TO $POSTGRES_API_USER; - GRANT SELECT ON s_personal_daten, s_abwesenheit_typen, s_anwesenheit_typen TO $POSTGRES_API_USER; + GRANT SELECT, INSERT, UPDATE ON anwesenheit, abwesenheit, user_password, wochen_report, s_feiertage TO $POSTGRES_API_USER; + GRANT SELECT ON s_personal_daten, s_abwesenheit_typen, s_anwesenheit_typen, s_feiertage TO $POSTGRES_API_USER; GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO $POSTGRES_API_USER; EOSQL diff --git a/Docker/env.example b/Docker/env.example index ce59b7b..caccaa8 100644 --- a/Docker/env.example +++ b/Docker/env.example @@ -4,9 +4,8 @@ POSTGRES_API_USER=api_nutzer # Postgres API Nutzername (f POSTGRES_API_PASS=password # Postgres API Passwort (für Arbeitszeitmessung) POSTGRES_PATH=../DB # Datebank Pfad (relativ zu Docker Ordner oder absoluter pfad mit /...) POSTGRES_DB=arbeitszeitmessung # Postgres Datenbank Name -POSTGRES_PORT=127.0.0.1:5432 # Postgres Port will not be exposed by default. +POSTGRES_PORT=127.0.0.1:5432 # Postgres Port will not be exposed by default. regex:^[0-9]{1,5}$ TZ=Europe/Berlin # Zeitzone -PGTZ=Europe/Berlin # Zeitzone API_TOKEN=dont_access # API Token für ESP Endpoints WEB_PORT=8000 # Port from which Arbeitszeitmessung should be accessable regex:^[0-9]{1,5}$ TYPST_CONTAINER=arbeitszeitmessung-doc-creator # Name of the pdf compiler container diff --git a/migrations/20251217215955_feiertage.up.sql b/migrations/20251217215955_feiertage.up.sql index 86df18f..69072a0 100644 --- a/migrations/20251217215955_feiertage.up.sql +++ b/migrations/20251217215955_feiertage.up.sql @@ -5,6 +5,8 @@ CREATE TABLE "s_feiertage" ( "counter_id" serial NOT NULL, "datum" date NOT NULL, "name" character varying(100) NOT NULL, + "wiederholen" smallint NOT NULL DEFAULT 0, + "arbeitszeit_equivalent" smallint NOT NULL DEFAULT 100, PRIMARY KEY ("counter_id") ); -- create index "feiertage_unique_pro_jahr" to table: "s_feiertage"