Compare commits
5 Commits
db507259c7
...
3be2a47c56
| Author | SHA1 | Date | |
|---|---|---|---|
| 3be2a47c56 | |||
| f6e77bda66 | |||
| 5fb6254c04 | |||
| f2a5e9874d | |||
| 32a4f5277a |
@@ -1,12 +1,21 @@
|
|||||||
FROM golang:alpine
|
# syntax=docker/dockerfile:1
|
||||||
|
FROM --platform=$BUILDPLATFORM golang:alpine AS build
|
||||||
|
ARG TARGETOS
|
||||||
|
ARG TARGETARCH
|
||||||
|
ENV CGO_ENABLED=0 \
|
||||||
|
GOOS=$TARGETOS \
|
||||||
|
GOARCH=$TARGETARCH
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY go.mod go.sum /app/
|
COPY go.mod go.sum /app/
|
||||||
|
|
||||||
RUN go mod download && go mod verify
|
RUN go mod download && go mod verify
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN go build -o /usr/local/bin/app
|
RUN go build -o server .
|
||||||
|
|
||||||
CMD ["app"]
|
FROM alpine
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=build /app/server /app/server
|
||||||
|
|
||||||
|
COPY /static /app/static
|
||||||
|
ENTRYPOINT ["./server"]
|
||||||
|
|||||||
@@ -43,14 +43,19 @@ func parseTimestamp(r *http.Request , get_key string, fallback string) (time.Tim
|
|||||||
|
|
||||||
// Returns bookings from DB with similar card uid -> checks for card uid in http query params
|
// Returns bookings from DB with similar card uid -> checks for card uid in http query params
|
||||||
func getBookings(w http.ResponseWriter, r *http.Request) {
|
func getBookings(w http.ResponseWriter, r *http.Request) {
|
||||||
// if(!Session.Exists(r.Context(), "user")){
|
var user models.User
|
||||||
// log.Println("No user in session storage!")
|
var err error
|
||||||
// http.Error(w, "Not logged in!", http.StatusForbidden)
|
if(helper.GetEnv("GO_ENV", "production") == "debug"){
|
||||||
// return
|
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"))
|
user, err = (*models.User).GetByPersonalNummer(nil, Session.GetInt(r.Context(), "user"))
|
||||||
user, err := (*models.User).GetByPersonalNummer(nil, 123)
|
}
|
||||||
if(err != nil){
|
if(err != nil){
|
||||||
log.Println("No user found with the given personal number!")
|
log.Println("No user found with the given personal number!")
|
||||||
http.Error(w, "No user found", http.StatusNotFound)
|
http.Error(w, "No user found", http.StatusNotFound)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"arbeitszeitmessung/templates"
|
"arbeitszeitmessung/templates"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/alexedwards/scs/v2"
|
"github.com/alexedwards/scs/v2"
|
||||||
@@ -20,18 +21,18 @@ func CreateSessionManager(lifetime time.Duration) *scs.SessionManager {
|
|||||||
|
|
||||||
func LoginHandler(w http.ResponseWriter, r *http.Request){
|
func LoginHandler(w http.ResponseWriter, r *http.Request){
|
||||||
switch r.Method{
|
switch r.Method{
|
||||||
case http.MethodGet: showForm(w, r)
|
case http.MethodGet: showForm(w, r, false)
|
||||||
break
|
break
|
||||||
case http.MethodPost: loginUser(w, r)
|
case http.MethodPost: loginUser(w, r)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
showForm(w, r)
|
showForm(w, r, false)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func showForm(w http.ResponseWriter, r *http.Request){
|
func showForm(w http.ResponseWriter, r *http.Request, failed bool){
|
||||||
templates.LoginForm().Render(r.Context(), w)
|
templates.LoginForm(failed).Render(r.Context(), w)
|
||||||
}
|
}
|
||||||
|
|
||||||
func loginUser(w http.ResponseWriter, r *http.Request){
|
func loginUser(w http.ResponseWriter, r *http.Request){
|
||||||
@@ -39,15 +40,24 @@ func loginUser(w http.ResponseWriter, r *http.Request){
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error parsing form!", err)
|
log.Println("Error parsing form!", err)
|
||||||
http.Error(w, "Internal error", http.StatusBadRequest)
|
http.Error(w, "Internal error", http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
card_uid := r.FormValue("card_uid")
|
_personal_nummer := r.FormValue("personal_nummer")
|
||||||
if(card_uid == ""){
|
if(_personal_nummer == ""){
|
||||||
log.Println("No card_uid provided!")
|
log.Println("No personal_nummer provided!")
|
||||||
http.Error(w, "No card_uid provided", http.StatusBadRequest)
|
http.Error(w, "No personal_nummer provided", http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
user, err := (*models.User).GetByCardUID(nil, card_uid)
|
personal_nummer, err := strconv.Atoi(_personal_nummer)
|
||||||
if(err != nil){
|
if(err != nil){
|
||||||
log.Println("No user found under this card_uid!")
|
log.Println("Cannot parse personal nubmer!")
|
||||||
|
http.Error(w, "Cannot parse number", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := (*models.User).GetByPersonalNummer(nil, personal_nummer)
|
||||||
|
if(err != nil){
|
||||||
|
log.Println("No user found under this personal number!")
|
||||||
http.Error(w, "No user found!", http.StatusNotFound)
|
http.Error(w, "No user found!", http.StatusNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +66,9 @@ func loginUser(w http.ResponseWriter, r *http.Request){
|
|||||||
log.Printf("New succesfull user login from %s %s!\n", user.Vorname, user.Name)
|
log.Printf("New succesfull user login from %s %s!\n", user.Vorname, user.Name)
|
||||||
Session.Put(r.Context(), "user", user.PersonalNummer)
|
Session.Put(r.Context(), "user", user.PersonalNummer)
|
||||||
http.Redirect(w, r, "/time", http.StatusSeeOther) //with this browser always uses GET
|
http.Redirect(w, r, "/time", http.StatusSeeOther) //with this browser always uses GET
|
||||||
|
}else{
|
||||||
|
showForm(w, r, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
showForm(w, r)
|
showForm(w, r, false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,4 +8,6 @@ require github.com/lib/pq v1.10.9
|
|||||||
|
|
||||||
require github.com/a-h/templ v0.3.833
|
require github.com/a-h/templ v0.3.833
|
||||||
|
|
||||||
require github.com/alexedwards/scs/v2 v2.8.0 // indirect
|
require github.com/alexedwards/scs/v2 v2.8.0
|
||||||
|
|
||||||
|
require github.com/joho/godotenv v1.5.1
|
||||||
|
|||||||
@@ -4,5 +4,7 @@ github.com/alexedwards/scs/v2 v2.8.0 h1:h31yUYoycPuL0zt14c0gd+oqxfRwIj6SOjHdKRZx
|
|||||||
github.com/alexedwards/scs/v2 v2.8.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8=
|
github.com/alexedwards/scs/v2 v2.8.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/joho/godotenv"
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,6 +18,12 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
err = godotenv.Load(".env")
|
||||||
|
if err != nil {
|
||||||
|
log.Println("No .env file found in directory!")
|
||||||
|
}
|
||||||
|
|
||||||
models.DB, err = OpenDatabase()
|
models.DB, err = OpenDatabase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
|||||||
@@ -9,12 +9,11 @@ type User struct {
|
|||||||
CardUID string `json:"card_uid"`
|
CardUID string `json:"card_uid"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Vorname string `json:"vorname"`
|
Vorname string `json:"vorname"`
|
||||||
HauptbeschaeftigungsOrt int8 `json:"hauptbeschaeftigungsort"`
|
|
||||||
PersonalNummer int `json:"personal_nummer"`
|
PersonalNummer int `json:"personal_nummer"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) GetAll() ([]User, error) {
|
func (u *User) GetAll() ([]User, error) {
|
||||||
qStr, err := DB.Prepare((`SELECT card_uid, vorname, nachname, hauptbeschaeftigung_ort FROM personal_daten;`))
|
qStr, err := DB.Prepare((`SELECT card_uid, vorname, nachname FROM personal_daten;`))
|
||||||
var users []User
|
var users []User
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error preparing query statement %v\n", err)
|
fmt.Printf("Error preparing query statement %v\n", err)
|
||||||
@@ -28,7 +27,7 @@ func (u *User) GetAll() ([]User, error) {
|
|||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var user User
|
var user User
|
||||||
if err := rows.Scan(&user.CardUID, &user.Vorname, &user.Name, &user.HauptbeschaeftigungsOrt); err != nil {
|
if err := rows.Scan(&user.CardUID, &user.Vorname, &user.Name); err != nil {
|
||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
users = append(users, user)
|
users = append(users, user)
|
||||||
@@ -69,11 +68,11 @@ func (u *User) Logout() error {
|
|||||||
|
|
||||||
func (u *User) GetByCardUID(card_uid string) (User, error) {
|
func (u *User) GetByCardUID(card_uid string) (User, error) {
|
||||||
var user User
|
var user User
|
||||||
qStr, err := DB.Prepare((`SELECT personal_nummer, card_uid, vorname, nachname, hauptbeschaeftigung_ort FROM personal_daten WHERE card_uid = $1;`))
|
qStr, err := DB.Prepare((`SELECT personal_nummer, card_uid, vorname, nachname FROM personal_daten WHERE card_uid = $1;`))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
err = qStr.QueryRow(card_uid).Scan(&user.PersonalNummer, &user.CardUID, &user.Vorname, &user.Name, &user.HauptbeschaeftigungsOrt)
|
err = qStr.QueryRow(card_uid).Scan(&user.PersonalNummer, &user.CardUID, &user.Vorname, &user.Name)
|
||||||
if err != nil{
|
if err != nil{
|
||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
@@ -83,11 +82,11 @@ func (u *User) GetByCardUID(card_uid string) (User, error) {
|
|||||||
func (u *User) GetByPersonalNummer (personalNummer int) (User, error) {
|
func (u *User) GetByPersonalNummer (personalNummer int) (User, error) {
|
||||||
var user User
|
var user User
|
||||||
|
|
||||||
qStr, err := DB.Prepare((`SELECT personal_nummer, card_uid, vorname, nachname, hauptbeschaeftigung_ort FROM personal_daten WHERE personal_nummer = $1;`))
|
qStr, err := DB.Prepare((`SELECT personal_nummer, card_uid, vorname, nachname FROM personal_daten WHERE personal_nummer = $1;`))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
err = qStr.QueryRow(personalNummer).Scan(&user.PersonalNummer, &user.CardUID, &user.Vorname, &user.Name, &user.HauptbeschaeftigungsOrt)
|
err = qStr.QueryRow(personalNummer).Scan(&user.PersonalNummer, &user.CardUID, &user.Vorname, &user.Name)
|
||||||
if err != nil{
|
if err != nil{
|
||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -600,9 +600,21 @@
|
|||||||
.h-4 {
|
.h-4 {
|
||||||
height: calc(var(--spacing) * 4);
|
height: calc(var(--spacing) * 4);
|
||||||
}
|
}
|
||||||
|
.h-\[90vh\] {
|
||||||
|
height: 90vh;
|
||||||
|
}
|
||||||
|
.h-\[100vh\] {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
.h-full {
|
.h-full {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
.w-1 {
|
||||||
|
width: calc(var(--spacing) * 1);
|
||||||
|
}
|
||||||
|
.w-1\/2 {
|
||||||
|
width: calc(1/2 * 100%);
|
||||||
|
}
|
||||||
.w-2 {
|
.w-2 {
|
||||||
width: calc(var(--spacing) * 2);
|
width: calc(var(--spacing) * 2);
|
||||||
}
|
}
|
||||||
@@ -702,18 +714,24 @@
|
|||||||
.border-neutral-200 {
|
.border-neutral-200 {
|
||||||
border-color: var(--color-neutral-200);
|
border-color: var(--color-neutral-200);
|
||||||
}
|
}
|
||||||
|
.border-neutral-300 {
|
||||||
|
border-color: var(--color-neutral-300);
|
||||||
|
}
|
||||||
|
.border-neutral-400 {
|
||||||
|
border-color: var(--color-neutral-400);
|
||||||
|
}
|
||||||
.border-neutral-900 {
|
.border-neutral-900 {
|
||||||
border-color: var(--color-neutral-900);
|
border-color: var(--color-neutral-900);
|
||||||
}
|
}
|
||||||
|
.border-red-600 {
|
||||||
|
border-color: var(--color-red-600);
|
||||||
|
}
|
||||||
.bg-accent {
|
.bg-accent {
|
||||||
background-color: var(--color-accent);
|
background-color: var(--color-accent);
|
||||||
}
|
}
|
||||||
.bg-neutral-100 {
|
.bg-neutral-100 {
|
||||||
background-color: var(--color-neutral-100);
|
background-color: var(--color-neutral-100);
|
||||||
}
|
}
|
||||||
.bg-neutral-200 {
|
|
||||||
background-color: var(--color-neutral-200);
|
|
||||||
}
|
|
||||||
.bg-neutral-300 {
|
.bg-neutral-300 {
|
||||||
background-color: var(--color-neutral-300);
|
background-color: var(--color-neutral-300);
|
||||||
}
|
}
|
||||||
@@ -726,6 +744,9 @@
|
|||||||
.bg-purple-600 {
|
.bg-purple-600 {
|
||||||
background-color: var(--color-purple-600);
|
background-color: var(--color-purple-600);
|
||||||
}
|
}
|
||||||
|
.bg-red-200 {
|
||||||
|
background-color: var(--color-red-200);
|
||||||
|
}
|
||||||
.bg-red-600 {
|
.bg-red-600 {
|
||||||
background-color: var(--color-red-600);
|
background-color: var(--color-red-600);
|
||||||
}
|
}
|
||||||
@@ -745,6 +766,10 @@
|
|||||||
font-size: var(--text-sm);
|
font-size: var(--text-sm);
|
||||||
line-height: var(--tw-leading, var(--text-sm--line-height));
|
line-height: var(--tw-leading, var(--text-sm--line-height));
|
||||||
}
|
}
|
||||||
|
.text-xs {
|
||||||
|
font-size: var(--text-xs);
|
||||||
|
line-height: var(--tw-leading, var(--text-xs--line-height));
|
||||||
|
}
|
||||||
.font-bold {
|
.font-bold {
|
||||||
--tw-font-weight: var(--font-weight-bold);
|
--tw-font-weight: var(--font-weight-bold);
|
||||||
font-weight: var(--font-weight-bold);
|
font-weight: var(--font-weight-bold);
|
||||||
@@ -817,6 +842,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.hover\:border-neutral-500 {
|
||||||
|
&:hover {
|
||||||
|
@media (hover: hover) {
|
||||||
|
border-color: var(--color-neutral-500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.hover\:bg-neutral-200 {
|
.hover\:bg-neutral-200 {
|
||||||
&:hover {
|
&:hover {
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
@@ -824,13 +856,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.hover\:bg-neutral-300 {
|
|
||||||
&:hover {
|
|
||||||
@media (hover: hover) {
|
|
||||||
background-color: var(--color-neutral-300);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.hover\:bg-neutral-700 {
|
.hover\:bg-neutral-700 {
|
||||||
&:hover {
|
&:hover {
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
|
|||||||
@@ -1,10 +1,22 @@
|
|||||||
package templates
|
package templates
|
||||||
|
|
||||||
templ LoginForm(){
|
templ LoginForm(failed bool){
|
||||||
@Style()
|
{{
|
||||||
<form method="POST">
|
failedClass := ""
|
||||||
<input name="card_uid" type="text" placeholder="card_uid"/>
|
if(failed){
|
||||||
<input name="password" type="passwort" placeholder="password"/>
|
failedClass = "border border-red-600"
|
||||||
<button type="submit">Send</button>
|
}
|
||||||
</form>
|
}}
|
||||||
|
@Style()
|
||||||
|
<div class="w-full h-[100vh] flex flex-col justify-center items-center">
|
||||||
|
|
||||||
|
<form method="POST" class={"w-1/2 flex flex-col gap-4 p-2", failedClass}>
|
||||||
|
<input name="personal_nummer" placeholder="Personalnummer" type="text" class="w-full placeholder:text-neutral-400 text-neutral-700 text-sm border border-neutral-300 rounded-md px-3 py-2 transition duration-300 ease focus:outline-none hover:border-neutral-500"/>
|
||||||
|
<input name="password" placeholder="Passwort" type="password" class="w-full placeholder:text-neutral-400 text-neutral-700 text-sm border border-neutral-300 rounded-md px-3 py-2 transition duration-300 ease focus:outline-none hover:border-neutral-500"/>
|
||||||
|
if failed {
|
||||||
|
<p class="text-red-600 text-sm" >Login fehlgeschlagen, bitte erneut versuchen!</p>
|
||||||
|
}
|
||||||
|
<button type="submit" class="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">Login</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ package templates
|
|||||||
import "github.com/a-h/templ"
|
import "github.com/a-h/templ"
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
func LoginForm() templ.Component {
|
func LoginForm(failed bool) templ.Component {
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
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
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
@@ -29,11 +29,48 @@ func LoginForm() templ.Component {
|
|||||||
templ_7745c5c3_Var1 = templ.NopComponent
|
templ_7745c5c3_Var1 = templ.NopComponent
|
||||||
}
|
}
|
||||||
ctx = templ.ClearChildren(ctx)
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
|
||||||
|
failedClass := ""
|
||||||
|
if failed {
|
||||||
|
failedClass = "border border-red-600"
|
||||||
|
}
|
||||||
templ_7745c5c3_Err = Style().Render(ctx, templ_7745c5c3_Buffer)
|
templ_7745c5c3_Err = Style().Render(ctx, templ_7745c5c3_Buffer)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<form method=\"POST\"><input name=\"card_uid\" type=\"text\" placeholder=\"card_uid\"> <input name=\"password\" type=\"passwort\" placeholder=\"password\"> <button type=\"submit\">Send</button></form>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"w-full h-[100vh] flex flex-col justify-center items-center\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var2 = []any{"w-1/2 flex flex-col gap-4 p-2", failedClass}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<form method=\"POST\" class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var3 string
|
||||||
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var2).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/user.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, 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, 3, "\"><input name=\"personal_nummer\" placeholder=\"Personalnummer\" type=\"text\" class=\"w-full placeholder:text-neutral-400 text-neutral-700 text-sm border border-neutral-300 rounded-md px-3 py-2 transition duration-300 ease focus:outline-none hover:border-neutral-500\"> <input name=\"password\" placeholder=\"Passwort\" type=\"password\" class=\"w-full placeholder:text-neutral-400 text-neutral-700 text-sm border border-neutral-300 rounded-md px-3 py-2 transition duration-300 ease focus:outline-none hover:border-neutral-500\"> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if failed {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<p class=\"text-red-600 text-sm\">Login fehlgeschlagen, bitte erneut versuchen!</p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<button type=\"submit\" class=\"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\">Login</button></form></div>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
|
|||||||
40
DB/initdb/01_create_tables.sql
Normal file
40
DB/initdb/01_create_tables.sql
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for anwesenheit
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS "anwesenheit";
|
||||||
|
CREATE TABLE "anwesenheit" (
|
||||||
|
"counter_id" bigserial PRIMARY KEY,
|
||||||
|
"timestamp" timestamp(6) DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"card_uid" varchar(255),
|
||||||
|
"check_in_out" int2,
|
||||||
|
"geraet_id" int2
|
||||||
|
);
|
||||||
|
COMMENT ON COLUMN "anwesenheit"."check_in_out" IS '1=Check In 2=Check Out , 3=Check in Manuell, 4=Check out manuell255=Automatic Check Out';
|
||||||
|
COMMENT ON COLUMN "anwesenheit"."geraet_id" IS 'ID des Lesegerätes';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for personal_daten
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS "personal_daten";
|
||||||
|
CREATE TABLE "personal_daten" (
|
||||||
|
"personal_nummer" int4 NOT NULL PRIMARY KEY,
|
||||||
|
"aktiv_beschaeftigt" bool,
|
||||||
|
"vorname" varchar(255),
|
||||||
|
"nachname" varchar(255),
|
||||||
|
"geburtsdatum" date,
|
||||||
|
"plz" varchar(255),
|
||||||
|
"adresse" varchar(255),
|
||||||
|
"geschlecht" int2,
|
||||||
|
"card_uid" varchar(255),
|
||||||
|
"hauptbeschaeftigungs_ort" int2,
|
||||||
|
"arbeitszeit_per_tag" float4,
|
||||||
|
"arbeitszeit_min_start" time(6),
|
||||||
|
"arbeitszeit_max_ende" time(6),
|
||||||
|
"vorgesetzter_pers_nr" int4
|
||||||
|
);
|
||||||
|
COMMENT ON COLUMN "personal_daten"."geschlecht" IS '1==weiblich, 2==maennlich, 3==divers';
|
||||||
|
|
||||||
|
-- Insert into personal_daten
|
||||||
|
|
||||||
|
INSERT INTO "personal_daten" ("personal_nummer", "aktiv_beschaeftigt", "vorname", "nachname", "geburtsdatum", "plz", "adresse", "geschlecht", "card_uid", "hauptbeschaeftigungs_ort", "arbeitszeit_per_tag", "arbeitszeit_min_start", "arbeitszeit_max_ende", "vorgesetzter_pers_nr") VALUES
|
||||||
|
(123, 't', 'Max', 'Mustermann', '2003-02-01', '08963', 'Altenburger Str. 44A', 1, 'acde-edca', 1, 7.5, '07:00:00', '20:00:00', 0);
|
||||||
14
DB/initdb/02_create_user.sh
Normal file
14
DB/initdb/02_create_user.sh
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e # Exit on error
|
||||||
|
|
||||||
|
echo "Creating PostgreSQL user and setting permissions... $POSTGRES_USER for API user $POSTGRES_API_USER"
|
||||||
|
|
||||||
|
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||||
|
CREATE USER $POSTGRES_API_USER WITH ENCRYPTED PASSWORD '$POSTGRES_API_PASSWORD';
|
||||||
|
GRANT CONNECT ON DATABASE $POSTGRES_DB TO $POSTGRES_API_USER;
|
||||||
|
GRANT USAGE ON SCHEMA public TO $POSTGRES_API_USER;
|
||||||
|
GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA public TO $POSTGRES_API_USER;
|
||||||
|
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO $POSTGRES_API_USER;
|
||||||
|
EOSQL
|
||||||
|
|
||||||
|
echo "User creation and permissions setup complete!"
|
||||||
@@ -6,12 +6,10 @@ services:
|
|||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: ${POSTGRES_ADMIN}
|
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_ADMIN_PASS}
|
|
||||||
POSTGRES_DB: ${POSTGRES_DB}
|
|
||||||
PGDATA: /var/lib/postgresql/data/pg_data
|
PGDATA: /var/lib/postgresql/data/pg_data
|
||||||
volumes:
|
volumes:
|
||||||
- ${POSTGRES_PATH}:/var/lib/postgresql/data
|
- ${POSTGRES_PATH}:/var/lib/postgresql/data
|
||||||
|
- ${POSTGRES_PATH}/initdb:/docker-entrypoint-initdb.d
|
||||||
ports:
|
ports:
|
||||||
- 5432:5432
|
- 5432:5432
|
||||||
|
|
||||||
@@ -28,8 +26,8 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
POSTGRES_HOST: db
|
POSTGRES_HOST: db
|
||||||
POSTGRES_DB: ${POSTGRES_DB}
|
POSTGRES_DB: ${POSTGRES_DB}
|
||||||
POSTGRES_USER: ${POSTGRES_USER}
|
POSTGRES_USER: ${POSTGRES_API_USER}
|
||||||
POSTGRES_PASS: ${POSTGRES_PASSWORD}
|
POSTGRES_PASS: ${POSTGRES_API_PASSWORD}
|
||||||
EXPOSED_PORT: ${EXPOSED_PORT}
|
EXPOSED_PORT: ${EXPOSED_PORT}
|
||||||
DEBUG: true
|
DEBUG: true
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ services:
|
|||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: ${POSTGRES_ADMIN}
|
POSTGRES_USER: ${POSTGRES_USER}
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_ADMIN_PASS}
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
POSTGRES_DB: ${POSTGRES_DB}
|
POSTGRES_DB: ${POSTGRES_DB}
|
||||||
PGDATA: /var/lib/postgresql/data/pg_data
|
PGDATA: /var/lib/postgresql/data/pg_data
|
||||||
volumes:
|
volumes:
|
||||||
@@ -21,8 +21,8 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
POSTGRES_HOST: db
|
POSTGRES_HOST: db
|
||||||
POSTGRES_DB: ${POSTGRES_DB}
|
POSTGRES_DB: ${POSTGRES_DB}
|
||||||
POSTGRES_USER: ${POSTGRES_USER}
|
POSTGRES_USER: ${POSTGRES_API_USER}
|
||||||
POSTGRES_PASS: ${POSTGRES_PASSWORD}
|
POSTGRES_PASS: ${POSTGRES_API_PASSWORD}
|
||||||
EXPOSED_PORT: ${EXPOSED_PORT}
|
EXPOSED_PORT: ${EXPOSED_PORT}
|
||||||
ports:
|
ports:
|
||||||
- ${EXPOSED_PORT}:8080
|
- ${EXPOSED_PORT}:8080
|
||||||
|
|||||||
17
Jenkinsfile
vendored
17
Jenkinsfile
vendored
@@ -16,22 +16,9 @@ pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
sh 'make build_backend'
|
sh 'make backend'
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
stage('Deploying image arbeitszeit-backend') {
|
|
||||||
when {
|
|
||||||
anyOf{
|
|
||||||
changeset 'Jenkinsfile'
|
|
||||||
changeset 'Makefile'
|
|
||||||
changeset 'Backend/**'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'make push_backend'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
4
Makefile
4
Makefile
@@ -36,3 +36,7 @@ push_%:
|
|||||||
full_%:
|
full_%:
|
||||||
make build_$*
|
make build_$*
|
||||||
make push_$*
|
make push_$*
|
||||||
|
|
||||||
|
backend: login_registry
|
||||||
|
docker buildx build --platform linux/amd64,linux/arm64 -t git.letsstein.de/tom/arbeitszeit-backend:latest Backend --push
|
||||||
|
docker buildx build --platform linux/amd64,linux/arm64 -t git.letsstein.de/tom/arbeitszeit-backend:${GIT_COMMIT} Backend --push
|
||||||
|
|||||||
6
db.sql
6
db.sql
@@ -8,6 +8,7 @@ CREATE TABLE "public"."anwesenheit" (
|
|||||||
);
|
);
|
||||||
COMMENT ON COLUMN "public"."anwesenheit"."check_in_out" IS '1=Check In 2=Check Out 255=Automatic Check Out';
|
COMMENT ON COLUMN "public"."anwesenheit"."check_in_out" IS '1=Check In 2=Check Out 255=Automatic Check Out';
|
||||||
COMMENT ON COLUMN "public"."anwesenheit"."geraet_id" IS 'ID des Lesegerätes';
|
COMMENT ON COLUMN "public"."anwesenheit"."geraet_id" IS 'ID des Lesegerätes';
|
||||||
|
|
||||||
-- @block create table personaldaten
|
-- @block create table personaldaten
|
||||||
CREATE TABLE "public"."personal_daten" (
|
CREATE TABLE "public"."personal_daten" (
|
||||||
"personal_nummer" SERIAL PRIMARY KEY,
|
"personal_nummer" SERIAL PRIMARY KEY,
|
||||||
@@ -25,9 +26,13 @@ COMMENT ON COLUMN "public"."personal_daten"."akiv_beschaeftig" IS 'derzeit aktiv
|
|||||||
COMMENT ON COLUMN "public"."personal_daten"."geschlecht" IS 'w:1 m:2 div:3 kA:null ';
|
COMMENT ON COLUMN "public"."personal_daten"."geschlecht" IS 'w:1 m:2 div:3 kA:null ';
|
||||||
COMMENT ON COLUMN "public"."personal_daten"."card_uid" IS 'RFID-Karten-UID';
|
COMMENT ON COLUMN "public"."personal_daten"."card_uid" IS 'RFID-Karten-UID';
|
||||||
COMMENT ON COLUMN "public"."personal_daten"."hauptbeschaeftigung_ort" IS 'Chemnitz:1 Sayda:2';
|
COMMENT ON COLUMN "public"."personal_daten"."hauptbeschaeftigung_ort" IS 'Chemnitz:1 Sayda:2';
|
||||||
|
|
||||||
|
|
||||||
-- @block drop tables
|
-- @block drop tables
|
||||||
DROP TABLE IF EXISTS "public"."anwesenheit";
|
DROP TABLE IF EXISTS "public"."anwesenheit";
|
||||||
DROP TABLE IF EXISTS "public"."personal_daten";
|
DROP TABLE IF EXISTS "public"."personal_daten";
|
||||||
|
|
||||||
|
|
||||||
-- @block insert into personal_daten
|
-- @block insert into personal_daten
|
||||||
INSERT INTO personal_daten (
|
INSERT INTO personal_daten (
|
||||||
personal_nummer,
|
personal_nummer,
|
||||||
@@ -53,6 +58,7 @@ VALUES (
|
|||||||
'test_card',
|
'test_card',
|
||||||
'1'
|
'1'
|
||||||
);
|
);
|
||||||
|
|
||||||
-- @block select
|
-- @block select
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM personal_daten;
|
FROM personal_daten;
|
||||||
|
|||||||
Reference in New Issue
Block a user