From 0bb12318cc49421797aa7f3650b897c1cf11c977 Mon Sep 17 00:00:00 2001 From: tom Date: Mon, 24 Feb 2025 22:11:28 +0100 Subject: [PATCH] CHANGE: added team page + working on function --- Backend/endpoints/team.go | 31 ++++ Backend/endpoints/time.go | 1 - Backend/endpoints/time_create.go | 2 +- Backend/main.go | 1 + Backend/models/user.go | 25 ++++ Backend/models/workDay.go | 38 ++--- Backend/models/workWeek.go | 5 + Backend/src/main.css | 13 +- Backend/static/css/styles.css | 137 ++++++++++++++++- Backend/templates/pages.templ | 18 +++ Backend/templates/pages_templ.go | 47 ++++++ Backend/templates/teamComponents.templ | 43 ++++++ Backend/templates/teamComponents_templ.go | 173 ++++++++++++++++++++++ Backend/templates/timeComponents.templ | 2 +- Backend/templates/timeComponents_templ.go | 2 +- DB/initdb/01_create_tables.sql | 12 ++ Docker/.env.example | 1 + 17 files changed, 516 insertions(+), 35 deletions(-) create mode 100644 Backend/endpoints/team.go create mode 100644 Backend/models/workWeek.go create mode 100644 Backend/templates/teamComponents.templ create mode 100644 Backend/templates/teamComponents_templ.go diff --git a/Backend/endpoints/team.go b/Backend/endpoints/team.go new file mode 100644 index 0000000..b439e92 --- /dev/null +++ b/Backend/endpoints/team.go @@ -0,0 +1,31 @@ +package endpoints + +import ( + "arbeitszeitmessung/helper" + "arbeitszeitmessung/models" + "arbeitszeitmessung/templates" + "log" + "net/http" +) + +func TeamHandler(w http.ResponseWriter, r *http.Request) { + var user models.User + var err error + if helper.GetEnv("GO_ENV", "production") == "debug" { + user, err = (*models.User).GetByPersonalNummer(nil, 123) + } else { + if !Session.Exists(r.Context(), "user") { + log.Println("No user in session storage!") + http.Error(w, "Not logged in!", http.StatusForbidden) + return + } + user, err = (*models.User).GetByPersonalNummer(nil, Session.GetInt(r.Context(), "user")) + } + if err != nil { + log.Println("No user found with the given personal number!") + http.Redirect(w, r, "/user/login", http.StatusSeeOther) + return + } + teamMembers, err := user.GetTeamMembers() + templates.TeamPage(teamMembers).Render(r.Context(), w) +} diff --git a/Backend/endpoints/time.go b/Backend/endpoints/time.go index 7b5acdc..1d8433a 100644 --- a/Backend/endpoints/time.go +++ b/Backend/endpoints/time.go @@ -52,7 +52,6 @@ func getBookings(w http.ResponseWriter, r *http.Request) { http.Error(w, "Not logged in!", http.StatusForbidden) return } - user, err = (*models.User).GetByPersonalNummer(nil, Session.GetInt(r.Context(), "user")) } if err != nil { diff --git a/Backend/endpoints/time_create.go b/Backend/endpoints/time_create.go index 3c13053..e7e7c2e 100644 --- a/Backend/endpoints/time_create.go +++ b/Backend/endpoints/time_create.go @@ -55,7 +55,7 @@ func createBooking(w http.ResponseWriter, r *http.Request) { } func checkPassword(r *http.Request) bool { - authToken := helper.GetEnv("apiToken", "dont_access") + authToken := helper.GetEnv("API_TOKEN", "dont_access") authHeaders := r.Header.Get("Authorization") _authStart := len("Bearer ") return authToken == authHeaders[_authStart:] diff --git a/Backend/main.go b/Backend/main.go index 8ba7a39..e1e88fb 100644 --- a/Backend/main.go +++ b/Backend/main.go @@ -39,6 +39,7 @@ func main() { server.HandleFunc("/logout", endpoints.LogoutHandler) server.HandleFunc("/user/login", endpoints.LoginHandler) server.HandleFunc("/user", endpoints.UserHandler) + server.HandleFunc("/team", endpoints.TeamHandler) server.Handle("/static/", http.StripPrefix("/static/", fs)) serverSessionMiddleware := endpoints.Session.LoadAndSave(server) diff --git a/Backend/models/user.go b/Backend/models/user.go index 4cf9989..d9dc698 100644 --- a/Backend/models/user.go +++ b/Backend/models/user.go @@ -3,6 +3,7 @@ package models import ( "fmt" "log" + "time" ) type User struct { @@ -115,3 +116,27 @@ func (u *User) ChangePass(password, newPassword string) (bool, error) { } return true, nil } + +func (u *User) GetTeamMembers() ([]User, error) { + var teamMembers []User + teamMembers = append(teamMembers, *u) + return teamMembers, nil +} + +func (u *User) GetWeek(tsFrom time.Time) WorkWeek { + var bookings []WorkDay + weekStart := tsFrom.AddDate(0, 0, -1*int(tsFrom.Local().Weekday())-1) + bookings, err := (*Booking).GetBookingsGrouped(nil, u.CardUID, weekStart, time.Now()) + if err != nil { + log.Println("Error fetching bookings!") + return WorkWeek{WorkDays: bookings} + } + return WorkWeek{WorkDays: bookings} +} + +// gets the first week, that needs to be submitted +func (u *User) GetNextWeek() WorkWeek { + var week WorkWeek + return week + +} diff --git a/Backend/models/workDay.go b/Backend/models/workDay.go index 5a8f534..5112c79 100644 --- a/Backend/models/workDay.go +++ b/Backend/models/workDay.go @@ -6,38 +6,38 @@ import ( ) type WorkDay struct { - Day time.Time - Bookings []Booking - workTime time.Duration + Day time.Time + Bookings []Booking + workTime time.Duration pauseTime time.Duration } // Gets the duration someone worked that day -func (d *WorkDay) GetWorkTime() time.Duration{ +func (d *WorkDay) GetWorkTime() time.Duration { var workTime, pauseTime time.Duration var lastBooking Booking - for _, booking := range d.Bookings{ - if booking.CheckInOut % 2 == 1 { + for _, booking := range d.Bookings { + if booking.CheckInOut%2 == 1 { if !lastBooking.Timestamp.IsZero() { pauseTime += booking.Timestamp.Sub(lastBooking.Timestamp) } - }else { + } else { workTime += booking.Timestamp.Sub(lastBooking.Timestamp) } lastBooking = booking } // checks if booking is today and has no gehen yet, so the time since last kommen booking is added to workTime - if(d.Day.Day() == time.Now().Day() && len(d.Bookings) % 2 == 1){ + if d.Day.Day() == time.Now().Day() && len(d.Bookings)%2 == 1 { workTime += time.Since(lastBooking.Timestamp.Local()) } - if workTime > 6 * time.Hour && pauseTime < 45 * time.Minute { - if workTime < 9 * time.Hour && pauseTime < 30 * time.Minute { - diff := 30 * time.Minute - pauseTime + if workTime > 6*time.Hour && pauseTime < 45*time.Minute { + if workTime < 9*time.Hour && pauseTime < 30*time.Minute { + diff := 30*time.Minute - pauseTime workTime -= diff pauseTime += diff - }else if pauseTime < 45 * time.Minute { - diff := 45 * time.Minute - pauseTime + } else if pauseTime < 45*time.Minute { + diff := 45*time.Minute - pauseTime workTime -= diff pauseTime += diff } @@ -47,15 +47,15 @@ func (d *WorkDay) GetWorkTime() time.Duration{ return workTime } -func formatDuration(d time.Duration) string{ +func formatDuration(d time.Duration) string { hours := int(d.Hours()) minutes := int(d.Minutes()) % 60 - switch{ - case hours > 0: + switch { + case hours > 0: return fmt.Sprintf("%dh %dmin", hours, minutes) - case minutes >0: + case minutes > 0: return fmt.Sprintf("%dmin", minutes) - default: + default: return "" } } @@ -77,6 +77,6 @@ func (d *WorkDay) RequiresAction() bool { // returns a integer percentage of how much day has been worked of func (d *WorkDay) GetWorkDayProgress(user User) uint8 { defaultWorkTime := time.Duration(user.Arbeitszeit * float32(time.Hour)) - progress := (d.workTime.Seconds()/defaultWorkTime.Seconds())*100 + progress := (d.workTime.Seconds() / defaultWorkTime.Seconds()) * 100 return uint8(progress) } diff --git a/Backend/models/workWeek.go b/Backend/models/workWeek.go new file mode 100644 index 0000000..1cd4bcc --- /dev/null +++ b/Backend/models/workWeek.go @@ -0,0 +1,5 @@ +package models + +type WorkWeek struct { + WorkDays []WorkDay +} diff --git a/Backend/src/main.css b/Backend/src/main.css index 99c8693..5911505 100644 --- a/Backend/src/main.css +++ b/Backend/src/main.css @@ -35,12 +35,16 @@ } .grid-sub { - display: flex; - flex-direction: column; + display: grid; + grid-template-columns: subgrid; grid-column: 1 / -1; border-color: var(--color-neutral-400); } + .grid-sub:hover { + background-color: var(--color-neutral-200); + } + .grid-cell { padding: calc(var(--spacing) * 2); border-color: var(--color-neutral-400); @@ -52,9 +56,6 @@ margin: 0 10%; } - .grid-sub { - display: grid; - grid-template-columns: subgrid; - } + .grid-sub {} } } diff --git a/Backend/static/css/styles.css b/Backend/static/css/styles.css index 243660e..7f7fb05 100644 --- a/Backend/static/css/styles.css +++ b/Backend/static/css/styles.css @@ -541,6 +541,12 @@ } } @layer utilities { + .collapse { + visibility: collapse; + } + .relative { + position: relative; + } .static { position: static; } @@ -559,15 +565,30 @@ .mb-2 { margin-bottom: calc(var(--spacing) * 2); } + .block { + display: block; + } .flex { display: flex; } + .grid { + display: grid; + } .hidden { display: none; } .inline { display: inline; } + .inline-flex { + display: inline-flex; + } + .list-item { + display: list-item; + } + .table { + display: table; + } .size-2 { width: calc(var(--spacing) * 2); height: calc(var(--spacing) * 2); @@ -591,6 +612,9 @@ .w-4 { width: calc(var(--spacing) * 4); } + .w-9 { + width: calc(var(--spacing) * 9); + } .w-9\/10 { width: calc(9/10 * 100%); } @@ -606,9 +630,18 @@ .grow-1 { flex-grow: 1; } + .border-collapse { + border-collapse: collapse; + } + .transform { + transform: var(--tw-rotate-x) var(--tw-rotate-y) var(--tw-rotate-z) var(--tw-skew-x) var(--tw-skew-y); + } .cursor-pointer { cursor: pointer; } + .resize { + resize: both; + } .grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } @@ -630,6 +663,9 @@ .justify-center { justify-content: center; } + .justify-end { + justify-content: flex-end; + } .gap-2 { gap: calc(var(--spacing) * 2); } @@ -675,6 +711,9 @@ .border-neutral-300 { border-color: var(--color-neutral-300); } + .border-neutral-800 { + border-color: var(--color-neutral-800); + } .border-neutral-900 { border-color: var(--color-neutral-900); } @@ -741,9 +780,20 @@ .uppercase { text-transform: uppercase; } + .underline { + text-decoration-line: underline; + } + .outline { + outline-style: var(--tw-outline-style); + outline-width: 1px; + } .filter { filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); } + .backdrop-filter { + -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + } .transition { transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter; transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); @@ -839,11 +889,21 @@ opacity: 50%; } } + .max-md\:flex { + @media (width < 48rem) { + display: flex; + } + } .max-md\:grid { @media (width < 48rem) { display: grid; } } + .max-md\:flex-col { + @media (width < 48rem) { + flex-direction: column; + } + } .md\:col-span-1 { @media (width >= 48rem) { grid-column: span 1 / span 1; @@ -904,11 +964,14 @@ align-items: stretch; } .grid-sub { - display: flex; - flex-direction: column; + display: grid; + grid-template-columns: subgrid; grid-column: 1 / -1; border-color: var(--color-neutral-400); } + .grid-sub:hover { + background-color: var(--color-neutral-200); + } .grid-cell { padding: calc(var(--spacing) * 2); border-color: var(--color-neutral-400); @@ -918,10 +981,6 @@ grid-template-columns: repeat(5, 1fr); margin: 0 10%; } - .grid-sub { - display: grid; - grid-template-columns: subgrid; - } } } @keyframes spin { @@ -950,6 +1009,31 @@ animation-timing-function: cubic-bezier(0, 0, 0.2, 1); } } +@property --tw-rotate-x { + syntax: "*"; + inherits: false; + initial-value: rotateX(0); +} +@property --tw-rotate-y { + syntax: "*"; + inherits: false; + initial-value: rotateY(0); +} +@property --tw-rotate-z { + syntax: "*"; + inherits: false; + initial-value: rotateZ(0); +} +@property --tw-skew-x { + syntax: "*"; + inherits: false; + initial-value: skewX(0); +} +@property --tw-skew-y { + syntax: "*"; + inherits: false; + initial-value: skewY(0); +} @property --tw-divide-x-reverse { syntax: "*"; inherits: false; @@ -969,6 +1053,11 @@ syntax: "*"; inherits: false; } +@property --tw-outline-style { + syntax: "*"; + inherits: false; + initial-value: solid; +} @property --tw-blur { syntax: "*"; inherits: false; @@ -1005,6 +1094,42 @@ syntax: "*"; inherits: false; } +@property --tw-backdrop-blur { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-brightness { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-contrast { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-grayscale { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-hue-rotate { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-invert { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-opacity { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-saturate { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-sepia { + syntax: "*"; + inherits: false; +} @property --tw-duration { syntax: "*"; inherits: false; diff --git a/Backend/templates/pages.templ b/Backend/templates/pages.templ index b245ee0..d2fce19 100644 --- a/Backend/templates/pages.templ +++ b/Backend/templates/pages.templ @@ -65,3 +65,21 @@ templ UserPage(status int) { } + +templ TeamPage(teamMembers []models.User) { + @Base() + @headerComponent() +
+
+
Max Mustermann
+
+
+

an Vorgesetzten senden

+ +
+
+ for _, user := range teamMembers { + @employeComponent(user) + } +
+} diff --git a/Backend/templates/pages_templ.go b/Backend/templates/pages_templ.go index 7b18e99..f665914 100644 --- a/Backend/templates/pages_templ.go +++ b/Backend/templates/pages_templ.go @@ -195,4 +195,51 @@ func UserPage(status int) templ.Component { }) } +func TeamPage(teamMembers []models.User) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = Base().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = headerComponent().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
Max Mustermann

an Vorgesetzten senden

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, user := range teamMembers { + templ_7745c5c3_Err = employeComponent(user).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + var _ = templruntime.GeneratedTemplate diff --git a/Backend/templates/teamComponents.templ b/Backend/templates/teamComponents.templ new file mode 100644 index 0000000..9d077d4 --- /dev/null +++ b/Backend/templates/teamComponents.templ @@ -0,0 +1,43 @@ +package templates + +import ( + "arbeitszeitmessung/models" + "time" +) + +templ weekDayComponent(day models.WorkDay) { + {{ work, pause := day.GetWorkTimeString() }} +
+ @timeGaugeComponent(92, false, false) +
+

{ day.Day.Format("02.01.2006") }

+
+ { work } + { pause } +
+
+
+} + +templ employeComponent(user models.User) { + {{ + workWeek := user.GetWeek(time.Now().AddDate(0, 0, -2)) + }} +
+
+

{ user.Vorname } { user.Name }

+

Arbeitszeit

+

40h 12min

+
+
+ for _, day := range workWeek.WorkDays { + @weekDayComponent(day) + } +
+
+ +
+
+} diff --git a/Backend/templates/teamComponents_templ.go b/Backend/templates/teamComponents_templ.go new file mode 100644 index 0000000..0cf3ce1 --- /dev/null +++ b/Backend/templates/teamComponents_templ.go @@ -0,0 +1,173 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package templates + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import ( + "arbeitszeitmessung/models" + "time" +) + +func weekDayComponent(day models.WorkDay) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + work, pause := day.GetWorkTimeString() + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = timeGaugeComponent(92, false, false).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(day.Day.Format("02.01.2006")) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/teamComponents.templ`, Line: 13, Col: 130} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(work) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/teamComponents.templ`, Line: 15, Col: 36} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var5 string + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(pause) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/teamComponents.templ`, Line: 16, Col: 42} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func employeComponent(user models.User) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var6 := templ.GetChildren(ctx) + if templ_7745c5c3_Var6 == nil { + templ_7745c5c3_Var6 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + + workWeek := user.GetWeek(time.Now().AddDate(0, 0, -2)) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var7 string + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(user.Vorname) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/teamComponents.templ`, Line: 28, Col: 48} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var8 string + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(user.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/teamComponents.templ`, Line: 28, Col: 62} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "

Arbeitszeit

40h 12min

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, day := range workWeek.WorkDays { + templ_7745c5c3_Err = weekDayComponent(day).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/Backend/templates/timeComponents.templ b/Backend/templates/timeComponents.templ index 194bc00..9102f79 100644 --- a/Backend/templates/timeComponents.templ +++ b/Backend/templates/timeComponents.templ @@ -13,7 +13,7 @@ templ inputForm() { urlParams := ctx.Value("urlParams").(url.Values) user := ctx.Value("user").(models.User) }} -
+

{ user.Vorname + " " + user.Name }

diff --git a/Backend/templates/timeComponents_templ.go b/Backend/templates/timeComponents_templ.go index a0c345c..e085bd6 100644 --- a/Backend/templates/timeComponents_templ.go +++ b/Backend/templates/timeComponents_templ.go @@ -40,7 +40,7 @@ func inputForm() templ.Component { urlParams := ctx.Value("urlParams").(url.Values) user := ctx.Value("user").(models.User) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/DB/initdb/01_create_tables.sql b/DB/initdb/01_create_tables.sql index f38b59a..4a65294 100644 --- a/DB/initdb/01_create_tables.sql +++ b/DB/initdb/01_create_tables.sql @@ -41,6 +41,8 @@ CREATE TABLE "user_password" ( "zuletzt_geandert" timestamp(6) DEFAULT CURRENT_TIMESTAMP ); +-- update Funktion für pass_hash + CREATE OR REPLACE FUNCTION update_zuletzt_geandert() RETURNS TRIGGER AS $$ BEGIN @@ -57,6 +59,16 @@ BEFORE UPDATE ON user_password FOR EACH ROW EXECUTE FUNCTION update_zuletzt_geandert(); +-- audittabelle für arbeitsstunden bestätigung + +DROP TABLE IF EXISTS "buchung_wochen"; +CREATE TABLE "buchung_wochen" ( + "personal_nummer" int4, + "woche_start" date, + "buchungen" []bigserial, + "bestaetigt" bool DEFAULT FALSE, +); + -- Adds crypto extension CREATE EXTENSION IF NOT EXISTS pgcrypto; diff --git a/Docker/.env.example b/Docker/.env.example index bdde990..492fcec 100644 --- a/Docker/.env.example +++ b/Docker/.env.example @@ -7,3 +7,4 @@ POSTGRES_DB=arbeitszeitmessung EXPOSED_PORT=8000 TZ=Europe/Berlin PGTZ=Europe/Berlin +API_TOKEN=dont_access