package endpoints import ( "arbeitszeitmessung/helper" "arbeitszeitmessung/models" "arbeitszeitmessung/templates" "context" "encoding/json" "log" "net/http" "sort" "strconv" "time" ) // Frontend relevant backend functionality -> not used by the arduino devices func TimeHandler(w http.ResponseWriter, r *http.Request) { helper.RequiresLogin(Session, w, r) helper.SetCors(w) switch r.Method { case http.MethodGet: getBookings(w, r) break case http.MethodPost: updateBooking(w, r) break case http.MethodOptions: // just support options header for non GET Requests from SWAGGER w.WriteHeader(http.StatusOK) break default: http.Error(w, "Method not allowed!", http.StatusMethodNotAllowed) break } } func parseTimestamp(r *http.Request, getKey string, fallback string) (time.Time, error) { getTimestamp := r.URL.Query().Get(getKey) if getTimestamp == "" { getTimestamp = fallback } Timestamp, err := time.Parse("2006-01-02", getTimestamp) if err != nil { return time.Now(), err } return Timestamp, nil } // Returns bookings from DB with similar card uid -> checks for card uid in http query params func getBookings(w http.ResponseWriter, r *http.Request) { user, err := (*models.User).GetUserFromSession(nil, Session, r.Context()) if err != nil { log.Println("No user found with the given personal number!") http.Redirect(w, r, "/user/login", http.StatusSeeOther) return } // TODO add config for timeoffset tsFrom, err := parseTimestamp(r, "time_from", time.Now().AddDate(0, -1, 0).Format("2006-01-02")) if err != nil { log.Println("Error parsing 'from' time", err) http.Error(w, "Timestamp 'from' cannot be parsed!", http.StatusBadRequest) return } tsTo, err := parseTimestamp(r, "time_to", time.Now().Format("2006-01-02")) if err != nil { log.Println("Error parsing 'to' time", err) http.Error(w, "Timestamp 'to' cannot be parsed!", http.StatusBadRequest) return } tsTo = tsTo.AddDate(0, 0, 1) // so that today is inside workDays := (*models.WorkDay).GetWorkDays(nil, user.CardUID, tsFrom, tsTo) sort.Slice(workDays, func(i, j int) bool { return workDays[i].Day.After(workDays[j].Day) }) if r.Header.Get("Accept") == "application/json" { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(workDays) return } ctx := context.WithValue(r.Context(), "user", user) templates.TimePage(workDays).Render(ctx, w) } func updateBooking(w http.ResponseWriter, r *http.Request) { r.ParseForm() var loc *time.Location loc, err := time.LoadLocation(helper.GetEnv("TZ", "Europe/Berlin")) if err != nil { log.Println("Error loading location", err) loc = time.Local } user, err := (*models.User).GetUserFromSession(nil, Session, r.Context()) if err != nil { log.Println("No user found!", err) return } switch r.FormValue("action") { case "add": timestamp, err := time.ParseInLocation("2006-01-02|15:04", r.FormValue("date")+"|"+r.FormValue("timestamp"), loc) if err != nil { log.Println("Error parsing timestamp", err) return } var check_in_out int check_in_out, err = strconv.Atoi(r.FormValue("check_in_out")) if err != nil { log.Println("Error parsing check_in_out", err) return } newBooking := (*models.Booking).New(nil, user.CardUID, 0, int16(check_in_out)) newBooking.Timestamp = timestamp err = newBooking.InsertWithTimestamp() if err != nil { log.Println("Error inserting booking", err) } break case "change": absenceType, err := strconv.Atoi(r.FormValue("absence")) if err != nil { log.Println("Error parsing absence type.", err) absenceType = 0 } if absenceType != 0 { createAbsence(absenceType, user, loc, r) } for index, possibleBooking := range r.PostForm { if len(index) > 7 && index[:7] == "booking" { booking_id, err := strconv.Atoi(index[8:]) if err != nil { log.Println("Error parsing bookingId", err) continue } booking, err := (*models.Booking).GetBookingById(nil, booking_id) if err != nil { log.Println("Error getting booking!", err) continue } parsedTime, err := time.ParseInLocation("15:04", possibleBooking[0], booking.Timestamp.Location()) if err != nil { log.Println("Error parsing time!", err) continue } // log.Println("Parsing time", parsedTime) booking.UpdateTime(parsedTime) } } break } getBookings(w, r) } func createAbsence(absenceType int, user models.User, loc *time.Location, r *http.Request) { absenceDate, err := time.ParseInLocation("2006-01-02", r.FormValue("date"), loc) if err != nil { log.Println("Cannot get date from input! Skipping absence creation", err) return } absence := models.NewAbsence(user.CardUID, int8(absenceType), absenceDate) err = absence.Insert() if err != nil { log.Println("Error inserting absence!", err) return } } func getBookingsAPI(w http.ResponseWriter, r *http.Request) { _user_pn := r.URL.Query().Get("personal_nummer") user_pn, err := strconv.Atoi(_user_pn) if err != nil { log.Println("No personal numver found!") http.Error(w, "No personal number found", http.StatusBadRequest) return } user, err := (*models.User).GetByPersonalNummer(nil, user_pn) if err != nil { log.Println("No user found with the given personal number!") http.Error(w, "No user found", http.StatusNotFound) return } // TODO add config for timeoffset tsFrom, err := parseTimestamp(r, "time_from", time.Now().AddDate(0, -1, 0).Format("2006-01-02")) if err != nil { log.Println("Error parsing 'from' time", err) http.Error(w, "Timestamp 'from' cannot be parsed!", http.StatusBadRequest) return } tsTo, err := parseTimestamp(r, "time_to", time.Now().Format("2006-01-02")) if err != nil { log.Println("Error parsing 'to' time", err) http.Error(w, "Timestamp 'to' cannot be parsed!", http.StatusBadRequest) return } tsTo = tsTo.AddDate(0, 0, 1) // so that today is inside bookings, err := (*models.Booking).GetBookingsGrouped(nil, user.CardUID, tsFrom, tsTo) if err != nil { log.Println("Error getting bookings: ", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(bookings) } // Updates a booking form the given json body func updateBookingAPI(w http.ResponseWriter, r *http.Request) { _booking_id := r.URL.Query().Get("counter_id") if _booking_id == "" { http.Error(w, "Missing bookingID query parameter", http.StatusBadRequest) return } booking_id, err := strconv.Atoi(_booking_id) if err != nil { http.Error(w, "Invalid bookingID query parameter", http.StatusBadRequest) return } bookingDB, err := (*models.Booking).GetBookingById(nil, booking_id) if err != nil { log.Println("Error getting booking: ", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } var booking models.Booking dec := json.NewDecoder(r.Body) dec.DisallowUnknownFields() err = dec.Decode(&booking) if err != nil { log.Println("Error parsing booking: ", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } if booking.CounterId != 0 && booking.CounterId != bookingDB.CounterId { log.Println("Booking Ids do not match") http.Error(w, "Booking Ids do not match", http.StatusBadRequest) return } bookingDB.Update(booking) bookingDB.Save() w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(bookingDB) }