2024-01-17 19:28:42 +00:00
|
|
|
package user
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2024-05-03 18:45:14 +00:00
|
|
|
httplib "dev.tandem.ws/tandem/camper/pkg/http"
|
|
|
|
"fmt"
|
2024-01-17 19:28:42 +00:00
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"dev.tandem.ws/tandem/camper/pkg/auth"
|
|
|
|
"dev.tandem.ws/tandem/camper/pkg/database"
|
|
|
|
"dev.tandem.ws/tandem/camper/pkg/template"
|
|
|
|
)
|
|
|
|
|
|
|
|
func serveLoginAttemptIndex(w http.ResponseWriter, r *http.Request, loginAttempt *auth.User, company *auth.Company, conn *database.Conn) {
|
2024-05-03 18:45:14 +00:00
|
|
|
filters := newFilterForm()
|
|
|
|
if err := filters.Parse(r); err != nil {
|
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
loginAttempts, err := collectLoginAttemptEntries(r.Context(), conn, filters)
|
2024-01-17 19:28:42 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2024-05-03 18:45:14 +00:00
|
|
|
index := &loginAttemptIndex{
|
|
|
|
Attempts: filters.buildCursor(loginAttempts),
|
|
|
|
Filters: filters,
|
|
|
|
}
|
|
|
|
index.MustRender(w, r, loginAttempt, company)
|
2024-01-17 19:28:42 +00:00
|
|
|
}
|
|
|
|
|
2024-05-03 18:45:14 +00:00
|
|
|
func collectLoginAttemptEntries(ctx context.Context, conn *database.Conn, filters *filterForm) ([]*loginAttemptEntry, error) {
|
|
|
|
where, args := filters.BuildQuery(nil)
|
|
|
|
rows, err := conn.Query(ctx, fmt.Sprintf(`
|
|
|
|
select attempt_id
|
|
|
|
, user_name
|
2024-01-17 19:28:42 +00:00
|
|
|
, host(ip_address)
|
|
|
|
, attempted_at
|
|
|
|
, success
|
|
|
|
from company_login_attempt
|
2024-05-03 18:45:14 +00:00
|
|
|
where (%s)
|
|
|
|
order by attempted_at desc, attempt_id desc
|
|
|
|
limit %d
|
|
|
|
`, where, filters.PerPage()+1), args...)
|
2024-01-17 19:28:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer rows.Close()
|
|
|
|
|
2024-05-03 18:45:14 +00:00
|
|
|
var entries []*loginAttemptEntry
|
2024-01-17 19:28:42 +00:00
|
|
|
for rows.Next() {
|
|
|
|
entry := &loginAttemptEntry{}
|
2024-05-03 18:45:14 +00:00
|
|
|
if err = rows.Scan(&entry.ID, &entry.UserName, &entry.IPAddress, &entry.Date, &entry.Success); err != nil {
|
2024-01-17 19:28:42 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
entries = append(entries, entry)
|
|
|
|
}
|
|
|
|
|
|
|
|
return entries, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type loginAttemptEntry struct {
|
2024-05-03 18:45:14 +00:00
|
|
|
ID int
|
2024-01-17 19:28:42 +00:00
|
|
|
UserName string
|
|
|
|
IPAddress string
|
|
|
|
Date time.Time
|
|
|
|
Success bool
|
|
|
|
}
|
|
|
|
|
2024-05-03 18:45:14 +00:00
|
|
|
type loginAttemptIndex struct {
|
|
|
|
Attempts []*loginAttemptEntry
|
|
|
|
Filters *filterForm
|
|
|
|
}
|
2024-01-17 19:28:42 +00:00
|
|
|
|
2024-05-03 18:45:14 +00:00
|
|
|
func (page *loginAttemptIndex) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) {
|
|
|
|
if httplib.IsHTMxRequest(r) && page.Filters.Paginated() {
|
|
|
|
template.MustRenderAdminNoLayout(w, r, user, company, "user/results.gohtml", page)
|
|
|
|
} else {
|
|
|
|
template.MustRenderAdminFiles(w, r, user, company, page, "user/login-attempts.gohtml", "user/results.gohtml")
|
|
|
|
}
|
2024-01-17 19:28:42 +00:00
|
|
|
}
|