dev/main #19
@@ -26,11 +26,11 @@ func autoLogout(w http.ResponseWriter) {
|
||||
}
|
||||
for _, user := range users {
|
||||
if user.CheckAnwesenheit() {
|
||||
err = user.Logout()
|
||||
err = user.CheckOut()
|
||||
if err != nil {
|
||||
fmt.Printf("Error logging out user %v\n", err)
|
||||
}else {
|
||||
logged_out_users = append(logged_out_users, user)
|
||||
} else {
|
||||
logged_out_users = append(logged_out_users, user)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"arbeitszeitmessung/helper"
|
||||
"arbeitszeitmessung/models"
|
||||
"arbeitszeitmessung/templates"
|
||||
"context"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -34,22 +35,15 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func UserSettingsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
helper.RequiresLogin(Session, w, r)
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
showUserPage(w, r, 0)
|
||||
break
|
||||
case http.MethodPost:
|
||||
changePassword(w, r)
|
||||
break
|
||||
default:
|
||||
http.Error(w, "Method not allowed!", http.StatusMethodNotAllowed)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func showLoginPage(w http.ResponseWriter, r *http.Request, failed bool) {
|
||||
r = r.WithContext(context.WithValue(r.Context(), "session", Session))
|
||||
if helper.GetEnv("GO_ENV", "production") == "debug" {
|
||||
// http.Redirect(w, r, "/time", http.StatusSeeOther)
|
||||
templates.LoginPage(failed).Render(r.Context(), w)
|
||||
}
|
||||
if Session.Exists(r.Context(), "user") {
|
||||
http.Redirect(w, r, "/time", http.StatusSeeOther)
|
||||
}
|
||||
templates.LoginPage(failed).Render(r.Context(), w)
|
||||
}
|
||||
|
||||
@@ -91,38 +85,3 @@ func loginUser(w http.ResponseWriter, r *http.Request) {
|
||||
showLoginPage(w, r, false)
|
||||
return
|
||||
}
|
||||
|
||||
// change user password and store salted hash in db
|
||||
func changePassword(w http.ResponseWriter, r *http.Request) {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
log.Println("Error parsing form!", err)
|
||||
http.Error(w, "Error parsing form error", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
password := r.FormValue("password")
|
||||
newPassword := r.FormValue("new_password")
|
||||
if password == "" || newPassword == "" || newPassword != r.FormValue("new_password_repeat") {
|
||||
showUserPage(w, r, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
user, err := (*models.User).GetByPersonalNummer(nil, Session.GetInt(r.Context(), "user"))
|
||||
if err != nil {
|
||||
log.Println("Error getting user!", err)
|
||||
showUserPage(w, r, http.StatusBadRequest)
|
||||
}
|
||||
auth, err := user.ChangePass(password, newPassword)
|
||||
if err != nil {
|
||||
log.Println("Error when changing password!", err)
|
||||
}
|
||||
if auth {
|
||||
showUserPage(w, r, http.StatusOK)
|
||||
return
|
||||
}
|
||||
showUserPage(w, r, http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
func showUserPage(w http.ResponseWriter, r *http.Request, status int) {
|
||||
templates.UserPage(status).Render(r.Context(), w)
|
||||
return
|
||||
}
|
||||
76
Backend/endpoints/user-settings.go
Normal file
76
Backend/endpoints/user-settings.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"arbeitszeitmessung/helper"
|
||||
"arbeitszeitmessung/models"
|
||||
"arbeitszeitmessung/templates"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func UserSettingsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
helper.RequiresLogin(Session, w, r)
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
showUserPage(w, r, 0)
|
||||
break
|
||||
case http.MethodPost:
|
||||
switch r.FormValue("action") {
|
||||
case "change-pass":
|
||||
changePassword(w, r)
|
||||
break
|
||||
case "logout-user":
|
||||
logoutUser(w, r)
|
||||
break
|
||||
}
|
||||
|
||||
break
|
||||
default:
|
||||
http.Error(w, "Method not allowed!", http.StatusMethodNotAllowed)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// change user password and store salted hash in db
|
||||
func changePassword(w http.ResponseWriter, r *http.Request) {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
log.Println("Error parsing form!", err)
|
||||
http.Error(w, "Error parsing form error", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
password := r.FormValue("password")
|
||||
newPassword := r.FormValue("new_password")
|
||||
if password == "" || newPassword == "" || newPassword != r.FormValue("new_password_repeat") {
|
||||
showUserPage(w, r, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
user, err := (*models.User).GetByPersonalNummer(nil, Session.GetInt(r.Context(), "user"))
|
||||
if err != nil {
|
||||
log.Println("Error getting user!", err)
|
||||
showUserPage(w, r, http.StatusBadRequest)
|
||||
}
|
||||
auth, err := user.ChangePass(password, newPassword)
|
||||
if err != nil {
|
||||
log.Println("Error when changing password!", err)
|
||||
}
|
||||
if auth {
|
||||
showUserPage(w, r, http.StatusAccepted)
|
||||
return
|
||||
}
|
||||
showUserPage(w, r, http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
func logoutUser(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
err := Session.Destroy(r.Context())
|
||||
if err != nil {
|
||||
log.Println("Error destroying session!", err)
|
||||
}
|
||||
http.Redirect(w, r, "/user/login", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func showUserPage(w http.ResponseWriter, r *http.Request, status int) {
|
||||
templates.UserPage(status).Render(r.Context(), w)
|
||||
return
|
||||
}
|
||||
@@ -47,8 +47,9 @@ func (b *Booking) FromUrlParams(params url.Values) Booking {
|
||||
return booking
|
||||
}
|
||||
|
||||
func (b Booking) Verify() bool {
|
||||
if b.CardUID == "" || b.GeraetID == 0 || b.CheckInOut == 0 {
|
||||
func (b *Booking) Verify() bool {
|
||||
//check for overlapping time + arbeitszeit verstoß
|
||||
if b.CardUID == "" { //|| b.GeraetID == 0 || b.CheckInOut == 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -71,7 +72,7 @@ func (b *Booking) Insert() error {
|
||||
|
||||
func (b *Booking) InsertTimestamp() error {
|
||||
if b.Timestamp.IsZero() {
|
||||
b.Timestamp = time.Now()
|
||||
return b.Insert()
|
||||
}
|
||||
stmt, err := DB.Prepare((`INSERT INTO anwesenheit (card_uid, geraet_id, check_in_out, timestamp) VALUES ($1, $2, $3, $4) RETURNING counter_id`))
|
||||
if err != nil {
|
||||
@@ -251,7 +252,9 @@ func (b *Booking) UpdateTime(newTime time.Time) {
|
||||
if b.CheckInOut == 254 {
|
||||
newBooking.CheckInOut = 4
|
||||
}
|
||||
log.Println("Updating")
|
||||
b.Update(newBooking)
|
||||
b.Verify()
|
||||
b.Save()
|
||||
}
|
||||
|
||||
|
||||
@@ -13,11 +13,11 @@ import (
|
||||
)
|
||||
|
||||
type User struct {
|
||||
CardUID string `json:"card_uid"`
|
||||
Name string `json:"name"`
|
||||
Vorname string `json:"vorname"`
|
||||
PersonalNummer int `json:"personal_nummer"`
|
||||
Arbeitszeit float32 `json:"arbeitszeit"`
|
||||
CardUID string `json:"card_uid"`
|
||||
Name string `json:"name"`
|
||||
Vorname string `json:"vorname"`
|
||||
PersonalNummer int `json:"personal_nummer"`
|
||||
ArbeitszeitPerTag float32 `json:"arbeitszeit"`
|
||||
}
|
||||
|
||||
func (u *User) GetUserFromSession(Session *scs.SessionManager, ctx context.Context) (User, error) {
|
||||
@@ -83,7 +83,7 @@ func (u *User) CheckAnwesenheit() bool {
|
||||
}
|
||||
|
||||
// Creates a new booking for the user -> check_in_out will be 254 for automatic check out
|
||||
func (u *User) Logout() error {
|
||||
func (u *User) CheckOut() error {
|
||||
booking := (*Booking).New(nil, u.CardUID, 0, 254)
|
||||
err := booking.Insert()
|
||||
if err != nil {
|
||||
@@ -100,7 +100,7 @@ func (u *User) GetByPersonalNummer(personalNummer int) (User, error) {
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
err = qStr.QueryRow(personalNummer).Scan(&user.PersonalNummer, &user.CardUID, &user.Vorname, &user.Name, &user.Arbeitszeit)
|
||||
err = qStr.QueryRow(personalNummer).Scan(&user.PersonalNummer, &user.CardUID, &user.Vorname, &user.Name, &user.ArbeitszeitPerTag)
|
||||
|
||||
if err != nil {
|
||||
return user, err
|
||||
@@ -196,7 +196,7 @@ func (u *User) GetNextWeek() WorkWeek {
|
||||
|
||||
func parseUser(rows *sql.Rows) (User, error) {
|
||||
var user User
|
||||
if err := rows.Scan(&user.PersonalNummer, &user.CardUID, &user.Vorname, &user.Name, &user.Arbeitszeit); err != nil {
|
||||
if err := rows.Scan(&user.PersonalNummer, &user.CardUID, &user.Vorname, &user.Name, &user.ArbeitszeitPerTag); err != nil {
|
||||
log.Println("Error scanning row!", err)
|
||||
return user, err
|
||||
}
|
||||
@@ -228,6 +228,22 @@ func (u *User) GetLastSubmission() time.Time {
|
||||
return lastSub
|
||||
}
|
||||
|
||||
func (u *User) GetFromCardUID(card_uid string) (User, error) {
|
||||
user := User{}
|
||||
var err error
|
||||
|
||||
qStr, err := DB.Prepare((`SELECT personal_nummer, card_uid, vorname, nachname, arbeitszeit_per_tag FROM personal_daten WHERE card_uid = $1;`))
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
err = qStr.QueryRow(card_uid).Scan(&user.PersonalNummer, &user.CardUID, &user.Vorname, &user.Name, &user.ArbeitszeitPerTag)
|
||||
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func getMonday(ts time.Time) time.Time {
|
||||
if ts.Weekday() != time.Monday {
|
||||
if ts.Weekday() == time.Sunday {
|
||||
|
||||
@@ -184,7 +184,7 @@ 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))
|
||||
defaultWorkTime := time.Duration(user.ArbeitszeitPerTag * float32(time.Hour))
|
||||
progress := (d.workTime.Seconds() / defaultWorkTime.Seconds()) * 100
|
||||
return uint8(progress)
|
||||
}
|
||||
|
||||
@@ -60,12 +60,21 @@ templ UserPage(status int) {
|
||||
<p class="text-red-600 text-sm">Aktuelles Passwort nicht korrekt!</p>
|
||||
case status >= 400:
|
||||
<p class="text-red-600 text-sm">Passwortwechsel fehlgeschlagen, bitte erneut versuchen!</p>
|
||||
case status == 200:
|
||||
case status == 202:
|
||||
<p class="text-accent text-sm">Passwortänderung erfolgreich</p>
|
||||
}
|
||||
</div>
|
||||
<div class="grid-cell">
|
||||
<button type="submit" class="w-full cursor-pointer rounded-md text-neutral-800 p-2 md:px-4 border text-center text-sm hover:text-white transition-colors border-neutral-300 focus:bg-neutral-700 active:bg-neutral-700 hover:bg-neutral-700 disabled:pointer-events-none disabled:opacity-50">Ändern</button>
|
||||
<button name="action" value="change-pass" type="submit" class="w-full cursor-pointer rounded-md text-neutral-800 p-2 md:px-4 border text-center text-sm hover:text-white transition-colors border-neutral-300 focus:bg-neutral-700 active:bg-neutral-700 hover:bg-neutral-700 disabled:pointer-events-none disabled:opacity-50">Ändern</button>
|
||||
</div>
|
||||
</form>
|
||||
<form method="POST" class="grid-sub divide-x-1">
|
||||
<h1 class="grid-cell font-bold uppercase text-xl text-center">Nutzer abmelden</h1>
|
||||
<div class="grid-cell col-span-3">
|
||||
<p>Nutzer von Weboberfläche abmelden.</p>
|
||||
</div>
|
||||
<div class="grid-cell">
|
||||
<button name="action" value="logout-user" type="submit" class="w-full cursor-pointer rounded-md text-neutral-800 p-2 md:px-4 border text-center text-sm hover:text-white transition-colors border-neutral-300 focus:bg-neutral-700 active:bg-neutral-700 hover:bg-neutral-700 disabled:pointer-events-none disabled:opacity-50">Abmelden</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -123,18 +132,17 @@ templ TeamPresencePage(teamPresence map[bool][]models.User) {
|
||||
<div class="grid-sub divide-x-1">
|
||||
<h2 class="grid-cell font-bold uppercase">Anwesend</h2>
|
||||
<div class="flex flex-col col-span-2 md:col-span-4">
|
||||
for _, user := range teamPresence[true] {
|
||||
|
||||
@userPresenceComponent(user, true)
|
||||
}
|
||||
for _, user := range teamPresence[true] {
|
||||
@userPresenceComponent(user, true)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid-sub divide-x-1">
|
||||
<h2 class="grid-cell font-bold uppercase">Nicht Anwesend</h2>
|
||||
<div class="flex flex-col col-span-2 md:col-span-4">
|
||||
for _, user := range teamPresence[false] {
|
||||
@userPresenceComponent(user, false)
|
||||
}
|
||||
for _, user := range teamPresence[false] {
|
||||
@userPresenceComponent(user, false)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -186,13 +186,13 @@ func UserPage(status int) templ.Component {
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
case status == 200:
|
||||
case status == 202:
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<p class=\"text-accent text-sm\">Passwortänderung erfolgreich</p>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</div><div class=\"grid-cell\"><button type=\"submit\" class=\"w-full cursor-pointer rounded-md text-neutral-800 p-2 md:px-4 border text-center text-sm hover:text-white transition-colors border-neutral-300 focus:bg-neutral-700 active:bg-neutral-700 hover:bg-neutral-700 disabled:pointer-events-none disabled:opacity-50\">Ändern</button></div></form></div>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</div><div class=\"grid-cell\"><button name=\"action\" value=\"change-pass\" type=\"submit\" class=\"w-full cursor-pointer rounded-md text-neutral-800 p-2 md:px-4 border text-center text-sm hover:text-white transition-colors border-neutral-300 focus:bg-neutral-700 active:bg-neutral-700 hover:bg-neutral-700 disabled:pointer-events-none disabled:opacity-50\">Ändern</button></div></form><form method=\"POST\" class=\"grid-sub divide-x-1\"><h1 class=\"grid-cell font-bold uppercase text-xl text-center\">Nutzer abmelden</h1><div class=\"grid-cell col-span-3\"><p>Nutzer von Weboberfläche abmelden.</p></div><div class=\"grid-cell\"><button name=\"action\" value=\"logout-user\" type=\"submit\" class=\"w-full cursor-pointer rounded-md text-neutral-800 p-2 md:px-4 border text-center text-sm hover:text-white transition-colors border-neutral-300 focus:bg-neutral-700 active:bg-neutral-700 hover:bg-neutral-700 disabled:pointer-events-none disabled:opacity-50\">Abmelden</button></div></form></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
@@ -238,7 +238,7 @@ func TeamPage(weeks []models.WorkWeek, userWeek models.WorkWeek) templ.Component
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%s %s", userWeek.User.Vorname, userWeek.User.Name))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pages.templ`, Line: 82, Col: 111}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pages.templ`, Line: 91, Col: 111}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
@@ -287,7 +287,7 @@ func TeamPage(weeks []models.WorkWeek, userWeek models.WorkWeek) templ.Component
|
||||
var templ_7745c5c3_Var9 string
|
||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(userWeek.WeekStart.Format(time.DateOnly))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pages.templ`, Line: 95, Col: 85}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pages.templ`, Line: 109, Col: 85}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
|
||||
@@ -34,7 +34,7 @@ templ employeComponent(week models.WorkWeek) {
|
||||
{{
|
||||
year, kw := week.WeekStart.ISOWeek()
|
||||
}}
|
||||
<div class="grid-sub divide-x-1">
|
||||
<div class="employeComponent grid-sub divide-x-1">
|
||||
<div class="grid-cell">
|
||||
<p class="font-bold uppercase">{ week.User.Vorname } { week.User.Name }</p>
|
||||
<p class="text-sm">Arbeitszeit</p>
|
||||
@@ -57,13 +57,13 @@ templ employeComponent(week models.WorkWeek) {
|
||||
</div>
|
||||
}
|
||||
|
||||
templ userPresenceComponent(user models.User, present bool){
|
||||
templ userPresenceComponent(user models.User, present bool) {
|
||||
<div class="grid-cell group flex flex-row gap-2">
|
||||
if present {
|
||||
<div class="h-8 bg-accent rounded-md group-hover:text-black md:text-transparent text-center p-1" >Anwesend</div>
|
||||
} else {
|
||||
<div class="h-8 bg-red-600 rounded-md group-hover:text-white md:text-transparent text-center p-1" >Abwesend</div>
|
||||
}
|
||||
<p>{user.Vorname} {user.Name}</p>
|
||||
if present {
|
||||
<div class="h-8 bg-accent rounded-md group-hover:text-black md:text-transparent text-center p-1">Anwesend</div>
|
||||
} else {
|
||||
<div class="h-8 bg-red-600 rounded-md group-hover:text-white md:text-transparent text-center p-1">Abwesend</div>
|
||||
}
|
||||
<p>{ user.Vorname } { user.Name }</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ func employeComponent(week models.WorkWeek) templ.Component {
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
|
||||
year, kw := week.WeekStart.ISOWeek()
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<div class=\"grid-sub divide-x-1\"><div class=\"grid-cell\"><p class=\"font-bold uppercase\">")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<div class=\"employeComponent grid-sub divide-x-1\"><div class=\"grid-cell\"><p class=\"font-bold uppercase\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
@@ -293,7 +293,7 @@ func userPresenceComponent(user models.User, present bool) templ.Component {
|
||||
var templ_7745c5c3_Var16 string
|
||||
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(user.Vorname)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/teamComponents.templ`, Line: 67, Col: 17}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/teamComponents.templ`, Line: 67, Col: 19}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
@@ -306,7 +306,7 @@ func userPresenceComponent(user models.User, present bool) templ.Component {
|
||||
var templ_7745c5c3_Var17 string
|
||||
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(user.Name)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/teamComponents.templ`, Line: 67, Col: 29}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/teamComponents.templ`, Line: 67, Col: 33}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
|
||||
Reference in New Issue
Block a user