Updates und Bugfixes

This commit is contained in:
jbergner
2025-06-12 16:04:05 +02:00
parent a93e34a9f5
commit 8b6da48e8c
4 changed files with 147 additions and 33 deletions

158
main.go
View File

@@ -15,6 +15,7 @@ import (
"os/signal"
"strconv"
"strings"
"sync"
"syscall"
"time"
@@ -114,6 +115,20 @@ type Contact struct {
LocationId sql.NullInt64
}
type SimplifiedContact struct {
Id int
OwnerId sql.NullInt64
AdUserId sql.NullInt64
DisplayName string
Phone string
Mobile string
Homeoffice string
Email string
Room string
DepartmentId string
LocationId string
}
type ContactKeywordLink struct {
Contact sql.NullInt64
Keyword sql.NullInt64
@@ -131,6 +146,12 @@ type DataPort struct {
/*Links []ContactKeywordLink*/
}
type SimplifiedDataPort struct {
Contacts []SimplifiedContact
Keywords []Keyword
/*Links []ContactKeywordLink*/
}
/* ################################################################## */
/* ENDE DER STRUKTUREN */
/* ################################################################## */
@@ -144,8 +165,15 @@ func (s *Server) privateHello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hallo %s - hier deine persönlichen Daten", user)
}
func GetDataReturnDataPort(QueryContact, QueryKeyword string) DataPort {
var contList []Contact
func NullInt64ToString(n sql.NullInt64) string {
if !n.Valid {
return ""
}
return strconv.FormatInt(n.Int64, 10)
}
func GetDataReturnDataPort(QueryContact, QueryKeyword string) SimplifiedDataPort {
var contList []SimplifiedContact
var keywordList []Keyword
if QueryContact != "" {
@@ -154,7 +182,7 @@ func GetDataReturnDataPort(QueryContact, QueryKeyword string) DataPort {
fmt.Println("a", err)
}
for rowsContact.Next() {
var c Contact
var c SimplifiedContact
err = rowsContact.Scan(&c.Id, &c.OwnerId, &c.AdUserId, &c.DisplayName, &c.Phone, &c.Mobile, &c.Homeoffice, &c.Email, &c.Room, &c.DepartmentId, &c.LocationId)
if err != nil {
fmt.Println("b", err)
@@ -178,11 +206,15 @@ func GetDataReturnDataPort(QueryContact, QueryKeyword string) DataPort {
}
}
return DataPort{Contacts: contList, Keywords: keywordList}
return SimplifiedDataPort{Contacts: contList, Keywords: keywordList}
}
func makeContactTableJoin() string {
return "SELECT c.contact_id, c.contact_owner_id, c.contact_aduser_id, c.contact_displayname, c.contact_phone, c.contact_mobile, c.contact_homeoffice, c.contact_email, c.contact_room, d.department_name, l.location_name FROM contact c JOIN department d ON (c.contact_department_id = d.department_id) JOIN location l ON (c.contact_location_id = l.location_id) "
}
func (s *Server) ListPublic(w http.ResponseWriter, r *http.Request) {
D := GetDataReturnDataPort("SELECT * FROM contact c WHERE c.contact_owner_id = -1;", "SELECT * FROM keyword c WHERE c.keyword_owner = -1;")
D := GetDataReturnDataPort(makeContactTableJoin()+"WHERE c.contact_owner_id = -1;", "SELECT * FROM keyword c WHERE c.keyword_owner = -1;")
funcs := template.FuncMap{"now": time.Now}
templatesDir := getenv("BLOG_TEMPLATES_DIR", "./static/templates")
layout := template.Must(template.New("base").Funcs(funcs).ParseFiles(templatesDir + "/base.html"))
@@ -194,19 +226,31 @@ func (s *Server) ListPublic(w http.ResponseWriter, r *http.Request) {
}
func (s *Server) ListPrivate(w http.ResponseWriter, r *http.Request) {
D := GetDataReturnDataPort("SELECT * FROM contact c WHERE c.contact_owner_id = -1 OR c.contact_owner_id = 1;", "SELECT * FROM keyword c WHERE c.keyword_owner = -1 OR c.keyword_owner = 1;")
user := r.Context().Value(userKey).(string)
/*fmt.Fprintf(w, "Hallo %s - hier deine persönlichen Daten", user)*/
fmt.Println("Hallo "+user+" hier deine persönlichen Daten", user)
D := GetDataReturnDataPort(makeContactTableJoin()+"WHERE c.contact_owner_id = -1 OR c.contact_owner_id = 1;", "SELECT * FROM keyword c WHERE c.keyword_owner = -1 OR c.keyword_owner = 1;")
funcs := template.FuncMap{"now": time.Now}
templatesDir := getenv("BLOG_TEMPLATES_DIR", "./static/templates")
layout := template.Must(template.New("base").Funcs(funcs).ParseFiles(templatesDir + "/base.html"))
tplFull := template.Must(layout.Clone())
template.Must(tplFull.Funcs(funcs).ParseFiles(templatesDir+"/kontaktliste.html", templatesDir+"/schlagwortliste.html"))
tplFull.ExecuteTemplate(w, "layout", D)
/*user := r.Context().Value(userKey).(string)
fmt.Fprintf(w, "Hallo %s - hier deine persönlichen Daten", user)*/
}
func (s *Server) XcontactPublic(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
sparam := strings.TrimSpace(r.Form.Get("search"))
D := GetDataReturnDataPort(makeContactTableJoin()+"WHERE c.contact_owner_id = -1 AND (c.contact_displayname LIKE '%"+sparam+"%' OR c.contact_phone LIKE '%"+sparam+"%' OR c.contact_mobile LIKE '%"+sparam+"%' OR c.contact_homeoffice LIKE '%"+sparam+"%');", "SELECT * FROM keyword c WHERE c.keyword_owner = -1;")
funcs := template.FuncMap{"now": time.Now}
templatesDir := getenv("BLOG_TEMPLATES_DIR", "./static/templates")
layout := template.Must(template.New("kontakt").Funcs(funcs).ParseFiles(templatesDir + "/kontaktliste.html"))
layout.ExecuteTemplate(w, "kontakt", D)
}
func (s *Server) XcontactPrivate(w http.ResponseWriter, r *http.Request) {
@@ -214,7 +258,16 @@ func (s *Server) XcontactPrivate(w http.ResponseWriter, r *http.Request) {
}
func (s *Server) XdepartmentPublic(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
sparam := strings.TrimSpace(r.Form.Get("search"))
D := GetDataReturnDataPort(makeContactTableJoin()+"WHERE c.contact_owner_id = -1 AND (d.department_name LIKE '%"+sparam+"%');", "SELECT * FROM keyword c WHERE c.keyword_owner = -1;")
funcs := template.FuncMap{"now": time.Now}
templatesDir := getenv("BLOG_TEMPLATES_DIR", "./static/templates")
layout := template.Must(template.New("kontakt").Funcs(funcs).ParseFiles(templatesDir + "/kontaktliste.html"))
layout.ExecuteTemplate(w, "kontakt", D)
}
func (s *Server) XdepartmentPrivate(w http.ResponseWriter, r *http.Request) {
@@ -222,7 +275,16 @@ func (s *Server) XdepartmentPrivate(w http.ResponseWriter, r *http.Request) {
}
func (s *Server) XroomPublic(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
sparam := strings.TrimSpace(r.Form.Get("search"))
D := GetDataReturnDataPort(makeContactTableJoin()+"WHERE c.contact_owner_id = -1 AND (c.contact_room LIKE '%"+sparam+"%');", "SELECT * FROM keyword c WHERE c.keyword_owner = -1;")
funcs := template.FuncMap{"now": time.Now}
templatesDir := getenv("BLOG_TEMPLATES_DIR", "./static/templates")
layout := template.Must(template.New("kontakt").Funcs(funcs).ParseFiles(templatesDir + "/kontaktliste.html"))
layout.ExecuteTemplate(w, "kontakt", D)
}
func (s *Server) XroomPrivate(w http.ResponseWriter, r *http.Request) {
@@ -230,7 +292,16 @@ func (s *Server) XroomPrivate(w http.ResponseWriter, r *http.Request) {
}
func (s *Server) XlocationPublic(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
sparam := strings.TrimSpace(r.Form.Get("search"))
D := GetDataReturnDataPort(makeContactTableJoin()+"WHERE c.contact_owner_id = -1 AND (l.location_name LIKE '%"+sparam+"%');", "SELECT * FROM keyword c WHERE c.keyword_owner = -1;")
funcs := template.FuncMap{"now": time.Now}
templatesDir := getenv("BLOG_TEMPLATES_DIR", "./static/templates")
layout := template.Must(template.New("kontakt").Funcs(funcs).ParseFiles(templatesDir + "/kontaktliste.html"))
layout.ExecuteTemplate(w, "kontakt", D)
}
func (s *Server) XlocationPrivate(w http.ResponseWriter, r *http.Request) {
@@ -238,15 +309,42 @@ func (s *Server) XlocationPrivate(w http.ResponseWriter, r *http.Request) {
}
func (s *Server) XkeywordPublic(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
sparam := strings.TrimSpace(r.Form.Get("search"))
D := GetDataReturnDataPort(makeContactTableJoin()+"WHERE c.contact_owner_id = -1 AND (l.location_name LIKE '%"+sparam+"%');", "SELECT * FROM keyword c WHERE c.keyword_owner = -1 AND c.keyword_name LIKE '%"+sparam+"%';")
funcs := template.FuncMap{"now": time.Now}
templatesDir := getenv("BLOG_TEMPLATES_DIR", "./static/templates")
layout := template.Must(template.New("schlagwort").Funcs(funcs).ParseFiles(templatesDir + "/schlagwortliste.html"))
layout.ExecuteTemplate(w, "schlagwort", D)
}
func (s *Server) XkeywordPrivate(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
sparam := strings.TrimSpace(r.Form.Get("search"))
D := GetDataReturnDataPort(makeContactTableJoin()+"WHERE c.contact_owner_id = -1 AND (l.location_name LIKE '%"+sparam+"%');", "SELECT * FROM keyword c WHERE (c.keyword_owner = -1 OR c.keyword_owner = 1) AND c.keyword_name LIKE '%"+sparam+"%';")
funcs := template.FuncMap{"now": time.Now}
templatesDir := getenv("BLOG_TEMPLATES_DIR", "./static/templates")
layout := template.Must(template.New("schlagwort").Funcs(funcs).ParseFiles(templatesDir + "/schlagwortliste.html"))
layout.ExecuteTemplate(w, "schlagwort", D)
}
func (s *Server) XkwbctPublic(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
sparam := strings.TrimSpace(r.Form.Get("cid"))
D := GetDataReturnDataPort(makeContactTableJoin()+"WHERE c.contact_owner_id = -1 AND (l.location_name LIKE '%"+sparam+"%');", "SELECT c.* FROM keyword c JOIN contactkeyword z ON (z.contactkeyword_keyword = c.keyword_id) WHERE z.contactkeyword_contact = "+sparam+";")
funcs := template.FuncMap{"now": time.Now}
templatesDir := getenv("BLOG_TEMPLATES_DIR", "./static/templates")
layout := template.Must(template.New("schlagwort").Funcs(funcs).ParseFiles(templatesDir + "/schlagwortliste.html"))
layout.ExecuteTemplate(w, "schlagwort", D)
}
func (s *Server) XkwbctPrivate(w http.ResponseWriter, r *http.Request) {
@@ -264,6 +362,22 @@ func (s *Server) XctbkwPrivate(w http.ResponseWriter, r *http.Request) {
var CFG Config
var DB *sql.DB
type Ranger struct {
mu sync.RWMutex
xContacts map[string]struct{}
}
/*func newRanger() *Ranger {
return &Ranger{
blocks: make(map[string]map[netip.Prefix]struct{}),
whites: make(map[netip.Addr]struct{}),
}
}*/
type XServer struct {
ranger *Ranger
}
func main() {
// Signal-Kanal einrichten
@@ -283,7 +397,7 @@ func main() {
templatesDir := getenv("BLOG_TEMPLATES_DIR", "./static/templates")
CFG = Config{
DSN: "hikos:hikos@tcp(10.10.5.31:3306)/hikos?parseTime=true",
DSN: "hikos:hikos@tcp(db-mysql-ubnt-a.stadt-hilden.de:3306)/hikos?parseTime=true",
LDAPURL: "ldaps://ldaps.example.com:636",
LDAPBindPattern: "uid=%s,ou=users,dc=example,dc=com",
SessionTTL: 24 * time.Hour,
@@ -322,8 +436,8 @@ func main() {
tplFull := template.Must(layout.Clone())
template.Must(tplFull.Funcs(funcs).ParseFiles(templatesDir+"/kontaktliste.html", templatesDir+"/schlagwortliste.html"))
tplKontakt := template.Must(template.New("kontakt").Funcs(funcs).ParseFiles(templatesDir + "/kontaktliste.html"))
tplSchlagwort := template.Must(template.New("kontakt").Funcs(funcs).ParseFiles(templatesDir + "/schlagwortliste.html"))
/*tplKontakt := template.Must(template.New("kontakt").Funcs(funcs).ParseFiles(templatesDir + "/kontaktliste.html"))
tplSchlagwort := template.Must(template.New("kontakt").Funcs(funcs).ParseFiles(templatesDir + "/schlagwortliste.html"))*/
layoutSSO := template.Must(template.New("sso").Funcs(funcs).ParseFiles(templatesDir + "/login.html"))
@@ -349,7 +463,7 @@ func main() {
mux.Handle("/htmx/keywordbycontact", srv.authAware(false, http.HandlerFunc(srv.XkwbctPublic), http.HandlerFunc(srv.XkwbctPrivate)))
mux.Handle("/htmx/contactbykeyword", srv.authAware(false, http.HandlerFunc(srv.XctbkwPublic), http.HandlerFunc(srv.XctbkwPrivate)))
mux.HandleFunc("/htmx/contact", func(w http.ResponseWriter, r *http.Request) {
/*mux.HandleFunc("/htmx/contact", func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
http.Error(w, "bad request", http.StatusBadRequest)
return
@@ -391,7 +505,7 @@ func main() {
mux.HandleFunc("/htmx/schlagwortbykontakt", func(w http.ResponseWriter, r *http.Request) {
tplSchlagwort.ExecuteTemplate(w, "schlagwort", nil)
})
})*/
mux.Handle("/static/", cacheControl(http.StripPrefix("/static/", http.FileServer(http.Dir(staticDir)))))
@@ -555,7 +669,7 @@ func (s *Server) loginHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "internal error", http.StatusInternalServerError)
return
}
http.SetCookie(w, &http.Cookie{Name: "session_token", Value: token, Expires: time.Now().Add(s.cfg.SessionTTL), Path: "/", Secure: true, HttpOnly: true, SameSite: http.SameSiteStrictMode})
http.SetCookie(w, &http.Cookie{Name: "session_token", Value: token, Expires: time.Now().Add(s.cfg.SessionTTL), Path: "/", Secure: false, HttpOnly: true, SameSite: http.SameSiteStrictMode})
http.Redirect(w, r, "/", http.StatusMovedPermanently)
}
@@ -596,7 +710,7 @@ func (s *Server) authAware(required bool, unauth, auth http.Handler) http.Handle
if required {
if !isAuth {
http.Redirect(w, r, "/login", http.StatusFound)
http.Redirect(w, r, "/sso", http.StatusFound)
return
}
auth.ServeHTTP(w, r) // C

View File

@@ -35,7 +35,7 @@
}
/* Dark mode (optional) */
@media (prefers-color-scheme: dark) {
/*@media (prefers-color-scheme: dark) {
:root {
--bg: #161b22;
--bg-alt: #161b22;
@@ -48,7 +48,7 @@
--code-border: #30363d;
--shadow: 0 4px 16px rgba(0,0,0,.32);
}
}
}*/
* {
margin: 0;
@@ -175,7 +175,7 @@
th, td {
border: 1px solid #ddd; /* Beispiel für einen Rahmen */
padding: 8px;
padding: 4px;
text-align: center; /* Beispiel für Textzentrierung */
}

View File

@@ -14,16 +14,16 @@
<div class="container">
<div id="bereich-a">
<div class="top">
<input type="text" name="search" placeholder="Suchfeld" autocomplete="false" hx-post="/htmx/contact" hx-trigger="keyup changed delay:500ms" hx-target="#z-1" hx-swap="outerHTML" />
<input type="text" name="search" placeholder="Amt" autocomplete="false" hx-post="/htmx/department" hx-trigger="keyup changed delay:500ms" hx-target="#z-1" hx-swap="outerHTML" />
<input type="text" name="search" placeholder="Raum" autocomplete="false" hx-post="/htmx/room" hx-trigger="keyup changed delay:500ms" hx-target="#z-1" hx-swap="outerHTML" />
<input type="text" name="search" placeholder="Gebäude" autocomplete="false" hx-post="/htmx/location" hx-trigger="keyup changed delay:500ms" hx-target="#z-1" hx-swap="outerHTML" />
<input type="text" name="search" placeholder="Suchfeld" autocomplete="false" hx-post="/htmx/contact" hx-trigger="keyup changed delay:200ms" hx-target="#z-1" hx-swap="outerHTML" />
<input type="text" name="search" placeholder="Amt" autocomplete="false" hx-post="/htmx/department" hx-trigger="keyup changed delay:200ms" hx-target="#z-1" hx-swap="outerHTML" />
<input type="text" name="search" placeholder="Raum" autocomplete="false" hx-post="/htmx/room" hx-trigger="keyup changed delay:200ms" hx-target="#z-1" hx-swap="outerHTML" />
<input type="text" name="search" placeholder="Gebäude" autocomplete="false" hx-post="/htmx/location" hx-trigger="keyup changed delay:200ms" hx-target="#z-1" hx-swap="outerHTML" />
</div>
{{ template "kontakt" . }}
</div>
<div id="bereich-b">
<div class="top">
<input type="text" placeholder="Stichwort" />
<input type="text" name="search" placeholder="Stichwort" hx-post="/htmx/keyword" hx-trigger="keyup changed delay:200ms" hx-target="#z-2" hx-swap="outerHTML" />
</div>
{{ template "schlagwort" . }}
</div>

View File

@@ -23,14 +23,14 @@
</thead>
<tbody>
{{ range .Contacts }}
<tr>
<tr hx-post="/htmx/keywordbycontact" hx-trigger="click delay:200ms" hx-target="#z-2" hx-swap="outerHTML" hx-vals='{"cid": "{{ .Id }}"}'>
<td>{{ if .DisplayName }}{{ .DisplayName }}{{ end }}</td>
<td>{{ if .Phone }}{{ .Phone }}{{ end }}</td>
<td>{{ if .Mobile }}{{ .Mobile }}{{ end }}</td>
<td>{{ if .Homeoffice }}{{ .Homeoffice }}{{ end }}</td>
<td>{{ if .DepartmentId.Valid }}{{ .DepartmentId.Int64 }}{{ end }}</td>
<td>{{ if .DepartmentId }}{{ .DepartmentId }}{{ end }}</td>
<td>{{ if .Room }}{{ .Room }}{{ end }}</td>
<td>{{ if .LocationId.Valid }}{{ .LocationId.Int64 }}{{ end }}</td>
<td>{{ if .LocationId }}{{ .LocationId }}{{ end }}</td>
</tr>
{{ end }}
</tbody>