Merge pull request 'Merge recent UI & Postgres work into main branch' (#4) from postgres into main

Reviewed-on: #4
This commit is contained in:
William Bouzourène 2025-07-24 10:13:00 +00:00
commit 8ddc81289b
51 changed files with 3657 additions and 3144 deletions

View file

@ -3,5 +3,5 @@ DEV_MODE=false
APP_LISTEN_ADDRESS=127.0.0.1
APP_LISTEN_PORT=3000
APP_BEHIND_PROXY=false
DATABASE_LOCATION=./people.db
DATABASE_DSN="host=localhost user=camarades password=camarades dbname=camarades port=5432 sslmode=disable TimeZone=Europe/Zurich"
SESSIONS_LOCATION=./sessions.db

14
compose.yml Normal file
View file

@ -0,0 +1,14 @@
services:
postgres:
image: postgres:latest
container_name: camarades-postgres
ports:
- "127.0.0.1:5432:5432"
environment:
POSTGRES_USER: camarades
POSTGRES_PASSWORD: camarades
POSTGRES_DB: camarades
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:

View file

@ -68,8 +68,11 @@ func Contacts(c *fiber.Ctx) error {
params.PageSize = 50
params.PersonType = "contacts"
params.OrderColumn = c.Query("c")
params.OrderDirection = c.Query("o")
var sections []models.Section
db.Order("name collate nocase asc").Find(&sections, "contains_contacts = ? AND id IN ?", true, allowedSections)
db.Order("name asc").Find(&sections, "contains_contacts = ? AND id IN ?", true, allowedSections)
params.AllowedSections = allowedSections
// Security for active contacts
@ -100,6 +103,8 @@ func Contacts(c *fiber.Ctx) error {
"SearchJSON": searchJSON,
"Sections": sections,
"Fields": fields,
"OrderCol": params.OrderColumn,
"OrderDir": params.OrderDirection,
})
}
@ -156,7 +161,7 @@ func ContactsExport(c *fiber.Ctx) error {
params.PersonType = "contacts"
var sections []models.Section
db.Order("name collate nocase asc").Find(&sections, "contains_members = ? AND id IN ?", true, allowedSections)
db.Order("name asc").Find(&sections, "contains_members = ? AND id IN ?", true, allowedSections)
params.AllowedSections = allowedSections
// Security for active contacts
@ -280,7 +285,7 @@ func ContactsExport(c *fiber.Ctx) error {
} else if field.FieldType == "list" {
if field.List.Multi {
if field.List != nil && field.List.Multi {
if countMulti == 0 {
c.Writef("\"")
@ -323,7 +328,7 @@ func ContactShow(c *fiber.Ctx) error {
var person models.Person
result := db.Unscoped().Preload("Section").Find(
&person, "id = ? AND is_contact", id, true,
&person, "id = ? AND is_contact = ?", id, true,
)
if result.Error != nil {
@ -416,7 +421,7 @@ func ContactAdd(c *fiber.Ctx) error {
}
var sections []models.Section
db.Order("name collate nocase asc").Find(
db.Order("name asc").Find(
&sections,
"contains_contacts = ?",
true,
@ -511,7 +516,7 @@ func ContactAdd(c *fiber.Ctx) error {
}
for _, field := range fields {
if field.List.Multi {
if field.List != nil && field.List.Multi {
for _, listItem := range field.List.ListItems {
key := fmt.Sprintf("field-%d-%d", field.ID, listItem.ID)
value := c.FormValue(key)
@ -520,7 +525,7 @@ func ContactAdd(c *fiber.Ctx) error {
var fieldValue models.FieldValue
fieldValue.FieldID = field.ID
fieldValue.PersonID = person.ID
fieldValue.ListItemID = listItem.ID
fieldValue.ListItemID = &listItem.ID
db.Create(&fieldValue)
}
}
@ -594,7 +599,8 @@ func ContactAdd(c *fiber.Ctx) error {
var fieldValue models.FieldValue
fieldValue.FieldID = field.ID
fieldValue.PersonID = person.ID
fieldValue.ListItemID = uint(valueInt)
valueUint := uint(valueInt)
fieldValue.ListItemID = &valueUint
db.Create(&fieldValue)
}
}
@ -659,7 +665,7 @@ func ContactEdit(c *fiber.Ctx) error {
}
var sections []models.Section
db.Order("name collate nocase asc").Find(
db.Order("name asc").Find(
&sections,
"contains_contacts = ?",
true,
@ -760,7 +766,7 @@ func ContactEdit(c *fiber.Ctx) error {
field.ID,
)
if field.List.Multi {
if field.List != nil && field.List.Multi {
for _, listItem := range field.List.ListItems {
key := fmt.Sprintf("field-%d-%d", field.ID, listItem.ID)
value := c.FormValue(key)
@ -769,7 +775,7 @@ func ContactEdit(c *fiber.Ctx) error {
var fieldValue models.FieldValue
fieldValue.FieldID = field.ID
fieldValue.PersonID = person.ID
fieldValue.ListItemID = listItem.ID
fieldValue.ListItemID = &listItem.ID
db.Create(&fieldValue)
}
}
@ -843,7 +849,8 @@ func ContactEdit(c *fiber.Ctx) error {
var fieldValue models.FieldValue
fieldValue.FieldID = field.ID
fieldValue.PersonID = person.ID
fieldValue.ListItemID = uint(valueInt)
valueUint := uint(valueInt)
fieldValue.ListItemID = &valueUint
db.Create(&fieldValue)
}
}

View file

@ -110,7 +110,7 @@ func DebugFixFieldsOrder(c *fiber.Ctx) error {
var memberFields []models.Field
result := db.Order(
"name collate nocase asc",
"name asc",
).Find(
&memberFields, "person_type = ?", "member",
)
@ -130,7 +130,7 @@ func DebugFixFieldsOrder(c *fiber.Ctx) error {
var contactFields []models.Field
result2 := db.Order(
"name collate nocase asc",
"name asc",
).Find(
&contactFields, "person_type = ?", "contact",
)

View file

@ -74,7 +74,7 @@ func FieldAdd(c *fiber.Ctx) error {
}
var lists []models.List
db.Order("name collate nocase asc").Find(&lists)
db.Order("name asc").Find(&lists)
if c.Method() == "POST" {
field.Name = c.FormValue("name")
@ -107,7 +107,8 @@ func FieldAdd(c *fiber.Ctx) error {
if err != nil || listID < 1 {
errors = append(errors, "Liste incorrecte")
} else {
field.ListID = uint(listID)
listID2 := uint(listID)
field.ListID = &listID2
}
}

View file

@ -1,15 +1,82 @@
package controllers
import "github.com/gofiber/fiber/v2"
import (
"git.readonly.ch/bouzoure/pop-camarades/helpers"
"git.readonly.ch/bouzoure/pop-camarades/models"
"github.com/gofiber/fiber/v2"
)
func Homepage(c *fiber.Ctx) error {
userid, err := helpers.GetSessionUserId(c)
if err != nil {
return err
}
allowedSectionsMembers, err := helpers.PermissionsGetSections(
userid, "show_member",
)
if err != nil {
return err
}
allowedSectionsContacts, err := helpers.PermissionsGetSections(
userid, "show_contact",
)
if err != nil {
return err
}
db, err := helpers.GetDatabase()
if err != nil {
return err
}
var membersCount int64
var contactsCount int64
db.Find(
&models.Person{},
"is_member = ? AND section_id IN ?",
true, allowedSectionsMembers,
).Count(&membersCount)
db.Find(
&models.Person{},
"is_contact = ? AND section_id IN ?",
true, allowedSectionsContacts,
).Count(&contactsCount)
return c.Render("index", fiber.Map{
"PageTitle": "Accueil",
"MembersCount": membersCount,
"ContactsCount": contactsCount,
})
}
func Admin(c *fiber.Ctx) error {
db, err := helpers.GetDatabase()
if err != nil {
return err
}
var sectionsCount int64
var listsCount int64
var fieldsCount int64
var usersCount int64
var rolesCount int64
db.Find(&models.Section{}).Count(&sectionsCount)
db.Find(&models.List{}).Count(&listsCount)
db.Find(&models.Field{}).Count(&fieldsCount)
db.Find(&models.User{}).Count(&usersCount)
db.Find(&models.Role{}).Count(&rolesCount)
return c.Render("admin", fiber.Map{
"PageTitle": "Administration",
"SectionsCount": sectionsCount,
"ListsCount": listsCount,
"FieldsCount": fieldsCount,
"UsersCount": usersCount,
"RolesCount": rolesCount,
})
}

View file

@ -17,7 +17,7 @@ func Lists(c *fiber.Ctx) error {
}
var lists []models.List
result := db.Order("name collate nocase asc").Find(&lists)
result := db.Order("name asc").Find(&lists)
if result.Error != nil && !errors.Is(result.Error, gorm.ErrRecordNotFound) {
return err
@ -54,7 +54,7 @@ func ListShow(c *fiber.Ctx) error {
)
var listItems []models.ListItem
db.Order("value collate nocase asc").Find(&listItems, "list_id = ?", id)
db.Order("value asc").Find(&listItems, "list_id = ?", id)
return c.Render("list", fiber.Map{
"PageTitle": title,

View file

@ -83,8 +83,11 @@ func Members(c *fiber.Ctx) error {
params.PageSize = 50
params.PersonType = "members"
params.OrderColumn = c.Query("c")
params.OrderDirection = c.Query("o")
var sections []models.Section
db.Order("name collate nocase asc").Find(&sections, "contains_members = ? AND id IN ?", true, allowedSections)
db.Order("name asc").Find(&sections, "contains_members = ? AND id IN ?", true, allowedSections)
params.AllowedSections = allowedSections
// Security for active contacts
@ -115,6 +118,8 @@ func Members(c *fiber.Ctx) error {
"SearchJSON": searchJSON,
"Sections": sections,
"Fields": fields,
"OrderCol": params.OrderColumn,
"OrderDir": params.OrderDirection,
})
}
@ -171,7 +176,7 @@ func MembersExport(c *fiber.Ctx) error {
params.PersonType = "members"
var sections []models.Section
db.Order("name collate nocase asc").Find(&sections, "contains_members = ? AND id IN ?", true, allowedSections)
db.Order("name asc").Find(&sections, "contains_members = ? AND id IN ?", true, allowedSections)
params.AllowedSections = allowedSections
// Security for active contacts
@ -338,7 +343,7 @@ func MemberShow(c *fiber.Ctx) error {
var person models.Person
result := db.Unscoped().Preload("Section").Find(
&person, "id = ? AND is_member", id, true,
&person, "id = ? AND is_member = ?", id, true,
)
if result.Error != nil {
@ -431,7 +436,7 @@ func MemberAdd(c *fiber.Ctx) error {
}
var sections []models.Section
db.Order("name collate nocase asc").Find(
db.Order("name asc").Find(
&sections,
"contains_members = ?",
true,
@ -526,7 +531,7 @@ func MemberAdd(c *fiber.Ctx) error {
}
for _, field := range fields {
if field.List.Multi {
if field.List != nil && field.List.Multi {
for _, listItem := range field.List.ListItems {
key := fmt.Sprintf("field-%d-%d", field.ID, listItem.ID)
value := c.FormValue(key)
@ -535,7 +540,7 @@ func MemberAdd(c *fiber.Ctx) error {
var fieldValue models.FieldValue
fieldValue.FieldID = field.ID
fieldValue.PersonID = person.ID
fieldValue.ListItemID = listItem.ID
fieldValue.ListItemID = &listItem.ID
db.Create(&fieldValue)
}
}
@ -609,7 +614,8 @@ func MemberAdd(c *fiber.Ctx) error {
var fieldValue models.FieldValue
fieldValue.FieldID = field.ID
fieldValue.PersonID = person.ID
fieldValue.ListItemID = uint(valueInt)
valueUint := uint(valueInt)
fieldValue.ListItemID = &valueUint
db.Create(&fieldValue)
}
}
@ -674,7 +680,7 @@ func MemberEdit(c *fiber.Ctx) error {
}
var sections []models.Section
db.Order("name collate nocase asc").Find(
db.Order("name asc").Find(
&sections,
"contains_members = ?",
true,
@ -775,7 +781,7 @@ func MemberEdit(c *fiber.Ctx) error {
field.ID,
)
if field.List.Multi {
if field.List != nil && field.List.Multi {
for _, listItem := range field.List.ListItems {
key := fmt.Sprintf("field-%d-%d", field.ID, listItem.ID)
value := c.FormValue(key)
@ -784,7 +790,7 @@ func MemberEdit(c *fiber.Ctx) error {
var fieldValue models.FieldValue
fieldValue.FieldID = field.ID
fieldValue.PersonID = person.ID
fieldValue.ListItemID = listItem.ID
fieldValue.ListItemID = &listItem.ID
db.Create(&fieldValue)
}
}
@ -858,7 +864,8 @@ func MemberEdit(c *fiber.Ctx) error {
var fieldValue models.FieldValue
fieldValue.FieldID = field.ID
fieldValue.PersonID = person.ID
fieldValue.ListItemID = uint(valueInt)
valueUint := uint(valueInt)
fieldValue.ListItemID = &valueUint
db.Create(&fieldValue)
}
}

View file

@ -17,7 +17,7 @@ func Roles(c *fiber.Ctx) error {
}
var roles []models.Role
result := db.Order("name collate nocase asc").Find(&roles)
result := db.Order("name asc").Find(&roles)
if result.Error != nil && !errors.Is(result.Error, gorm.ErrRecordNotFound) {
return err

View file

@ -18,7 +18,7 @@ func Sections(c *fiber.Ctx) error {
}
var sections []models.Section
result := db.Order("name collate nocase asc").Preload("ParentSection").Find(&sections)
result := db.Order("name asc").Preload("ParentSection").Find(&sections)
if result.Error != nil && !errors.Is(result.Error, gorm.ErrRecordNotFound) {
return err
@ -70,8 +70,8 @@ func SectionAdd(c *fiber.Ctx) error {
}
var sections []models.Section
db.Order("name collate nocase asc").Find(
&sections, "id <> ? AND parent_section_id = 0", section.ID,
db.Order("name asc").Find(
&sections, "id <> ? AND parent_section_id IS NULL", section.ID,
)
if c.Method() == "POST" {
@ -106,12 +106,12 @@ func SectionAdd(c *fiber.Ctx) error {
section.Name = name
section.ShortName = shortName
section.ParentSectionID = 0
parentSectionID, err := strconv.ParseUint(parentSection, 10, 0)
if err == nil {
for _, parentSection := range sections {
if parentSection.ID == uint(parentSectionID) {
section.ParentSectionID = uint(parentSectionID)
parentSectionID2 := uint(parentSectionID)
if parentSection.ID == parentSectionID2 {
section.ParentSectionID = &parentSectionID2
break
}
}
@ -177,8 +177,8 @@ func SectionEdit(c *fiber.Ctx) error {
)
var sections []models.Section
db.Order("name collate nocase asc").Find(
&sections, "id <> ? AND parent_section_id = 0", section.ID,
db.Order("name asc").Find(
&sections, "id <> ? AND parent_section_id IS NULL", section.ID,
)
var errors []string
@ -200,12 +200,12 @@ func SectionEdit(c *fiber.Ctx) error {
section.Name = name
section.ShortName = shortName
section.ParentSectionID = 0
parentSectionID, err := strconv.ParseUint(parentSection, 10, 0)
if err == nil {
for _, parentSection := range sections {
if parentSection.ID == uint(parentSectionID) {
section.ParentSectionID = uint(parentSectionID)
parentSectionID2 := uint(parentSectionID)
if parentSection.ID == parentSectionID2 {
section.ParentSectionID = &parentSectionID2
break
}
}

View file

@ -25,7 +25,7 @@ func Users(c *fiber.Ctx) error {
}
var users []models.User
result := db.Order("name collate nocase asc").Find(&users)
result := db.Order("name asc").Find(&users)
if result.Error != nil && !errors.Is(result.Error, gorm.ErrRecordNotFound) {
return err
@ -62,7 +62,7 @@ func UserShow(c *fiber.Ctx) error {
)
var userRoles []models.UserRole
db.Joins("Role").Joins("Section").Order("Section__name collate nocase asc").Find(
db.Joins("Role").Joins("Section").Order("\"Section\".\"name\" asc").Find(
&userRoles, "user_id = ?", id,
)
@ -284,10 +284,10 @@ func UserPermissions(c *fiber.Ctx) error {
)
var roles []models.Role
db.Order("name collate nocase asc").Find(&roles)
db.Order("name asc").Find(&roles)
var sections []models.Section
db.Order("name collate nocase asc").Find(&sections)
db.Order("name asc").Find(&sections)
var errors []string
if c.Method() == "POST" {

6
frontend/bootstrap.scss vendored Normal file
View file

@ -0,0 +1,6 @@
$red: #cb0000;
@use "npm:bootstrap/scss/bootstrap.scss" with (
$enable-rounded: false,
$danger: $red
);

View file

@ -1,4 +1,4 @@
@import "npm:bootstrap/dist/css/bootstrap.css";
@import "bootstrap.scss";
@import "npm:bootstrap-icons/font/bootstrap-icons.css";
img#header-logo {
@ -53,3 +53,17 @@ a {
#licenses p {
margin: 0;
}
.fs-7 {
font-size: .75rem !important;
}
.mw-600 {
max-width: 600px;
}
.mw-900 {
max-width: 900px;
}
.mw-1200 {
max-width: 1200px;
}

48
go.mod
View file

@ -3,32 +3,32 @@ module git.readonly.ch/bouzoure/pop-camarades
go 1.23.4
require (
github.com/brianvoe/gofakeit/v7 v7.2.1
github.com/charmbracelet/log v0.4.1
github.com/brianvoe/gofakeit/v7 v7.3.0
github.com/charmbracelet/log v0.4.2
github.com/flosch/pongo2/v6 v6.0.0
github.com/glebarez/sqlite v1.11.0
github.com/go-playground/validator/v10 v10.26.0
github.com/gofiber/fiber/v2 v2.52.6
github.com/go-playground/validator/v10 v10.27.0
github.com/gofiber/fiber/v2 v2.52.8
github.com/gofiber/helmet/v2 v2.2.26
github.com/gofiber/storage/badger/v2 v2.0.1
github.com/gofiber/template/django/v3 v3.1.13
github.com/gofiber/template/django/v3 v3.1.14
github.com/golobby/dotenv v1.3.2
github.com/google/uuid v1.6.0
github.com/pquerna/otp v1.4.0
github.com/yuin/goldmark v1.7.11
golang.org/x/crypto v0.38.0
gorm.io/gorm v1.26.1
github.com/pquerna/otp v1.5.0
github.com/yuin/goldmark v1.7.12
golang.org/x/crypto v0.40.0
gorm.io/driver/postgres v1.6.0
gorm.io/gorm v1.30.0
)
require (
github.com/andybalholm/brotli v1.1.1 // indirect
github.com/andybalholm/brotli v1.2.0 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/boombuler/barcode v1.0.2 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charmbracelet/colorprofile v0.3.1 // indirect
github.com/charmbracelet/lipgloss v1.1.0 // indirect
github.com/charmbracelet/x/ansi v0.9.2 // indirect
github.com/charmbracelet/x/ansi v0.9.3 // indirect
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
@ -36,19 +36,22 @@ require (
github.com/dgraph-io/ristretto v0.2.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
github.com/glebarez/go-sqlite v1.22.0 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/gofiber/template v1.8.3 // indirect
github.com/gofiber/utils v1.1.0 // indirect
github.com/gofiber/utils/v2 v2.0.0-beta.8 // indirect
github.com/gofiber/utils/v2 v2.0.0-beta.10 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v1.0.0 // indirect
github.com/golobby/cast v1.3.3 // indirect
github.com/google/flatbuffers v25.2.10+incompatible // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.5 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/compress v1.18.0 // indirect
@ -58,22 +61,17 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/muesli/termenv v0.16.0 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.62.0 // indirect
github.com/valyala/fasthttp v1.63.0 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.25.0 // indirect
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
golang.org/x/net v0.42.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/text v0.27.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
modernc.org/libc v1.65.4 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.10.0 // indirect
modernc.org/sqlite v1.37.0 // indirect
)

123
go.sum
View file

@ -2,16 +2,16 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/boombuler/barcode v1.0.2 h1:79yrbttoZrLGkL/oOI8hBrUKucwOL0oOjUgEguGMcJ4=
github.com/boombuler/barcode v1.0.2/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/brianvoe/gofakeit/v7 v7.2.1 h1:AGojgaaCdgq4Adzrd2uWdbGNDyX6MWNhHdQBraNfOHI=
github.com/brianvoe/gofakeit/v7 v7.2.1/go.mod h1:QXuPeBw164PJCzCUZVmgpgHJ3Llj49jSLVkKPMtxtxA=
github.com/brianvoe/gofakeit/v7 v7.3.0 h1:TWStf7/lLpAjKw+bqwzeORo9jvrxToWEwp9b1J2vApQ=
github.com/brianvoe/gofakeit/v7 v7.3.0/go.mod h1:QXuPeBw164PJCzCUZVmgpgHJ3Llj49jSLVkKPMtxtxA=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
@ -22,10 +22,10 @@ github.com/charmbracelet/colorprofile v0.3.1 h1:k8dTHMd7fgw4bnFd7jXTLZrSU/CQrKnL
github.com/charmbracelet/colorprofile v0.3.1/go.mod h1:/GkGusxNs8VB/RSOh3fu0TJmQ4ICMMPApIIVn0KszZ0=
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
github.com/charmbracelet/log v0.4.1 h1:6AYnoHKADkghm/vt4neaNEXkxcXLSV2g1rdyFDOpTyk=
github.com/charmbracelet/log v0.4.1/go.mod h1:pXgyTsqsVu4N9hGdHmQ0xEA4RsXof402LX9ZgiITn2I=
github.com/charmbracelet/x/ansi v0.9.2 h1:92AGsQmNTRMzuzHEYfCdjQeUzTrgE1vfO5/7fEVoXdY=
github.com/charmbracelet/x/ansi v0.9.2/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
github.com/charmbracelet/log v0.4.2 h1:hYt8Qj6a8yLnvR+h7MwsJv/XvmBJXiueUcI3cIxsyig=
github.com/charmbracelet/log v0.4.2/go.mod h1:qifHGX/tc7eluv2R6pWIpyHDDrrb/AG71Pf2ysQu5nw=
github.com/charmbracelet/x/ansi v0.9.3 h1:BXt5DHS/MKF+LjuK4huWrC6NCvHtexww7dMayh6GXd0=
github.com/charmbracelet/x/ansi v0.9.3/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k=
github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
@ -63,10 +63,6 @@ github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vt
github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
@ -75,22 +71,22 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/gofiber/fiber/v2 v2.52.6 h1:Rfp+ILPiYSvvVuIPvxrBns+HJp8qGLDnLJawAu27XVI=
github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/gofiber/fiber/v2 v2.52.8 h1:xl4jJQ0BV5EJTA2aWiKw/VddRpHrKeZLF0QPUxqn0x4=
github.com/gofiber/fiber/v2 v2.52.8/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
github.com/gofiber/helmet/v2 v2.2.26 h1:KreQVUpCIGppPQ6Yt8qQMaIR4fVXMnvBdsda0dJSsO8=
github.com/gofiber/helmet/v2 v2.2.26/go.mod h1:XE0DF4cgf0M5xIt7qyAK5zOi8jJblhxfSDv9DAmEEQo=
github.com/gofiber/storage/badger/v2 v2.0.1 h1:iIB5Dh2dypJjdEruYgBf7H4l5a98R5pVKVLk5wbY5bo=
github.com/gofiber/storage/badger/v2 v2.0.1/go.mod h1:2LA5uR3q4xFVd0oXIZWK+7yzlO2vzLa/D062R7fowFI=
github.com/gofiber/template v1.8.3 h1:hzHdvMwMo/T2kouz2pPCA0zGiLCeMnoGsQZBTSYgZxc=
github.com/gofiber/template v1.8.3/go.mod h1:bs/2n0pSNPOkRa5VJ8zTIvedcI/lEYxzV3+YPXdBvq8=
github.com/gofiber/template/django/v3 v3.1.13 h1:9b5VOFUoetOV3axFE7BsLmnZ442Q+h7o9LZPwQ29WEc=
github.com/gofiber/template/django/v3 v3.1.13/go.mod h1:orkcSnqCO0HGTczIBj9rz77i+EneUMebCqA7bsIWaVA=
github.com/gofiber/template/django/v3 v3.1.14 h1:SvTvs+u5vTZuu1Y2pMUD2NhaGIjBj9FmDA3XD50QBvw=
github.com/gofiber/template/django/v3 v3.1.14/go.mod h1:gP4vH+T1ajZw7yaejqG1dZVdHQkMC/jPoQbmlG812I0=
github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM=
github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0=
github.com/gofiber/utils/v2 v2.0.0-beta.8 h1:ZifwbHZqZO3YJsx1ZhDsWnPjaQ7C0YD20LHt+DQeXOU=
github.com/gofiber/utils/v2 v2.0.0-beta.8/go.mod h1:1lCBo9vEF4RFEtTgWntipnaScJZQiM8rrsYycLZ4n9c=
github.com/gofiber/utils/v2 v2.0.0-beta.10 h1:yDQgcBKTnZiZ4S0YY+hpTnf5iJYwVaFA2HsOgOesAyY=
github.com/gofiber/utils/v2 v2.0.0-beta.10/go.mod h1:qEZ175nSOkl5xciHmqxwNDsWzwiB39gB8RgU1d3U4mQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@ -130,13 +126,19 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs=
github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
@ -169,8 +171,6 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -178,17 +178,17 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs=
github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/shamaton/msgpack/v2 v2.2.3 h1:uDOHmxQySlvlUYfQwdjxyybAOzjlQsD1Vjy+4jmO9NM=
github.com/shamaton/msgpack/v2 v2.2.3/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@ -204,6 +204,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
@ -212,8 +213,8 @@ github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.62.0 h1:8dKRBX/y2rCzyc6903Zu1+3qN0H/d2MsxPPmVNamiH0=
github.com/valyala/fasthttp v1.62.0/go.mod h1:FCINgr4GKdKqV8Q0xv8b+UxPV+H/O5nNFo3D+r54Htg=
github.com/valyala/fasthttp v1.63.0 h1:DisIL8OjB7ul2d7cBaMRcKTQDYnrGy56R4FCiuDP0Ns=
github.com/valyala/fasthttp v1.63.0/go.mod h1:REc4IeW+cAEyLrRPa5A81MIjvz0QE1laoTX2EaPHKJM=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
@ -223,8 +224,8 @@ github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZ
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.7.11 h1:ZCxLyDMtz0nT2HFfsYG8WZ47Trip2+JyLysKcMYE5bo=
github.com/yuin/goldmark v1.7.11/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
github.com/yuin/goldmark v1.7.12 h1:YwGP/rrea2/CnCtUHgjuolG/PnMxdQtPMO5PvaE2/nY=
github.com/yuin/goldmark v1.7.12/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
@ -232,18 +233,16 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -253,8 +252,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -262,8 +261,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -272,12 +271,12 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@ -286,8 +285,6 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -323,31 +320,9 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/gorm v1.26.1 h1:ghB2gUI9FkS46luZtn6DLZ0f6ooBJ5IbVej2ENFDjRw=
gorm.io/gorm v1.26.1/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs=
gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
modernc.org/cc/v4 v4.26.1 h1:+X5NtzVBn0KgsBCBe+xkDC7twLb/jNVj9FPgiwSQO3s=
modernc.org/cc/v4 v4.26.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE=
modernc.org/fileutil v1.3.1 h1:8vq5fe7jdtEvoCf3Zf9Nm0Q05sH6kGx0Op2CPx1wTC8=
modernc.org/fileutil v1.3.1/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/libc v1.65.4 h1:8oVL/29p3e+ZvMv4nE1pryq5p8grHiFsU8bN8Eah/rs=
modernc.org/libc v1.65.4/go.mod h1:MOiGAM9lrMBT9L8xT1nO41qYl5eg9gCp9/kWhz5L7WA=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.10.0 h1:fzumd51yQ1DxcOxSO+S6X7+QTuVU+n8/Aj7swYjFfC4=
modernc.org/memory v1.10.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.37.0 h1:s1TMe7T3Q3ovQiK2Ouz4Jwh7dw4ZDqbebSDTlSJdfjI=
modernc.org/sqlite v1.37.0/go.mod h1:5YiWv+YviqGMuGw4V+PNplcyaJ5v+vQd7TQOgkACoJM=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=

View file

@ -15,7 +15,7 @@ type Config struct {
BehindProxy bool `env:"APP_BEHIND_PROXY"`
}
Database struct {
Location string `env:"DATABASE_LOCATION"`
DSN string `env:"DATABASE_DSN"`
}
Sessions struct {
Location string `env:"SESSIONS_LOCATION"`

View file

@ -2,7 +2,7 @@ package helpers
import (
"git.readonly.ch/bouzoure/pop-camarades/models"
"github.com/glebarez/sqlite"
"gorm.io/driver/postgres"
"gorm.io/gorm"
gormLogger "gorm.io/gorm/logger"
)
@ -30,7 +30,7 @@ func GetDatabase() (*gorm.DB, error) {
}
database, err = gorm.Open(
sqlite.Open(config.Database.Location),
postgres.Open(config.Database.DSN),
&gormConfig,
)
if err != nil {
@ -42,7 +42,8 @@ func GetDatabase() (*gorm.DB, error) {
return database, err
}
db.SetMaxOpenConns(1)
db.SetMaxIdleConns(10)
db.SetMaxOpenConns(50)
err = database.AutoMigrate(
&models.User{},

View file

@ -27,6 +27,8 @@ type PeopleSearchParams struct {
PageSize int `json:"-"`
PageNumber int `json:"-"`
AllowedSections []uint `json:"-"`
OrderColumn string `json:"-"`
OrderDirection string `json:"-"`
}
type PeopleSearchResults struct {
@ -43,16 +45,35 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
return results, nil
}
if strings.EqualFold(params.OrderDirection, "DESC") {
params.OrderDirection = "DESC"
} else {
params.OrderDirection = "ASC"
}
switch strings.ToLower(params.OrderColumn) {
case "address":
params.OrderColumn = "people.address1"
case "npa":
params.OrderColumn = "people.postal_code"
case "section":
params.OrderColumn = "people.section_id"
case "created":
params.OrderColumn = "people.created_at"
case "updated":
params.OrderColumn = "people.updated_at"
default:
params.OrderColumn = "CONCAT(people.last_name, people.first_name)"
}
// SQL qeury for results
sqlQuery := `--sql
SELECT people.*,
sections.name AS Section__name
sqlQuery := `
SELECT people.*
FROM people
INNER JOIN sections
ON people.section_id = sections.id`
`
// SQL query to count results
sqlQueryCount := `--sql
sqlQueryCount := `
SELECT people.id
FROM people
`
@ -62,7 +83,7 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
var sqlFilters string
// Filter: member or contact
sqlFilters = `--sql
sqlFilters = `
WHERE is_member = @is_member
AND is_contact = @is_contact
`
@ -78,11 +99,11 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
// Filter: name -> first_name + last_name
if len(params.Name) > 0 {
nameFilter := `--sql
people.first_name LIKE @name
OR people.last_name LIKE @name
OR CONCAT(people.first_name, ' ', people.last_name) LIKE @name
OR CONCAT(people.last_name, ' ', people.first_name) LIKE @name
nameFilter := `
LOWER(people.first_name) LIKE LOWER(@name)
OR LOWER(people.last_name) LIKE LOWER(@name)
OR LOWER(CONCAT(people.first_name, ' ', people.last_name)) LIKE LOWER(@name)
OR LOWER(CONCAT(people.last_name, ' ', people.first_name)) LIKE LOWER(@name)
`
sqlParams = append(sqlParams, sql.Named(
"name",
@ -92,10 +113,10 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
if strings.Contains(params.Name, " ") {
names := strings.Split(params.Name, " ")
for index, name := range names {
nameFilter = fmt.Sprintf(`--sql
nameFilter = fmt.Sprintf(`
%s
OR people.first_name LIKE @name_%d
OR people.last_name LIKE @name_%d
OR LOWER(people.first_name) LIKE LOWER(@name_%d)
OR LOWER(people.last_name) LIKE LOWER(@name_%d)
`, nameFilter, index, index)
sqlParams = append(sqlParams, sql.Named(
@ -105,7 +126,7 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
}
}
sqlFilters = fmt.Sprintf(`--sql
sqlFilters = fmt.Sprintf(`
%s
AND (%s)
`, sqlFilters, nameFilter)
@ -113,7 +134,7 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
// Filter: section
if params.Section > 0 {
sqlFilters = fmt.Sprintf(`--sql
sqlFilters = fmt.Sprintf(`
%s
AND people.section_id = @section
`, sqlFilters)
@ -122,7 +143,7 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
// Filter: active (only apply if archived is false)
if params.Active && !params.Archive {
sqlFilters = fmt.Sprintf(`--sql
sqlFilters = fmt.Sprintf(`
%s
AND people.deleted_at IS NULL
`, sqlFilters)
@ -130,7 +151,7 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
// Filter: archived (only apply if active is false)
if params.Archive && !params.Active {
sqlFilters = fmt.Sprintf(`--sql
sqlFilters = fmt.Sprintf(`
%s
AND people.deleted_at IS NOT NULL
`, sqlFilters)
@ -138,7 +159,7 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
// Filter: if both active and archived are turned off, return nothing
if !params.Archive && !params.Active {
sqlFilters = fmt.Sprintf(`--sql
sqlFilters = fmt.Sprintf(`
%s
AND 0=1
`, sqlFilters)
@ -146,9 +167,9 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
// Filters: email
if len(params.Email) > 0 {
sqlFilters = fmt.Sprintf(`--sql
sqlFilters = fmt.Sprintf(`
%s
AND people.email LIKE @email
AND LOWER(people.email) LIKE LOWER(@email)
`, sqlFilters)
sqlParams = append(sqlParams, sql.Named(
"email",
@ -158,35 +179,29 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
// Filters: phone
if len(params.Phone) > 0 {
params.Phone = strings.ReplaceAll(params.Phone, " ", "")
params.Phone = strings.ReplaceAll(params.Phone, "-", "")
params.Phone = strings.ReplaceAll(params.Phone, ".", "")
params.Phone = strings.ReplaceAll(params.Phone, "/", "")
params.Phone = strings.ReplaceAll(params.Phone, "+", "")
var phoneWithoutZeroFilter string
if string(params.Phone[0]) == "0" {
phoneWithoutZeroFilter = `
OR
TRANSLATE(people.phone, ' ,-,.,/,+', '') LIKE TRANSLATE(@phone2, ' ,-,.,/,+', '') OR
TRANSLATE(people.mobile, ' ,-,.,/,+', '') LIKE TRANSLATE(@phone2, ' ,-,.,/,+', '')
`
sqlFilters = fmt.Sprintf(`--sql
phone2 := params.Phone[1:]
sqlParams = append(sqlParams, sql.Named(
"phone2",
fmt.Sprintf("%%%s%%", phone2),
))
}
sqlFilters = fmt.Sprintf(`
%s
AND (
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(people.phone, ' ', '')
, '-', '')
, '.', '')
, '/', '')
, '+', '') LIKE @phone
OR REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(people.mobile, ' ', '')
, '-', '')
, '.', '')
, '/', '')
, '+', '') LIKE @phone
TRANSLATE(people.phone, ' ,-,.,/,+', '') LIKE TRANSLATE(@phone, ' ,-,.,/,+', '') OR
TRANSLATE(people.mobile, ' ,-,.,/,+', '') LIKE TRANSLATE(@phone, ' ,-,.,/,+', '')
%s
)
`, sqlFilters)
`, sqlFilters, phoneWithoutZeroFilter)
sqlParams = append(sqlParams, sql.Named(
"phone",
fmt.Sprintf("%%%s%%", params.Phone),
@ -195,7 +210,7 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
// Filters: address
if len(params.Address) > 0 {
sqlFilters = fmt.Sprintf(`--sql
sqlFilters = fmt.Sprintf(`
%s
AND (
people.address1 LIKE @address
@ -210,7 +225,7 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
// Filters: postal code
if len(params.PostalCode) > 0 {
sqlFilters = fmt.Sprintf(`--sql
sqlFilters = fmt.Sprintf(`
%s
AND people.postal_code = @postal_code
`, sqlFilters)
@ -222,7 +237,7 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
// Filters: city
if len(params.City) > 0 {
sqlFilters = fmt.Sprintf(`--sql
sqlFilters = fmt.Sprintf(`
%s
AND people.city LIKE @city
`, sqlFilters)
@ -233,7 +248,7 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
}
// Security filter: only show results in allowed secitons
sqlFilters = fmt.Sprintf(`--sql
sqlFilters = fmt.Sprintf(`
%s
AND people.section_id IN @allowed_sections
`, sqlFilters)
@ -250,7 +265,7 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
continue
}
sqlFieldJoins = fmt.Sprintf(`--sql
sqlFieldJoins = fmt.Sprintf(`
%s
LEFT JOIN field_values
AS field_%d
@ -271,36 +286,53 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
}
switch v := value.(type) {
default:
fmt.Println(v)
continue
case string:
filter = fmt.Sprintf(`--sql
if field.FieldType == "date" {
filter = fmt.Sprintf(`
%s
field_%d.value_string LIKE @field_%d_%d
OR field_%d.value_date LIKE @field_%d_%d
`, filter, field.ID, field.ID, index, field.ID, field.ID, index)
sqlParams = append(sqlParams, sql.Named(
fmt.Sprintf("field_%d_%d", field.ID, index),
fmt.Sprintf("%%%s%%", v),
))
case float64:
filter = fmt.Sprintf(`--sql
%s
field_%d.value_int = @field_%d_%d
OR field_%d.list_item_id = @field_%d_%d
`, filter, field.ID, field.ID, index, field.ID, field.ID, index)
TO_CHAR(field_%d.value_date, 'YYYY-MM-DD') = @field_%d_%d
`, filter, field.ID, field.ID, index)
sqlParams = append(sqlParams, sql.Named(
fmt.Sprintf("field_%d_%d", field.ID, index),
v,
))
} else {
filter = fmt.Sprintf(`
%s
LOWER(field_%d.value_string) LIKE LOWER(@field_%d_%d)
`, filter, field.ID, field.ID, index)
sqlParams = append(sqlParams, sql.Named(
fmt.Sprintf("field_%d_%d", field.ID, index),
fmt.Sprintf("%%%s%%", v),
))
}
case float64:
if field.FieldType == "list" {
filter = fmt.Sprintf(`
%s
field_%d.list_item_id = @field_%d_%d
`, filter, field.ID, field.ID, index)
sqlParams = append(sqlParams, sql.Named(
fmt.Sprintf("field_%d_%d", field.ID, index),
v,
))
} else {
filter = fmt.Sprintf(`
%s
field_%d.value_int = @field_%d_%d
`, filter, field.ID, field.ID, index)
sqlParams = append(sqlParams, sql.Named(
fmt.Sprintf("field_%d_%d", field.ID, index),
v,
))
}
}
fieldFilter = fmt.Sprintf("%s %s", fieldFilter, filter)
}
if fieldFilter != "" {
sqlFilters = fmt.Sprintf(`--sql
sqlFilters = fmt.Sprintf(`
%s
AND (%s)
`, sqlFilters, fieldFilter)
@ -308,7 +340,7 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
}
// Build and run count query
sqlQueryCount = fmt.Sprintf(`--sql
sqlQueryCount = fmt.Sprintf(`
%s
%s
%s
@ -330,7 +362,7 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
var sqlPagination string
if params.PageSize > 0 {
sqlPagination = `--sql
sqlPagination = `
LIMIT @pagination_limit
OFFSET @pagination_offset
`
@ -339,16 +371,16 @@ func PeopleSearch(params PeopleSearchParams) (PeopleSearchResults, error) {
}
// Build and run paginated result query
sqlQuery = fmt.Sprintf(`--sql
sqlQuery = fmt.Sprintf(`
%s
%s
%s
GROUP BY people.id
ORDER BY CONCAT(people.last_name, people.first_name) COLLATE NOCASE ASC
ORDER BY %s %s
%s
`, sqlQuery, sqlFieldJoins, sqlFilters, sqlPagination)
`, sqlQuery, sqlFieldJoins, sqlFilters, params.OrderColumn, params.OrderDirection, sqlPagination)
sqlResult := db.Raw(sqlQuery, sqlParams...).Scan(&results.Results)
sqlResult := db.Raw(sqlQuery, sqlParams...).Preload("Section").Find(&results.Results)
if sqlResult.Error != nil {
return results, sqlResult.Error
}

View file

@ -16,7 +16,7 @@ func FirstAccountCheck() (bool, error) {
}
var user models.User
result := db.First(&user, "is_admin = 1")
result := db.First(&user, "is_admin = ?", true)
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return false, nil

View file

@ -11,8 +11,8 @@ type Field struct {
Name string
PersonType string
FieldType string
ListID uint
List List
ListID *uint
List *List
Position int
}
@ -25,8 +25,8 @@ type FieldValue struct {
ValueString sql.NullString
ValueInt sql.NullInt64
ValueDate sql.NullTime
ListItemID uint
ListItem ListItem
ListItemID *uint
ListItem *ListItem
}
var PersonTypes = map[string]string{

View file

@ -6,7 +6,7 @@ type Section struct {
gorm.Model
Name string
ShortName string
ParentSectionID uint
ParentSectionID *uint
ParentSection *Section
ContainsMembers bool
ContainsContacts bool

View file

@ -8,8 +8,9 @@
"url": "https://git.readonly.ch/bouzoure/pop-camarades"
},
"devDependencies": {
"parcel": "^2.15.0",
"prettier": "^3.5.3",
"@parcel/transformer-sass": "2.15.4",
"parcel": "^2.15.4",
"prettier": "^3.6.2",
"prettier-plugin-jinja-template": "^2.1.0"
},
"source": "frontend/index.js",
@ -31,7 +32,7 @@
"build": "go build"
},
"dependencies": {
"bootstrap": "^5.3.6",
"bootstrap": "^5.3.7",
"bootstrap-icons": "^1.13.1",
"jquery": "^3.7.1"
}

1244
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -688,9 +688,9 @@ Public License instead of this License. But first, please read
## github.com/andybalholm/brotli
* Name: github.com/andybalholm/brotli
* Version: v1.1.1
* Version: v1.2.0
* License: [MIT](https://github.com/andybalholm/brotli/blob/v1.1.1/LICENSE)
* License: [MIT](https://github.com/andybalholm/brotli/blob/v1.2.0/LICENSE)
```
@ -785,9 +785,9 @@ SOFTWARE.
## github.com/brianvoe/gofakeit/v7
* Name: github.com/brianvoe/gofakeit/v7
* Version: v7.2.1
* Version: v7.3.0
* License: [MIT](https://github.com/brianvoe/gofakeit/blob/v7.2.1/LICENSE.txt)
* License: [MIT](https://github.com/brianvoe/gofakeit/blob/v7.3.0/LICENSE.txt)
```
@ -950,9 +950,9 @@ SOFTWARE.
## github.com/charmbracelet/log
* Name: github.com/charmbracelet/log
* Version: v0.4.1
* Version: v0.4.2
* License: [MIT](https://github.com/charmbracelet/log/blob/v0.4.1/LICENSE)
* License: [MIT](https://github.com/charmbracelet/log/blob/v0.4.2/LICENSE)
```
@ -983,9 +983,9 @@ SOFTWARE.
## github.com/charmbracelet/x/ansi
* Name: github.com/charmbracelet/x/ansi
* Version: v0.9.2
* Version: v0.9.3
* License: [MIT](https://github.com/charmbracelet/x/blob/ansi/v0.9.2/ansi/LICENSE)
* License: [MIT](https://github.com/charmbracelet/x/blob/ansi/v0.9.3/ansi/LICENSE)
```
@ -1629,77 +1629,6 @@ SOFTWARE.
```
## github.com/glebarez/go-sqlite
* Name: github.com/glebarez/go-sqlite
* Version: v1.22.0
* License: [BSD-3-Clause](https://github.com/glebarez/go-sqlite/blob/v1.22.0/LICENSE)
```
Copyright (c) 2017 The Sqlite Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
## github.com/glebarez/sqlite
* Name: github.com/glebarez/sqlite
* Version: v1.11.0
* License: [MIT](https://github.com/glebarez/sqlite/blob/v1.11.0/License)
```
The MIT License (MIT)
Copyright (c) 2013-NOW Jinzhu <wosmvp@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
```
## github.com/go-logfmt/logfmt
* Name: github.com/go-logfmt/logfmt
@ -1802,9 +1731,9 @@ SOFTWARE.
## github.com/go-playground/validator/v10
* Name: github.com/go-playground/validator/v10
* Version: v10.26.0
* Version: v10.27.0
* License: [MIT](https://github.com/go-playground/validator/blob/v10.26.0/LICENSE)
* License: [MIT](https://github.com/go-playground/validator/blob/v10.27.0/LICENSE)
```
@ -1836,9 +1765,9 @@ SOFTWARE.
## github.com/gofiber/fiber/v2
* Name: github.com/gofiber/fiber/v2
* Version: v2.52.6
* Version: v2.52.8
* License: [MIT](https://github.com/gofiber/fiber/blob/v2.52.6/LICENSE)
* License: [MIT](https://github.com/gofiber/fiber/blob/v2.52.8/LICENSE)
```
@ -1869,9 +1798,9 @@ SOFTWARE.
## github.com/gofiber/fiber/v2/internal/schema
* Name: github.com/gofiber/fiber/v2/internal/schema
* Version: v2.52.6
* Version: v2.52.8
* License: [BSD-3-Clause](https://github.com/gofiber/fiber/blob/v2.52.6/internal/schema/LICENSE)
* License: [BSD-3-Clause](https://github.com/gofiber/fiber/blob/v2.52.8/internal/schema/LICENSE)
```
@ -2007,9 +1936,9 @@ SOFTWARE.
## github.com/gofiber/template/django/v3
* Name: github.com/gofiber/template/django/v3
* Version: v3.1.13
* Version: v3.1.14
* License: [MIT](https://github.com/gofiber/template/blob/django/v3.1.13/django/LICENSE)
* License: [MIT](https://github.com/gofiber/template/blob/django/v3.1.14/django/LICENSE)
```
@ -2073,9 +2002,9 @@ SOFTWARE.
## github.com/gofiber/utils/v2
* Name: github.com/gofiber/utils/v2
* Version: v2.0.0-beta.8
* Version: v2.0.0-beta.10
* License: [MIT](https://github.com/gofiber/utils/blob/v2.0.0-beta.8/LICENSE)
* License: [MIT](https://github.com/gofiber/utils/blob/v2.0.0-beta.10/LICENSE)
```
@ -2751,6 +2680,142 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
## github.com/jackc/pgpassfile
* Name: github.com/jackc/pgpassfile
* Version: v1.0.0
* License: [MIT](https://github.com/jackc/pgpassfile/blob/v1.0.0/LICENSE)
```
Copyright (c) 2019 Jack Christensen
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
```
## github.com/jackc/pgservicefile
* Name: github.com/jackc/pgservicefile
* Version: v0.0.0-20240606120523-5a60cdf6a761
* License: [MIT](https://github.com/jackc/pgservicefile/blob/5a60cdf6a761/LICENSE)
```
Copyright (c) 2020 Jack Christensen
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
```
## github.com/jackc/pgx/v5
* Name: github.com/jackc/pgx/v5
* Version: v5.7.5
* License: [MIT](https://github.com/jackc/pgx/blob/v5.7.5/LICENSE)
```
Copyright (c) 2013-2021 Jack Christensen
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
```
## github.com/jackc/puddle/v2
* Name: github.com/jackc/puddle/v2
* Version: v2.2.2
* License: [MIT](https://github.com/jackc/puddle/blob/v2.2.2/LICENSE)
```
Copyright (c) 2018 Jack Christensen
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
```
## github.com/jinzhu/inflection
* Name: github.com/jinzhu/inflection
@ -3416,9 +3481,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
## github.com/pquerna/otp
* Name: github.com/pquerna/otp
* Version: v1.4.0
* Version: v1.5.0
* License: [Apache-2.0](https://github.com/pquerna/otp/blob/v1.4.0/LICENSE)
* License: [Apache-2.0](https://github.com/pquerna/otp/blob/v1.5.0/LICENSE)
```
@ -3627,45 +3692,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
## github.com/remyoudompheng/bigfft
* Name: github.com/remyoudompheng/bigfft
* Version: v0.0.0-20230129092748-24d4a6f8daec
* License: [BSD-3-Clause](https://github.com/remyoudompheng/bigfft/blob/24d4a6f8daec/LICENSE)
```
Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
## github.com/rivo/uniseg
* Name: github.com/rivo/uniseg
@ -3736,9 +3762,9 @@ SOFTWARE.
## github.com/valyala/fasthttp
* Name: github.com/valyala/fasthttp
* Version: v1.62.0
* Version: v1.63.0
* License: [MIT](https://github.com/valyala/fasthttp/blob/v1.62.0/LICENSE)
* License: [MIT](https://github.com/valyala/fasthttp/blob/v1.63.0/LICENSE)
```
@ -3757,9 +3783,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
## github.com/valyala/fasthttp/reuseport
* Name: github.com/valyala/fasthttp/reuseport
* Version: v1.62.0
* Version: v1.63.0
* License: [MIT](https://github.com/valyala/fasthttp/blob/v1.62.0/reuseport/LICENSE)
* License: [MIT](https://github.com/valyala/fasthttp/blob/v1.63.0/reuseport/LICENSE)
```
@ -3822,9 +3848,9 @@ SOFTWARE.
## github.com/yuin/goldmark
* Name: github.com/yuin/goldmark
* Version: v1.7.11
* Version: v1.7.12
* License: [MIT](https://github.com/yuin/goldmark/blob/v1.7.11/LICENSE)
* License: [MIT](https://github.com/yuin/goldmark/blob/v1.7.12/LICENSE)
```
@ -4068,48 +4094,9 @@ SOFTWARE.
## golang.org/x/crypto
* Name: golang.org/x/crypto
* Version: v0.38.0
* Version: v0.40.0
* License: [BSD-3-Clause](https://cs.opensource.google/go/x/crypto/+/v0.38.0:LICENSE)
```
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
## golang.org/x/exp/constraints
* Name: golang.org/x/exp/constraints
* Version: v0.0.0-20250506013437-ce4c2cf36ca6
* License: [BSD-3-Clause](https://cs.opensource.google/go/x/exp/+/ce4c2cf3:LICENSE)
* License: [BSD-3-Clause](https://cs.opensource.google/go/x/crypto/+/v0.40.0:LICENSE)
```
@ -4146,9 +4133,48 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
## golang.org/x/net
* Name: golang.org/x/net
* Version: v0.40.0
* Version: v0.42.0
* License: [BSD-3-Clause](https://cs.opensource.google/go/x/net/+/v0.40.0:LICENSE)
* License: [BSD-3-Clause](https://cs.opensource.google/go/x/net/+/v0.42.0:LICENSE)
```
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
## golang.org/x/sync/semaphore
* Name: golang.org/x/sync/semaphore
* Version: v0.16.0
* License: [BSD-3-Clause](https://cs.opensource.google/go/x/sync/+/v0.16.0:LICENSE)
```
@ -4185,9 +4211,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
## golang.org/x/sys
* Name: golang.org/x/sys
* Version: v0.33.0
* Version: v0.34.0
* License: [BSD-3-Clause](https://cs.opensource.google/go/x/sys/+/v0.33.0:LICENSE)
* License: [BSD-3-Clause](https://cs.opensource.google/go/x/sys/+/v0.34.0:LICENSE)
```
@ -4224,9 +4250,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
## golang.org/x/text
* Name: golang.org/x/text
* Version: v0.25.0
* Version: v0.27.0
* License: [BSD-3-Clause](https://cs.opensource.google/go/x/text/+/v0.25.0:LICENSE)
* License: [BSD-3-Clause](https://cs.opensource.google/go/x/text/+/v0.27.0:LICENSE)
```
@ -4299,12 +4325,45 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
## gorm.io/driver/postgres
* Name: gorm.io/driver/postgres
* Version: v1.6.0
* License: [MIT](https://github.com/go-gorm/postgres/blob/v1.6.0/License)
```
The MIT License (MIT)
Copyright (c) 2013-NOW Jinzhu <wosmvp@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
```
## gorm.io/gorm
* Name: gorm.io/gorm
* Version: v1.26.1
* Version: v1.30.0
* License: [MIT](https://github.com/go-gorm/gorm/blob/v1.26.1/LICENSE)
* License: [MIT](https://github.com/go-gorm/gorm/blob/v1.30.0/LICENSE)
```
@ -4332,131 +4391,3 @@ THE SOFTWARE.
```
## modernc.org/libc
* Name: modernc.org/libc
* Version: v1.65.4
* License: [BSD-3-Clause](https://gitlab.com/cznic/libc/blob/v1.65.4/LICENSE-GO)
```
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
## modernc.org/mathutil
* Name: modernc.org/mathutil
* Version: v1.7.1
* License: Unknown
```
```
## modernc.org/memory
* Name: modernc.org/memory
* Version: v1.10.0
* License: [BSD-3-Clause](https://gitlab.com/cznic/memory/blob/v1.10.0/LICENSE-GO)
```
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
## modernc.org/sqlite/lib
* Name: modernc.org/sqlite/lib
* Version: v1.37.0
* License: [BSD-3-Clause](https://gitlab.com/cznic/sqlite/blob/v1.37.0/LICENSE)
```
Copyright (c) 2017 The Sqlite Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -12,6 +12,7 @@
<hr />
</div>
<form id="account" method="post" style="max-width: 1200px;">
{% if Errors %}
<div class="alert alert-danger">
<ul class="m-0">
@ -22,10 +23,11 @@
</div>
{% endif %}
<form id="account" method="post">
<div class="row mb-3">
<label for="name" class="col-md-2 form-label"> Nom complet </label>
<div class="col-md-10">
<label for="name" class="col-md-2 col-xl-3 form-label">
Nom complet
</label>
<div class="col-md-10 col-xl-9">
<input
id="name"
class="form-control"
@ -40,8 +42,8 @@
</div>
<div class="row mb-3">
<label for="email" class="col-md-2 form-label"> Email </label>
<div class="col-md-10">
<label for="email" class="col-md-2 col-xl-3 form-label"> Email </label>
<div class="col-md-10 col-xl-9">
<input
id="email"
class="form-control"
@ -55,8 +57,10 @@
</div>
<div class="row mb-3">
<label for="password" class="col-md-2 form-label"> Mot de passe </label>
<div class="col-md-10">
<label for="password" class="col-md-2 col-xl-3 form-label">
Mot de passe
</label>
<div class="col-md-10 col-xl-9">
<input
id="password"
class="form-control"
@ -69,10 +73,10 @@
</div>
<div class="row mb-3">
<label for="password" class="col-md-2 form-label">
<label for="password" class="col-md-2 col-xl-3 form-label">
Confirmer le mot de passe
</label>
<div class="col-md-10">
<div class="col-md-10 col-xl-9">
<input
id="password-verify"
class="form-control"

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -12,45 +12,84 @@
<hr />
</div>
<div class="row">
<div class="col-md-6">
<div class="row mw-900">
<div class="col-12">
<a class="dashboard-tile" href="/admin/sections">
<div class="alert alert-primary">
<div class="row align-items-center">
<div class="col-12 text-center text-md-start col-md-6">
<i class="bi-building me-2"></i>
Gestion des sections
</div>
<div class="col text-center text-md-end fs-1">
{{ SectionsCount }}
</div>
</div>
</div>
</a>
</div>
<div class="col-md-6">
<div class="col-12">
<a class="dashboard-tile" href="/admin/lists">
<div class="alert alert-primary">
<div class="row align-items-center">
<div class="col-12 text-center text-md-start col-md-6">
<i class="bi-list-check me-2"></i>
Gestion des listes
</div>
<div class="col text-center text-md-end fs-1">
{{ ListsCount }}
</div>
</div>
</div>
</a>
</div>
<div class="col-md-6">
<div class="col-12">
<a class="dashboard-tile" href="/admin/fields">
<div class="alert alert-primary">
<div class="row align-items-center">
<div class="col-12 text-center text-md-start col-md-6">
<i class="bi-database-add me-2"></i>
Gestion des champs supplémentaires
</div>
<div class="col text-center text-md-end fs-1">
{{ FieldsCount }}
</div>
</div>
</div>
</a>
</div>
<div class="col-md-6">
<div class="col-12">
<a class="dashboard-tile" href="/admin/users">
<div class="alert alert-primary">
<div class="row align-items-center">
<div class="col-12 text-center text-md-start col-md-6">
<i class="bi-person-square me-2"></i>
Gestion des utilisateurs
</div>
<div class="col text-center text-md-end fs-1">
{{ UsersCount }}
</div>
</div>
</div>
</a>
</div>
<div class="col-md-6">
<div class="col-12">
<a class="dashboard-tile" href="/admin/roles">
<div class="alert alert-primary">
<div class="row align-items-center">
<div class="col-12 text-center text-md-start col-md-6">
<i class="bi-briefcase me-2"></i>
Gestion des rôles
</div>
<div class="col text-center text-md-end fs-1">
{{ RolesCount }}
</div>
</div>
</div>
</a>
</div>
</div>

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container text-center py-5">
<div class="container-fluid my-4 px-4 text-center py-5">
<div class="h1 mb-3">Erreur {{ Code }}</div>
<code>{{ Message }}</code>
</div>

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -16,7 +16,8 @@
<hr />
</div>
<div class="row mb-3">
<div class="mw-1200">
<div class="row align-items-center mb-3">
<div class="col-md-2">Nom du champ</div>
<div class="col-md-10">
<input
@ -29,7 +30,7 @@
</div>
</div>
<div class="row mb-3">
<div class="row align-items-center mb-3">
<div class="col-md-2">Population</div>
<div class="col-md-10">
{% for Key, Value in PersonTypes %}
@ -46,7 +47,7 @@
</div>
</div>
<div class="row mb-3">
<div class="row align-items-center mb-3">
<div class="col-md-2">Type de champ</div>
<div class="col-md-10">
{% for Key, Value in FieldTypes %}
@ -63,7 +64,7 @@
</div>
</div>
<div class="row mb-3">
<div class="row align-items-center mb-3">
<div class="col-md-2">Liste</div>
<div class="col-md-10">
{% if Field.ListID %}
@ -93,7 +94,7 @@
</div>
</div>
<div class="row my-4">
<div class="row align-items-center my-4">
<div class="col-6">
<a
class="btn btn-outline-primary"
@ -116,6 +117,7 @@
</div>
</div>
</div>
</div>
<div id="modal-delete" class="modal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -24,6 +24,7 @@
<hr />
</div>
<form id="field" method="post" class="mw-1200">
{% if Errors %}
<div class="alert alert-danger">
<ul class="m-0">
@ -34,9 +35,10 @@
</div>
{% endif %}
<form id="field" method="post">
<div class="row mb-3">
<label for="name" class="form-label col-md-2"> Nom du champ </label>
<div class="row align-items-center mb-3">
<label for="name" class="form-label mb-0 col-md-2">
Nom du champ
</label>
<div class="col-md-10">
<input
id="name"
@ -52,8 +54,8 @@
</div>
{% if !Field.ID %}
<div class="row mb-3">
<label for="person_type" class="form-label col-md-2">
<div class="row align-items-center mb-3">
<label for="person_type" class="form-label mb-0 col-md-2">
Population
</label>
<div class="col-md-10">
@ -65,13 +67,13 @@
required
>
<option value="member">Membre</option>
<option value="contact">Contact</option>
<option value="contact">Sympathisant</option>
</select>
</div>
</div>
<div class="row mb-3">
<label for="field_type" class="form-label col-md-2">
<div class="row align-items-center mb-3">
<label for="field_type" class="form-label mb-0 col-md-2">
Type de champ
</label>
<div class="col-md-10">
@ -91,8 +93,8 @@
</div>
</div>
<div class="row mb-3">
<label for="list" class="form-label col-md-2"> Liste </label>
<div class="row align-items-center mb-3">
<label for="list" class="form-label mb-0 col-md-2"> Liste </label>
<div class="col-md-10">
<select
name="list"

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container my-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -13,88 +13,47 @@
<hr />
</div>
<div class="my-3 text-end">
<div class="row my-3">
<div class="col-sm-6">
<span class="h2 d-none d-sm-inline">Champs supplémentaires</span>
</div>
<div class="col-sm-6 text-end">
<a class="btn btn-outline-primary" href="/admin/fields/add">
<i class="bi-plus-lg"></i>
Ajouter
</a>
</div>
</div>
<div class="h4 my-2">Membres</div>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th class="w-50">Nom</th>
<th class="w-25">Type de champ</th>
<th class="w-25"></th>
</tr>
</thead>
<tbody>
<div class="card mb-3">
<div class="card-header">Membres</div>
<div class="card-body">
{% for Field in Fields %}
{% if Field.PersonType == "member" %}
<tr>
<td>
<a href="/admin/fields/{{ Field.ID }}"> {{ Field.Name }} </a>
</td>
<td>
{% for Key, Value in FieldTypes %}
{% if Key == Field.FieldType %}
{{ Value }}
{% endif %}
{% endfor %}
</td>
<td class="text-end">
<div class="btn-group">
<a
class="btn btn-sm btn-outline-primary"
href="/admin/fields/{{ Field.ID }}/move-up"
>
<i class="bi-arrow-up me-1"></i>
Monter
</a>
<a
class="btn btn-sm btn-outline-primary"
href="/admin/fields/{{ Field.ID }}/move-down"
>
<i class="bi-arrow-down me-1"></i>
Descendre
<div class="card card-body my-2 py-2 bg-body-tertiary">
<div class="row align-items-center">
<div class="col-12 col-md-8 col-lg-6">
<div class="text-bold fs-7 mt-xxl-0 mt-2">Nom</div>
<div>
<a href="/admin/fields/{{ Field.ID }}">
{{ Field.Name }}
</a>
</div>
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
<div class="h4 my-2">Contacts</div>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th class="w-50">Nom</th>
<th class="w-25">Type de champ</th>
<th class="w-25"></th>
</tr>
</thead>
<tbody>
{% for Field in Fields %}
{% if Field.PersonType == "contact" %}
<tr>
<td>
<a href="/admin/fields/{{ Field.ID }}"> {{ Field.Name }} </a>
</td>
<td>
<div class="col-12 col-md-4 col-lg-3">
<div class="text-bold fs-7 mt-xxl-0 mt-2">Type de champ</div>
<div>
{% for Key, Value in FieldTypes %}
{% if Key == Field.FieldType %}
{{ Value }}
<span class="badge text-bg-primary"> {{ Value }} </span>
{% endif %}
{% endfor %}
</td>
<td class="text-end">
<div class="btn-group">
</div>
</div>
<div class="col text-lg-end">
<div class="btn-group mb-2 mt-3 mt-lg-0 mb-lg-0">
<a
class="btn btn-sm btn-outline-primary"
href="/admin/fields/{{ Field.ID }}/move-up"
@ -110,12 +69,64 @@
Descendre
</a>
</div>
</td>
</tr>
</div>
</div>
</div>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="card">
<div class="card-header">Sympathisants</div>
<div class="card-body">
{% for Field in Fields %}
{% if Field.PersonType == "contact" %}
<div class="card card-body my-2 py-2 bg-body-tertiary">
<div class="row align-items-center">
<div class="col-12 col-md-8 col-lg-6">
<div class="text-bold fs-7 mt-xxl-0 mt-2">Nom</div>
<div>
<a href="/admin/fields/{{ Field.ID }}">
{{ Field.Name }}
</a>
</div>
</div>
<div class="col-12 col-md-4 col-lg-3">
<div class="text-bold fs-7 mt-xxl-0 mt-2">Type de champ</div>
<div>
{% for Key, Value in FieldTypes %}
{% if Key == Field.FieldType %}
<span class="badge text-bg-primary"> {{ Value }} </span>
{% endif %}
{% endfor %}
</div>
</div>
<div class="col text-lg-end">
<div class="btn-group mb-2 mt-3 mt-lg-0 mb-lg-0">
<a
class="btn btn-sm btn-outline-primary"
href="/admin/fields/{{ Field.ID }}/move-up"
>
<i class="bi-arrow-up me-1"></i>
Monter
</a>
<a
class="btn btn-sm btn-outline-primary"
href="/admin/fields/{{ Field.ID }}/move-down"
>
<i class="bi-arrow-down me-1"></i>
Descendre
</a>
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
</div>
</div>
</div>
{% endblock %}

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -11,36 +11,57 @@
<hr />
</div>
<div class="row">
<div class="row mw-900">
{% if Globals.AllowMembersPage %}
<div class="col-md-6">
<div class="col-12">
<a class="dashboard-tile" href="/members">
<div class="alert alert-primary">
<div class="row align-items-center">
<div class="col-12 text-center text-md-start col-md-6">
<i class="bi-people me-2"></i>
Gestion des membres
</div>
<div class="col text-center text-md-end fs-1">
{{ MembersCount }}
</div>
</div>
</div>
</a>
</div>
{% endif %}
{% if Globals.AllowContactsPage %}
<div class="col-md-6">
<div class="col-12">
<a class="dashboard-tile" href="/contacts">
<div class="alert alert-primary">
<div class="row align-items-center">
<div class="col-12 text-center text-md-start col-md-6">
<i class="bi-telephone me-2"></i>
Gestion des contacts
Gestion des sympathisants
</div>
<div class="col text-center text-md-end fs-1">
{{ ContactsCount }}
</div>
</div>
</div>
</a>
</div>
{% endif %}
{% if Globals.UserIsAdmin %}
<div class="col-md-6">
<div class="col-12">
<a class="dashboard-tile" href="/admin">
<div class="alert alert-primary">
<div class="row align-items-center">
<div class="col-12 text-center text-md-start col-md-6">
<i class="bi-gear me-2"></i>
Administration de l'application
</div>
<div class="col text-center text-md-end fs-1">
<i class="bi-arrow-right"></i>
</div>
</div>
</div>
</a>
</div>
{% endif %}

View file

@ -35,7 +35,7 @@
</main>
<footer class="footer mt-auto py-2 bg-body-tertiary">
<div class="container">
<div class="container-fluid">
<span class="text-body-secondary">
<a
class="text-body-secondary me-2"

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container my-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -14,9 +14,10 @@
<hr />
</div>
<div class="row mb-3">
<div class="col-md-2">Nom</div>
<div class="col-md-10">
<div class="mw-1200">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Nom</div>
<div class="col-md-10 col-xl-9">
<input
type="text"
class="form-control"
@ -27,9 +28,9 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Liste à choix multiples</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Liste à choix multiples</div>
<div class="col-md-10 col-xl-9">
{% if List.Multi %}
<div class="input-group">
<span class="input-group-text">
@ -48,7 +49,38 @@
</div>
</div>
<div class="my-4 row">
<div class="p-3 my-4 bg-body-tertiary border">
<div class="mb-3">
<span class="h5">Liste</span>
</div>
{% if ListItems %}
<ul class="p-0" style="list-style: none;">
{% for Item in ListItems %}
<li>
<a href="/admin/lists/{{ List.ID }}/items/{{ Item.ID }}">
{{ Item.Value }}
</a>
{% if Item.Default %}
<span class="badge text-bg-success">Par défaut</span>
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
<div class="mb-4">Pas encore d'éléments dans cette liste</div>
{% endif %}
<a
class="btn btn-outline-primary"
href="/admin/lists/{{ List.ID }}/items/add"
>
<i class="bi-plus-lg"></i>
Ajouter
</a>
</div>
<div class="my-4 row align-items-center">
<div class="col-6">
<a
class="btn btn-outline-primary"
@ -70,68 +102,9 @@
</button>
</div>
</div>
<div class="my-3 row">
<div class="col-sm-9 h4">Contenu de la liste</div>
<div class="col-sm-3 text-end">
<a
class="btn btn-outline-primary"
href="/admin/lists/{{ List.ID }}/items/add"
>
<i class="bi-plus-lg"></i>
Ajouter
</a>
</div>
</div>
{% if ListItems %}
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th class="w-50">Valeur</th>
<th class="w-25">Par défaut</th>
<th class="w-25"></th>
</tr>
</thead>
<tbody>
{% for Item in ListItems %}
<tr>
<td>
<a href="/admin/lists/{{ List.ID }}/items/{{ Item.ID }}">
{{ Item.Value }}
</a>
</td>
<td>
{% if Item.Default %}
<i class="bi-check-lg text-success me-1"></i>
Oui
{% else %}
<i class="bi-x-lg text-danger me-1"></i>
Non
{% endif %}
</td>
<td class="text-end">
<button
type="button"
class="btn btn-outline-danger btn-sm"
data-bs-toggle="modal"
data-bs-target="#modal-delete-value-{{ Item.ID }}"
>
<i class="bi-trash3 me-1"></i>
Supprimer
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div>Pas encore d'éléments dans cette liste.</div>
{% endif %}
</div>
<div id="modal-delete" class="modal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
@ -162,37 +135,4 @@
</div>
</div>
</div>
{% for Item in ListItems %}
<div id="modal-delete-value-{{ Item.ID }}" class="modal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-body">
<p>Êtes-vous sûr de vouloir supprimer cette valeur ?</p>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-outline-secondary"
data-bs-dismiss="modal"
>
<i class="bi-x-lg me-1"></i>
Annuler
</button>
<form
action="/admin/lists/{{ List.ID }}/items/{{ Item.ID }}/delete"
method="post"
class="d-inline p-0"
>
<button class="btn btn-outline-danger" type="submit">
<i class="bi-trash3 me-1"></i>
Supprimer
</button>
</form>
</div>
</div>
</div>
</div>
{% endfor %}
{% endblock %}

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -22,6 +22,7 @@
<hr />
</div>
<form id="list" method="post" class="mw-1200">
{% if Errors %}
<div class="alert alert-danger">
<ul class="m-0">
@ -32,10 +33,11 @@
</div>
{% endif %}
<form id="list" method="post">
<div class="row mb-3">
<label for="name" class="form-label col-md-2"> Nom </label>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<label for="name" class="form-label mb-0 col-md-2 col-xl-3">
Nom
</label>
<div class="col">
<input
id="name"
class="form-control"
@ -49,8 +51,8 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="row align-items-center mb-3">
<div class="col-md-10 offset-md-2 offset-xl-3">
<input
type="checkbox"
class="form-check-input me-2"

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -22,6 +22,7 @@
<hr />
</div>
<form id="listitem" method="post" class="mw-900">
{% if Errors %}
<div class="alert alert-danger">
<ul class="m-0">
@ -32,9 +33,8 @@
</div>
{% endif %}
<form id="listitem" method="post">
<div class="row mb-3">
<label for="value" class="form-label col-md-2"> Valeur </label>
<div class="row align-items-center mb-3">
<label for="value" class="form-label mb-0 col-md-2"> Valeur </label>
<div class="col-md-10">
<input
id="value"
@ -49,7 +49,7 @@
</div>
</div>
<div class="row mb-3">
<div class="row align-items-center mb-3">
<div class="col-md-10 offset-md-2">
<input
type="checkbox"
@ -67,12 +67,60 @@
</div>
</div>
<div class="my-4">
<div class="my-4 row align-items-center">
<div class="col-6">
<button class="btn btn-outline-primary" type="submit">
<i class="me-1 bi-floppy"></i>
Enregistrer
</button>
</div>
<div class="col-6 text-end">
{% if ListItem.ID %}
<button
type="button"
class="btn btn-outline-danger"
data-bs-toggle="modal"
data-bs-target="#modal-delete"
>
<i class="bi-trash3 me-1"></i>
Supprimer
</button>
{% endif %}
</div>
</div>
</form>
</div>
{% if ListItem.ID %}
<div id="modal-delete" class="modal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-body">
<p>Êtes-vous sûr de vouloir supprimer cette valeur ?</p>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-outline-secondary"
data-bs-dismiss="modal"
>
<i class="bi-x-lg me-1"></i>
Annuler
</button>
<form
action="/admin/lists/{{ List.ID }}/items/{{ ListItem.ID }}/delete"
method="post"
class="d-inline p-0"
>
<button class="btn btn-outline-danger" type="submit">
<i class="bi-trash3 me-1"></i>
Supprimer
</button>
</form>
</div>
</div>
</div>
</div>
{% endif %}
{% endblock %}

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container my-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -13,42 +13,42 @@
<hr />
</div>
<div class="my-3 text-end">
<div class="row my-3">
<div class="col-sm-6">
<span class="h2 d-none d-sm-inline">Listes</span>
</div>
<div class="col-sm-6 text-end">
<a class="btn btn-outline-primary" href="/admin/lists/add">
<i class="bi-plus-lg"></i>
Ajouter
</a>
</div>
</div>
{% if Lists %}
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th class="w-75">Nom</th>
<th class="w-25">Choix multiples</th>
</tr>
</thead>
<tbody>
{% for List in Lists %}
<tr>
<td>
<div class="card card-body my-2 py-2 bg-body-tertiary">
<div class="row">
<div class="col-12 col-sm-8 col-md-9 col-xl-6">
<div class="text-bold fs-7 mt-xxl-0 mt-2">Nom</div>
<div>
<a href="/admin/lists/{{ List.ID }}"> {{ List.Name }} </a>
</td>
<td>
{% if List.Multi %}
<i class="bi-check-lg text-success me-1"></i>
Oui
{% else %}
<i class="bi-x-lg text-danger me-1"></i>
Non
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="col">
<div class="text-bold fs-7 mt-xxl-0 mt-2">Choix multiples</div>
<div>
{% if List.Multi %}
<span class="badge text-bg-success">Oui</span>
{% else %}
<span class="badge text-bg-danger">Non</span>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
{% else %}
<div class="my-4">Pas de liste pour le moment</div>
{% endif %}

View file

@ -33,7 +33,7 @@
{% if Globals.AllowContactsPage %}
<li class="nav-item">
<a class="nav-link active" href="/contacts">
<i class="bi-telephone me-2"></i>Contacts
<i class="bi-telephone me-2"></i>Sympathisants
</a>
</li>
{% endif %}

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container my-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -10,14 +10,22 @@
{% if MembersPage %}
<li class="breadcrumb-item active">Membres</li>
{% else %}
<li class="breadcrumb-item active">Contacts</li>
<li class="breadcrumb-item active">Sympathisants</li>
{% endif %}
</ol>
</nav>
<hr />
</div>
<div class="my-3 text-end">
<div class="row my-3">
<div class="col-sm-6">
{% if MembersPage %}
<span class="h2 d-none d-sm-inline">Membres</span>
{% else %}
<span class="h2 d-none d-sm-inline">Sympathisants</span>
{% endif %}
</div>
<div class="col-sm-6 text-end">
{% if MembersPage %}
<div class="btn-group">
<a class="btn btn-outline-primary" href="/members/add">
@ -48,11 +56,9 @@
</div>
{% endif %}
</div>
</div>
<div
id="search-container"
class="h-100 p-4 mb-3 bg-body-tertiary border rounded-3"
>
<div id="search-container" class="h-100 p-4 mb-3 bg-body-tertiary border">
<div class="row">
<div class="col-lg-6 mb-3">
<label for="name" class="form-label">Nom et prénom</label>
@ -83,11 +89,10 @@
</div>
<div class="col-sm-6 col-lg-3 mb-3 pt-3">
{% if PermShow %}
<div class="form-check form-switch">
<div class="form-check">
<input
class="form-check-input"
type="checkbox"
role="switch"
data-search-field="active"
data-search-advanced="false"
id="active"
@ -99,18 +104,17 @@
>
{% else %}
<label class="form-check-label" for="active"
>Afficher contacts actifs</label
>Afficher sympathisants actifs</label
>
{% endif %}
</div>
{% endif %}
{% if PermShowArchived %}
<div class="form-check form-switch">
<div class="form-check">
<input
class="form-check-input"
type="checkbox"
role="switch"
data-search-field="archive"
data-search-advanced="false"
id="archive"
@ -121,7 +125,7 @@
>
{% else %}
<label class="form-check-label" for="archive"
>Afficher contacts archivés</label
>Afficher sympathisants archivés</label
>
{% endif %}
</div>
@ -208,7 +212,7 @@
</div>
<div class="row mt-2">
<div class="col-6">
<div class="col-12 col-sm-8 col-md-6 d-grid d-sm-block">
<button
class="btn btn-outline-primary"
id="advanced"
@ -225,7 +229,7 @@
<i class="bi-arrow-clockwise me-1"></i> Réinitialiser
</button>
</div>
<div class="col-6 text-end">
<div class="col-12 col-sm-4 col-md-6 text-end d-grid d-sm-block">
<button class="btn btn-outline-success" id="search" type="button">
<i class="bi-search me-1"></i> Recherche
</button>
@ -248,19 +252,146 @@
</form>
</div>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th class="w-25">Nom</th>
<th class="w-50 d-none d-sm-table-cell">Adresse</th>
<th class="w-25">Section</th>
</tr>
</thead>
<tbody>
<div>
<div class="card card-body my-2 py-2 bg-body-tertiary">
<div class="row">
<div
class="col-xxl col-lg-4 col-md-6 order-1 order-md-1 order-lg-1 order-xxl-1"
>
<div class="text-bold fs-7 mt-xxl-0 mt-2">
{% if OrderCol == "name" || OrderCol == "" %}
{% if OrderDir == "asc" || OrderDir == "" %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=name&o=desc">
Nom <i class="bi-arrow-down"></i>
</a>
{% else %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=name&o=asc">
Nom <i class="bi-arrow-up"></i>
</a>
{% endif %}
{% else %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=name&o=asc">
Nom
</a>
{% endif %}
</div>
</div>
<div
class="col-xxl col-lg-4 col-md-6 order-2 order-md-3 order-lg-2 order-xxl-2"
>
<div class="text-bold fs-7 mt-xxl-0 mt-2">
{% if OrderCol == "address" %}
{% if OrderDir == "asc" || OrderDir == "" %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=address&o=desc">
Adresse <i class="bi-arrow-down"></i>
</a>
{% else %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=address&o=asc">
Adresse <i class="bi-arrow-up"></i>
</a>
{% endif %}
{% else %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=address&o=asc">
Adresse
</a>
{% endif %}
</div>
</div>
<div
class="col-xxl col-lg-4 col-md-6 order-3 order-md-5 order-lg-5 order-xxl-3"
>
<div class="text-bold fs-7 mt-xxl-0 mt-2">
{% if OrderCol == "npa" %}
{% if OrderDir == "asc" || OrderDir == "" %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=npa&o=desc">
Lieu <i class="bi-arrow-down"></i>
</a>
{% else %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=npa&o=asc">
Lieu <i class="bi-arrow-up"></i>
</a>
{% endif %}
{% else %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=npa&o=asc">
Lieu
</a>
{% endif %}
</div>
</div>
<div
class="col-xxl col-lg-4 col-md-6 order-4 order-md-2 order-lg-4 order-xxl-4"
>
<div class="text-bold fs-7 mt-xxl-0 mt-2">
{% if OrderCol == "section" %}
{% if OrderDir == "asc" || OrderDir == "" %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=section&o=desc">
Section <i class="bi-arrow-down"></i>
</a>
{% else %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=section&o=asc">
Section <i class="bi-arrow-up"></i>
</a>
{% endif %}
{% else %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=section&o=asc">
Section
</a>
{% endif %}
</div>
</div>
<div
class="col-xxl col-lg-4 col-md-6 order-5 order-md-3 order-lg-4 order-xxl-5"
>
<div class="text-bold fs-7 mt-xxl-0 mt-2">
{% if OrderCol == "created" %}
{% if OrderDir == "asc" || OrderDir == "" %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=created&o=desc">
Création <i class="bi-arrow-down"></i>
</a>
{% else %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=created&o=asc">
Création <i class="bi-arrow-up"></i>
</a>
{% endif %}
{% else %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=created&o=asc">
Création
</a>
{% endif %}
</div>
</div>
<div
class="col-xxl col-lg-4 col-md-6 order-last order-md-last order-lg-last order-xxl-last"
>
<div class="text-bold fs-7 mt-xxl-0 mt-2">
{% if OrderCol == "updated" %}
{% if OrderDir == "asc" || OrderDir == "" %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=updated&o=desc">
Modification <i class="bi-arrow-down"></i>
</a>
{% else %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=updated&o=asc">
Modification <i class="bi-arrow-up"></i>
</a>
{% endif %}
{% else %}
<a href="?p=1&s={{ SearchJSON|urlencode }}&c=updated&o=asc">
Modification
</a>
{% endif %}
</div>
</div>
</div>
</div>
{% for Person in People %}
<tr>
<td>
<div class="card card-body my-2 py-2 bg-body-tertiary">
<div class="row">
<div
class="col-xxl col-lg-4 col-md-6 order-1 order-md-1 order-lg-1 order-xxl-1"
>
<div class="text-bold fs-7 mt-xxl-0 mt-2">Nom</div>
<div>
{% if Person.IsMember %}
<a href="/members/{{ Person.ID }}">
{{ Person.LastName }} {{ Person.FirstName }}
@ -270,24 +401,53 @@
{{ Person.LastName }} {{ Person.FirstName }}
</a>
{% endif %}
</td>
<td class="d-none d-sm-table-cell">
{{ Person.Address1 }}
{% if Person.Address1 and (Person.PostalCode or Person.City) %}
&ndash;
</div>
</div>
<div
class="col-xxl col-lg-4 col-md-6 order-2 order-md-3 order-lg-2 order-xxl-2"
>
<div class="text-bold fs-7 mt-xxl-0 mt-2">Adresse</div>
<div>{{ Person.Address1 }}</div>
</div>
<div
class="col-xxl col-lg-4 col-md-6 order-3 order-md-5 order-lg-5 order-xxl-3"
>
<div class="text-bold fs-7 mt-xxl-0 mt-2">Lieu</div>
<div>{{ Person.PostalCode }} {{ Person.City }}</div>
</div>
<div
class="col-xxl col-lg-4 col-md-6 order-4 order-md-2 order-lg-4 order-xxl-4"
>
<div class="text-bold fs-7 mt-xxl-0 mt-2">Section</div>
<div>{{ Person.Section.Name }}</div>
</div>
<div
class="col-xxl col-lg-4 col-md-6 order-5 order-md-3 order-lg-4 order-xxl-5"
>
<div class="text-bold fs-7 mt-xxl-0 mt-2">Création</div>
<div>
{% if Person.CreatedAt|date:"2006-01-02" == "1970-01-01" %}
<code>Inconnu</code>
{% else %}
<code>{{ Person.CreatedAt|date:"02.01.2006 15:04" }}</code>
{% endif %}
{{ Person.PostalCode }}
{{ Person.City }}
</td>
<td>
{% if Person.SectionID %}
{{ Person.Section.Name }}
</div>
</div>
<div
class="col-xxl col-lg-4 col-md-6 order-last order-md-last order-lg-last order-xxl-last"
>
<div class="text-bold fs-7 mt-xxl-0 mt-2">Modification</div>
<div>
{% if Person.UpdatedAt|date:"2006-01-02" == "1970-01-01" %}
<code>Inconnu</code>
{% else %}
<code>{{ Person.UpdatedAt|date:"02.01.2006 15:04" }}</code>
{% endif %}
</td>
</tr>
</div>
</div>
</div>
</div>
{% endfor %}
</tbody>
</table>
</div>
<nav class="mt-3 mb-5">
@ -305,14 +465,17 @@
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="?p=1&s={{ SearchJSON|urlencode }}">
<a
class="page-link"
href="?p=1&s={{ SearchJSON|urlencode }}&c={{ OrderCol }}&o={{ OrderDir }}"
>
<i class="bi-rewind"></i>
</a>
</li>
<li class="page-item">
<a
class="page-link"
href="?&p={{ Pagination.CurrentPage - 1 }}&s={{ SearchJSON|urlencode }}"
href="?&p={{ Pagination.CurrentPage - 1 }}&s={{ SearchJSON|urlencode }}&c={{ OrderCol }}&o={{ OrderDir }}"
>
<i class="bi-caret-left"></i>
</a>
@ -327,7 +490,7 @@
{% else %}
class="page-link"
{% endif %}
href="?&p={{ i }}&s={{ SearchJSON|urlencode }}"
href="?&p={{ i }}&s={{ SearchJSON|urlencode }}&c={{ OrderCol }}&o={{ OrderDir }}"
>
{{ i }}
</a>
@ -349,7 +512,7 @@
<li class="page-item">
<a
class="page-link"
href="?&p={{ Pagination.CurrentPage + 1 }}&s={{ SearchJSON|urlencode }}"
href="?&p={{ Pagination.CurrentPage + 1 }}&s={{ SearchJSON|urlencode }}&c={{ OrderCol }}&o={{ OrderDir }}"
>
<i class="bi-caret-right"></i>
</a>
@ -357,7 +520,7 @@
<li class="page-item">
<a
class="page-link"
href="?p={{ Pagination.MaxPages }}&s={{ SearchJSON|urlencode }}"
href="?p={{ Pagination.MaxPages }}&s={{ SearchJSON|urlencode }}&c={{ OrderCol }}&o={{ OrderDir }}"
>
<i class="bi-fast-forward"></i>
</a>

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -10,7 +10,9 @@
{% if Person.IsMember %}
<li class="breadcrumb-item"><a href="/members">Membres</a></li>
{% else %}
<li class="breadcrumb-item"><a href="/contacts">Contacts</a></li>
<li class="breadcrumb-item">
<a href="/contacts">Sympathisants</a>
</li>
{% endif %}
<li class="breadcrumb-item active">
@ -21,9 +23,10 @@
<hr />
</div>
<div class="row mb-3">
<div class="col-md-2">Nom de famille</div>
<div class="col-md-10">
<div class="mw-1200">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Nom de famille</div>
<div class="col">
<input
type="text"
class="form-control"
@ -34,9 +37,9 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Prénom</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Prénom</div>
<div class="col">
<input
type="text"
class="form-control"
@ -47,9 +50,9 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Email</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Email</div>
<div class="col">
<input
type="text"
class="form-control"
@ -60,9 +63,9 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Téléphone fixe</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Téléphone fixe</div>
<div class="col">
<input
type="text"
class="form-control"
@ -73,9 +76,9 @@
</div>
</div>
<div class="row mb-5">
<div class="col-md-2">Téléphone mobile</div>
<div class="col-md-10">
<div class="row align-items-center mb-5">
<div class="col-md-2 col-xl-3">Téléphone mobile</div>
<div class="col">
<input
type="text"
class="form-control"
@ -86,9 +89,9 @@
</div>
</div>
<div class="row mb-2">
<div class="col-md-2">Adresse</div>
<div class="col-md-10">
<div class="row align-items-center mb-2">
<div class="col-md-2 col-xl-3">Adresse</div>
<div class="col">
<input
type="text"
class="form-control"
@ -99,8 +102,8 @@
</div>
</div>
<div class="row mb-2">
<div class="col-md-10 offset-md-2">
<div class="row align-items-center mb-2">
<div class="col offset-md-2 offset-xl-3">
<input
type="text"
class="form-control"
@ -111,8 +114,8 @@
</div>
</div>
<div class="row mb-5">
<div class="col-md-3 col-lg-2 offset-md-2 mb-2 mb-md-0">
<div class="row align-items-center mb-5">
<div class="col-md-3 col-lg-2 offset-md-2 offset-xl-3 mb-2 mb-md-0">
<input
type="text"
class="form-control"
@ -121,7 +124,7 @@
readonly
/>
</div>
<div class="col-md-7 col-lg-8">
<div class="col">
<input
type="text"
class="form-control"
@ -132,9 +135,9 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Section</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Section</div>
<div class="col">
<input
type="text"
class="form-control"
@ -152,9 +155,9 @@
{% endif %}
{% for Field in Fields %}
<div class="row mb-3">
<div class="col-md-2">{{ Field.Name }}</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">{{ Field.Name }}</div>
<div class="col">
{% if Field.FieldType == "text" %}
<input
type="text"
@ -175,7 +178,8 @@
class="form-control"
disabled
readonly
rows="4"
row
align-items-centers="4"
>
{% for FieldValue in FieldValues %}{% if FieldValue.FieldID == Field.ID %}{{ FieldValue.ValueString.String }}{% endif %}{% endfor %}</textarea
>
@ -250,7 +254,7 @@
<div class="my-5">
{% if Person.IsMember %}
<div class="row">
<div class="row align-items-center">
<div class="col-md-6">
{% if !Person.DeletedAt.Valid %}
@ -266,13 +270,13 @@
{% if PermConvert %}
<button
class="btn btn-outline-secondary"
class="btn btn-outline-primary"
type="button"
data-bs-toggle="modal"
data-bs-target="#modal-convert"
>
<i class="bi-arrow-repeat"></i>
Convertir en contact
<i class="bi-arrow-repeat align-items-center-repeat"></i>
Convertir en sympathisant
</button>
{% endif %}
{% endif %}
@ -282,7 +286,7 @@
{% if PermRestore %}
<button
class="btn btn-outline-secondary"
class="btn btn-outline-primary"
type="button"
data-bs-toggle="modal"
data-bs-target="#modal-restore"
@ -295,7 +299,7 @@
{% if PermArchive %}
<button
class="btn btn-outline-secondary"
class="btn btn-outline-primary"
type="button"
data-bs-toggle="modal"
data-bs-target="#modal-archive"
@ -320,7 +324,7 @@
</div>
</div>
{% else %}
<div class="row">
<div class="row align-items-center">
<div class="col-md-6">
{% if !Person.DeletedAt.Valid %}
@ -336,12 +340,12 @@
{% if PermConvert %}
<button
class="btn btn-outline-secondary"
class="btn btn-outline-primary"
type="button"
data-bs-toggle="modal"
data-bs-target="#modal-convert"
>
<i class="bi-arrow-repeat"></i>
<i class="bi-arrow-repeat align-items-center-repeat"></i>
Convertir en membre
</button>
{% endif %}
@ -352,7 +356,7 @@
{% if PermRestore %}
<button
class="btn btn-outline-secondary"
class="btn btn-outline-primary"
type="button"
data-bs-toggle="modal"
data-bs-target="#modal-restore"
@ -365,7 +369,7 @@
{% if PermArchive %}
<button
class="btn btn-outline-secondary"
class="btn btn-outline-primary"
type="button"
data-bs-toggle="modal"
data-bs-target="#modal-archive"
@ -392,6 +396,7 @@
{% endif %}
</div>
</div>
</div>
<div id="modal-delete" class="modal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
@ -400,7 +405,7 @@
{% if Person.IsMember %}
<p>Êtes-vous sûr de vouloir supprimer ce membre ?</p>
{% else %}
<p>Êtes-vous sûr de vouloir supprimer ce contact ?</p>
<p>Êtes-vous sûr de vouloir supprimer ce sympathisant ?</p>
{% endif %}
</div>
<div class="modal-footer">
@ -448,7 +453,7 @@
{% if Person.IsMember %}
<p>Êtes-vous sûr de vouloir archiver ce membre ?</p>
{% else %}
<p>Êtes-vous sûr de vouloir archiver ce contact ?</p>
<p>Êtes-vous sûr de vouloir archiver ce sympathisant ?</p>
{% endif %}
</div>
<div class="modal-footer">
@ -496,7 +501,7 @@
{% if Person.IsMember %}
<p>Êtes-vous sûr de vouloir restaurer ce membre ?</p>
{% else %}
<p>Êtes-vous sûr de vouloir restaurer ce contact ?</p>
<p>Êtes-vous sûr de vouloir restaurer ce sympathisant ?</p>
{% endif %}
</div>
<div class="modal-footer">
@ -542,9 +547,13 @@
<div class="modal-content">
<div class="modal-body">
{% if Person.IsMember %}
<p>Êtes-vous sûr de vouloir convertir ce membre en contact ?</p>
<p>
Êtes-vous sûr de vouloir convertir ce membre en sympathisant ?
</p>
{% else %}
<p>Êtes-vous sûr de vouloir convertir ce contact en membre ?</p>
<p>
Êtes-vous sûr de vouloir convertir ce sympathisant en membre ?
</p>
{% endif %}
</div>
<div class="modal-footer">
@ -564,7 +573,7 @@
class="d-inline p-0"
>
<button class="btn btn-outline-primary" type="submit">
<i class="bi-arrow-repeat"></i>
<i class="bi-arrow align-items-center-repeat"></i>
Convertir
</button>
</form>
@ -575,7 +584,7 @@
class="d-inline p-0"
>
<button class="btn btn-outline-primary" type="submit">
<i class="bi-arrow-repeat"></i>
<i class="bi-arrow align-items-center-repeat"></i>
Convertir
</button>
</form>

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -10,7 +10,9 @@
{% if Person.IsMember or MembersPage %}
<li class="breadcrumb-item"><a href="/members">Membres</a></li>
{% else %}
<li class="breadcrumb-item"><a href="/contacts">Contacts</a></li>
<li class="breadcrumb-item">
<a href="/contacts">Sympathisants</a>
</li>
{% endif %}
{% if Person.ID %}
@ -37,6 +39,7 @@
<hr />
</div>
<form id="person" method="post" class="mw-1200">
{% if Errors %}
<div class="alert alert-danger">
<ul class="m-0">
@ -47,12 +50,11 @@
</div>
{% endif %}
<form id="person" method="post">
<div class="row mb-3">
<label for="last_name" class="form-label col-md-2">
<div class="row align-items-center mb-3">
<label for="last_name" class="form-label col-md-2 col-xl-3">
Nom de famille
</label>
<div class="col-md-10">
<div class="col">
<input
id="name"
class="form-control"
@ -65,9 +67,11 @@
</div>
</div>
<div class="row mb-3">
<label for="first_name" class="form-label col-md-2"> Prénom </label>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<label for="first_name" class="form-label col-md-2 col-xl-3">
Prénom
</label>
<div class="col">
<input
id="first_name"
class="form-control"
@ -80,9 +84,9 @@
</div>
</div>
<div class="row mb-3">
<label for="email" class="form-label col-md-2"> Email </label>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<label for="email" class="form-label col-md-2 col-xl-3"> Email </label>
<div class="col">
<input
id="email"
class="form-control"
@ -94,9 +98,11 @@
</div>
</div>
<div class="row mb-3">
<label for="phone" class="form-label col-md-2"> Téléphone fixe </label>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<label for="phone" class="form-label col-md-2 col-xl-3">
Téléphone fixe
</label>
<div class="col">
<input
id="phone"
class="form-control"
@ -108,11 +114,11 @@
</div>
</div>
<div class="row mb-5">
<label for="mobile" class="form-label col-md-2">
<div class="row align-items-center mb-5">
<label for="mobile" class="form-label col-md-2 col-xl-3">
Téléphone mobile
</label>
<div class="col-md-10">
<div class="col">
<input
id="mobile"
class="form-control"
@ -124,9 +130,11 @@
</div>
</div>
<div class="row mb-2">
<label for="address1" class="form-label col-md-2"> Adresse </label>
<div class="col-md-10">
<div class="row align-items-center mb-2">
<label for="address1" class="form-label col-md-2 col-xl-3">
Adresse
</label>
<div class="col">
<input
id="address1"
class="form-control"
@ -139,8 +147,8 @@
</div>
</div>
<div class="row mb-2">
<div class="col-md-10 offset-md-2">
<div class="row align-items-center mb-2">
<div class="col offset-md-2 offset-xl-3">
<input
id="address2"
class="form-control"
@ -153,8 +161,8 @@
</div>
</div>
<div class="row mb-5">
<div class="col-md-3 col-lg-2 offset-md-2 mb-2 mb-md-0">
<div class="row align-items-center mb-5">
<div class="col-md-3 col-lg-2 offset-md-2 offset-xl-3 mb-2 mb-md-0">
<input
id="postal_code"
class="form-control"
@ -166,7 +174,7 @@
autocomplete="off"
/>
</div>
<div class="col-md-7 col-lg-8">
<div class="col">
<input
id="city"
class="form-control"
@ -179,9 +187,11 @@
</div>
</div>
<div class="row mb-3">
<label for="section" class="form-label col-md-2"> Section </label>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<label for="section" class="form-label col-md-2 col-xl-3">
Section
</label>
<div class="col">
<select
class="form-select"
name="section"
@ -210,11 +220,14 @@
{% endif %}
{% for Field in Fields %}
<div class="row mb-3">
<label for="field-{{ Field.ID }}" class="form-label col-md-2">
<div class="row align-items-center mb-3">
<label
for="field-{{ Field.ID }}"
class="form-label col-md-2 col-xl-3"
>
{{ Field.Name }}
</label>
<div class="col-md-10">
<div class="col">
{% if Field.FieldType == "text" %}
<input
id="field-{{ Field.ID }}"
@ -235,7 +248,8 @@
id="field-{{ Field.ID }}"
class="form-control"
name="field-{{ Field.ID }}"
rows="4"
row
align-items-centers="4"
autocomplete="off"
>
{% for FieldValue in FieldValues %}{% if FieldValue.FieldID == Field.ID %}{{ FieldValue.ValueString.String }}{% endif %}{% endfor %}</textarea

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -14,9 +14,10 @@
<hr />
</div>
<div class="row mb-3">
<div class="col-md-2">Nom</div>
<div class="col-md-10">
<div class="mw-1200">
<div class="row align-items-center mb-4">
<div class="col-md-2 col-xl-3">Nom</div>
<div class="col">
<input
type="text"
class="form-control"
@ -27,351 +28,521 @@
</div>
</div>
<div class="mt-4 mb-3">
<span class="h4"> Permissions membres </span>
</div>
<div class="row mb-3">
<div class="col-md-2">Afficher membres</div>
<div class="col-md-10">
<div class="card mb-4">
<div class="card-header">Permissions membres</div>
<div class="card-body">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Afficher membres</div>
<div class="col">
{% if Role.ShowMember %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-check-lg text-success"></i>
</span>
<input type="text" class="form-control" value="Oui" disabled />
<input
type="text"
class="form-control"
value="Oui"
disabled
/>
</div>
{% else %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-x-lg text-danger"></i>
</span>
<input type="text" class="form-control" value="Non" disabled />
<input
type="text"
class="form-control"
value="Non"
disabled
/>
</div>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Créer membres</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Créer membres</div>
<div class="col">
{% if Role.CreateMember %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-check-lg text-success"></i>
</span>
<input type="text" class="form-control" value="Oui" disabled />
<input
type="text"
class="form-control"
value="Oui"
disabled
/>
</div>
{% else %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-x-lg text-danger"></i>
</span>
<input type="text" class="form-control" value="Non" disabled />
<input
type="text"
class="form-control"
value="Non"
disabled
/>
</div>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Modifier membres</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Modifier membres</div>
<div class="col">
{% if Role.EditMember %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-check-lg text-success"></i>
</span>
<input type="text" class="form-control" value="Oui" disabled />
<input
type="text"
class="form-control"
value="Oui"
disabled
/>
</div>
{% else %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-x-lg text-danger"></i>
</span>
<input type="text" class="form-control" value="Non" disabled />
<input
type="text"
class="form-control"
value="Non"
disabled
/>
</div>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Afficher membres archivés</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Afficher membres archivés</div>
<div class="col">
{% if Role.ShowArchivedMember %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-check-lg text-success"></i>
</span>
<input type="text" class="form-control" value="Oui" disabled />
<input
type="text"
class="form-control"
value="Oui"
disabled
/>
</div>
{% else %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-x-lg text-danger"></i>
</span>
<input type="text" class="form-control" value="Non" disabled />
<input
type="text"
class="form-control"
value="Non"
disabled
/>
</div>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Archiver membres</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Archiver membres</div>
<div class="col">
{% if Role.ArchiveMember %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-check-lg text-success"></i>
</span>
<input type="text" class="form-control" value="Oui" disabled />
<input
type="text"
class="form-control"
value="Oui"
disabled
/>
</div>
{% else %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-x-lg text-danger"></i>
</span>
<input type="text" class="form-control" value="Non" disabled />
<input
type="text"
class="form-control"
value="Non"
disabled
/>
</div>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Restaurer membres</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Restaurer membres</div>
<div class="col">
{% if Role.RestoreMember %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-check-lg text-success"></i>
</span>
<input type="text" class="form-control" value="Oui" disabled />
<input
type="text"
class="form-control"
value="Oui"
disabled
/>
</div>
{% else %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-x-lg text-danger"></i>
</span>
<input type="text" class="form-control" value="Non" disabled />
<input
type="text"
class="form-control"
value="Non"
disabled
/>
</div>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Purger membres (suppression définitive)</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">
Purger membres (suppression définitive)
</div>
<div class="col">
{% if Role.PurgeMember %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-check-lg text-success"></i>
</span>
<input type="text" class="form-control" value="Oui" disabled />
<input
type="text"
class="form-control"
value="Oui"
disabled
/>
</div>
{% else %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-x-lg text-danger"></i>
</span>
<input type="text" class="form-control" value="Non" disabled />
<input
type="text"
class="form-control"
value="Non"
disabled
/>
</div>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Convertir membres en contacts</div>
<div class="col-md-10">
<div class="row align-items-center">
<div class="col-md-2 col-xl-3">
Convertir membres en sympathisants
</div>
<div class="col">
{% if Role.ConvertMemberToContact %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-check-lg text-success"></i>
</span>
<input type="text" class="form-control" value="Oui" disabled />
<input
type="text"
class="form-control"
value="Oui"
disabled
/>
</div>
{% else %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-x-lg text-danger"></i>
</span>
<input type="text" class="form-control" value="Non" disabled />
<input
type="text"
class="form-control"
value="Non"
disabled
/>
</div>
{% endif %}
</div>
</div>
<div class="mt-4 mb-3">
<span class="h4"> Permissions contacts </span>
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Afficher contacts</div>
<div class="col-md-10">
<div class="card">
<div class="card-header">Permissions sympathisants</div>
<div class="card-body">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Afficher sympathisants</div>
<div class="col">
{% if Role.ShowContact %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-check-lg text-success"></i>
</span>
<input type="text" class="form-control" value="Oui" disabled />
<input
type="text"
class="form-control"
value="Oui"
disabled
/>
</div>
{% else %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-x-lg text-danger"></i>
</span>
<input type="text" class="form-control" value="Non" disabled />
<input
type="text"
class="form-control"
value="Non"
disabled
/>
</div>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Créer contacts</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Créer sympathisants</div>
<div class="col">
{% if Role.CreateContact %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-check-lg text-success"></i>
</span>
<input type="text" class="form-control" value="Oui" disabled />
<input
type="text"
class="form-control"
value="Oui"
disabled
/>
</div>
{% else %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-x-lg text-danger"></i>
</span>
<input type="text" class="form-control" value="Non" disabled />
<input
type="text"
class="form-control"
value="Non"
disabled
/>
</div>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Modifier contacts</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Modifier sympathisants</div>
<div class="col">
{% if Role.EditContact %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-check-lg text-success"></i>
</span>
<input type="text" class="form-control" value="Oui" disabled />
<input
type="text"
class="form-control"
value="Oui"
disabled
/>
</div>
{% else %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-x-lg text-danger"></i>
</span>
<input type="text" class="form-control" value="Non" disabled />
<input
type="text"
class="form-control"
value="Non"
disabled
/>
</div>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Afficher contacts archivés</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Afficher sympathisants archivés</div>
<div class="col">
{% if Role.ShowArchivedContact %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-check-lg text-success"></i>
</span>
<input type="text" class="form-control" value="Oui" disabled />
<input
type="text"
class="form-control"
value="Oui"
disabled
/>
</div>
{% else %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-x-lg text-danger"></i>
</span>
<input type="text" class="form-control" value="Non" disabled />
<input
type="text"
class="form-control"
value="Non"
disabled
/>
</div>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Archiver contacts</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Archiver sympathisants</div>
<div class="col">
{% if Role.ArchiveContact %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-check-lg text-success"></i>
</span>
<input type="text" class="form-control" value="Oui" disabled />
<input
type="text"
class="form-control"
value="Oui"
disabled
/>
</div>
{% else %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-x-lg text-danger"></i>
</span>
<input type="text" class="form-control" value="Non" disabled />
<input
type="text"
class="form-control"
value="Non"
disabled
/>
</div>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Restaurer contacts</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Restaurer sympathisants</div>
<div class="col">
{% if Role.RestoreContact %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-check-lg text-success"></i>
</span>
<input type="text" class="form-control" value="Oui" disabled />
<input
type="text"
class="form-control"
value="Oui"
disabled
/>
</div>
{% else %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-x-lg text-danger"></i>
</span>
<input type="text" class="form-control" value="Non" disabled />
<input
type="text"
class="form-control"
value="Non"
disabled
/>
</div>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Purger contacts (suppression définitive)</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">
Purger sympathisants (suppression définitive)
</div>
<div class="col">
{% if Role.PurgeContact %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-check-lg text-success"></i>
</span>
<input type="text" class="form-control" value="Oui" disabled />
<input
type="text"
class="form-control"
value="Oui"
disabled
/>
</div>
{% else %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-x-lg text-danger"></i>
</span>
<input type="text" class="form-control" value="Non" disabled />
<input
type="text"
class="form-control"
value="Non"
disabled
/>
</div>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Convertir contacts en membres</div>
<div class="col-md-10">
<div class="row align-items-center">
<div class="col-md-2 col-xl-3">
Convertir sympathisants en membres
</div>
<div class="col">
{% if Role.ConvertContactToMember %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-check-lg text-success"></i>
</span>
<input type="text" class="form-control" value="Oui" disabled />
<input
type="text"
class="form-control"
value="Oui"
disabled
/>
</div>
{% else %}
<div class="input-group">
<span class="input-group-text">
<i class="bi-x-lg text-danger"></i>
</span>
<input type="text" class="form-control" value="Non" disabled />
<input
type="text"
class="form-control"
value="Non"
disabled
/>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<div class="my-4 row">
<div class="my-4 row align-items-center">
<div class="col-6">
<a
class="btn btn-outline-primary"
@ -394,6 +565,7 @@
</div>
</div>
</div>
</div>
<div id="modal-delete" class="modal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -22,6 +22,7 @@
<hr />
</div>
<form id="role" method="post" class="mw-1200">
{% if Errors %}
<div class="alert alert-danger">
<ul class="m-0">
@ -32,8 +33,7 @@
</div>
{% endif %}
<form id="role" method="post">
<div class="row mb-3">
<div class="row align-items-center mb-3">
<label for="name" class="form-label col-md-2"> Nom </label>
<div class="col-md-10">
<input
@ -49,15 +49,12 @@
</div>
</div>
<div class="mt-4 mb-3 d-md-none">
<span class="h4"> Permissions membres </span>
</div>
<div class="row mb-3">
<div class="col-md-2">
<div class="d-none d-md-block">Permissions membres</div>
<div class="mb-2">Permissions membres</div>
</div>
<div class="col-md-10">
<div class="mb-1">
<input
type="checkbox"
class="form-check-input me-2"
@ -66,12 +63,10 @@
autocomplete="off"
{% if Role.ShowMember %}checked{% endif %}
/>
<label for="show_member" class="form-label"> Afficher membres </label>
</div>
<label for="show_member" class="form-label"> Afficher </label>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="mb-1">
<input
type="checkbox"
class="form-check-input me-2"
@ -80,12 +75,10 @@
autocomplete="off"
{% if Role.CreateMember %}checked{% endif %}
/>
<label for="create_member" class="form-label"> Créer membres </label>
</div>
<label for="create_member" class="form-label"> Créer </label>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="mb-1">
<input
type="checkbox"
class="form-check-input me-2"
@ -94,12 +87,10 @@
autocomplete="off"
{% if Role.EditMember %}checked{% endif %}
/>
<label for="edit_member" class="form-label"> Modifier membres </label>
</div>
<label for="edit_member" class="form-label"> Modifier </label>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="mb-1">
<input
type="checkbox"
class="form-check-input me-2"
@ -109,13 +100,11 @@
{% if Role.ShowArchivedMember %}checked{% endif %}
/>
<label for="show_archived_member" class="form-label">
Afficher membres archivés
Afficher archivés
</label>
</div>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="mb-1">
<input
type="checkbox"
class="form-check-input me-2"
@ -124,14 +113,10 @@
autocomplete="off"
{% if Role.ArchiveMember %}checked{% endif %}
/>
<label for="archive_member" class="form-label">
Archiver membres
</label>
</div>
<label for="archive_member" class="form-label"> Archiver </label>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="mb-1">
<input
type="checkbox"
class="form-check-input me-2"
@ -140,14 +125,10 @@
autocomplete="off"
{% if Role.RestoreMember %}checked{% endif %}
/>
<label for="restore_member" class="form-label">
Restaurer membres
</label>
</div>
<label for="restore_member" class="form-label"> Restaurer </label>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="mb-1">
<input
type="checkbox"
class="form-check-input me-2"
@ -157,13 +138,11 @@
{% if Role.PurgeMember %}checked{% endif %}
/>
<label for="purge_member" class="form-label">
Purger membres (suppression définitive)
Purger (suppression définitive)
</label>
</div>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="mb-1">
<input
type="checkbox"
class="form-check-input me-2"
@ -173,20 +152,18 @@
{% if Role.ConvertMemberToContact %}checked{% endif %}
/>
<label for="convert_member_to_contact" class="form-label">
Convertir membres en contacts
Convertir en sympathisants
</label>
</div>
</div>
<div class="mt-4 mb-3 d-md-none">
<span class="h4"> Permissions contacts </span>
</div>
<div class="row mb-3">
<div class="col-md-2">
<div class="d-none d-md-block">Permissions contacts</div>
<div class="mb-2">Permissions sympathisants</div>
</div>
<div class="col-md-10">
<div class="mb-1">
<input
type="checkbox"
class="form-check-input me-2"
@ -195,14 +172,10 @@
autocomplete="off"
{% if Role.ShowContact %}checked{% endif %}
/>
<label for="show_contact" class="form-label">
Afficher contacts
</label>
</div>
<label for="show_contact" class="form-label"> Afficher </label>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="mb-1">
<input
type="checkbox"
class="form-check-input me-2"
@ -211,14 +184,10 @@
autocomplete="off"
{% if Role.CreateContact %}checked{% endif %}
/>
<label for="create_contact" class="form-label">
Créer contacts
</label>
</div>
<label for="create_contact" class="form-label"> Créer </label>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="mb-1">
<input
type="checkbox"
class="form-check-input me-2"
@ -227,14 +196,10 @@
autocomplete="off"
{% if Role.EditContact %}checked{% endif %}
/>
<label for="edit_contact" class="form-label">
Modifier contacts
</label>
</div>
<label for="edit_contact" class="form-label"> Modifier </label>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="mb-1">
<input
type="checkbox"
class="form-check-input me-2"
@ -244,13 +209,11 @@
{% if Role.ShowArchivedContact %}checked{% endif %}
/>
<label for="show_archived_contact" class="form-label">
Afficher contacts archivés
Afficher archivés
</label>
</div>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="mb-1">
<input
type="checkbox"
class="form-check-input me-2"
@ -259,14 +222,10 @@
autocomplete="off"
{% if Role.ArchiveContact %}checked{% endif %}
/>
<label for="archive_contact" class="form-label">
Archiver contacts
</label>
</div>
<label for="archive_contact" class="form-label"> Archiver </label>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="mb-1">
<input
type="checkbox"
class="form-check-input me-2"
@ -275,14 +234,10 @@
autocomplete="off"
{% if Role.RestoreContact %}checked{% endif %}
/>
<label for="restore_contact" class="form-label">
Restaurer contacts
</label>
</div>
<label for="restore_contact" class="form-label"> Restaurer </label>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="mb-1">
<input
type="checkbox"
class="form-check-input me-2"
@ -292,13 +247,11 @@
{% if Role.PurgeContact %}checked{% endif %}
/>
<label for="purge_contact" class="form-label">
Purger contacts (suppression définitive)
Purger (suppression définitive)
</label>
</div>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="mb-1">
<input
type="checkbox"
class="form-check-input me-2"
@ -308,10 +261,11 @@
{% if Role.ConvertContactToMember %}checked{% endif %}
/>
<label for="convert_contact_to_member" class="form-label">
Convertir contacts en membres
Convertir en membres
</label>
</div>
</div>
</div>
<div class="my-4">
<button class="btn btn-outline-primary" type="submit">

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container my-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -13,32 +13,31 @@
<hr />
</div>
<div class="my-3 text-end">
<div class="row my-3">
<div class="col-sm-6">
<span class="h2 d-none d-sm-inline">Rôles</span>
</div>
<div class="col-sm-6 text-end">
<a class="btn btn-outline-primary" href="/admin/roles/add">
<i class="bi-plus-lg"></i>
Ajouter
</a>
</div>
</div>
{% if Roles %}
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Nom</th>
</tr>
</thead>
<tbody>
{% for Role in Roles %}
<tr>
<td>
<div class="card card-body my-2 py-2 bg-body-tertiary">
<div class="row">
<div class="col">
<div class="text-bold fs-7 mt-xxl-0 mt-2">Nom</div>
<div>
<a href="/admin/roles/{{ Role.ID }}"> {{ Role.Name }} </a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endfor %}
{% else %}
<div class="my-4">Pas de rôle pour le moment</div>
{% endif %}

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -16,9 +16,10 @@
<hr />
</div>
<div class="row mb-3">
<div class="col-md-2">Nom</div>
<div class="col-md-10">
<div class="mw-1200">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Nom</div>
<div class="col-md-10 col-xl-9">
<input
type="text"
class="form-control"
@ -29,9 +30,9 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Nom technique</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Nom technique</div>
<div class="col-md-10 col-xl-9">
<input
type="text"
class="form-control"
@ -42,9 +43,9 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Section parente</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Section parente</div>
<div class="col-md-10 col-xl-9">
{% if Section.ParentSectionID %}
<input
type="text"
@ -64,9 +65,9 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Peut contenir des membres</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Peut contenir des membres</div>
<div class="col-md-10 col-xl-9">
{% if Section.ContainsMembers %}
<div class="input-group">
<span class="input-group-text">
@ -85,9 +86,9 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Peut contenir des contacts</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Peut contenir des sympathisants</div>
<div class="col-md-10 col-xl-9">
{% if Section.ContainsContacts %}
<div class="input-group">
<span class="input-group-text">
@ -106,7 +107,7 @@
</div>
</div>
<div class="my-4 row">
<div class="my-4 row align-items-center">
<div class="col-6">
<a
class="btn btn-outline-primary"
@ -160,4 +161,5 @@
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -24,6 +24,7 @@
<hr />
</div>
<form id="section" method="post" class="mw-1200">
{% if Errors %}
<div class="alert alert-danger">
<ul class="m-0">
@ -34,10 +35,11 @@
</div>
{% endif %}
<form id="section" method="post">
<div class="row mb-3">
<label for="name" class="form-label col-md-2"> Nom </label>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<label for="name" class="form-label mb-0 col-md-2 col-xl-3">
Nom
</label>
<div class="col-md-10 col-xl-9">
<input
id="name"
class="form-control"
@ -51,11 +53,11 @@
</div>
</div>
<div class="row mb-3">
<label for="short_name" class="form-label col-md-2">
<div class="row align-items-center mb-3">
<label for="short_name" class="form-label mb-0 col-md-2 col-xl-3">
Nom technique
</label>
<div class="col-md-10">
<div class="col-md-10 col-xl-9">
<input
id="short_name"
class="form-control"
@ -68,11 +70,11 @@
</div>
</div>
<div class="row mb-3">
<label for="parent_section" class="form-label col-md-2">
<div class="row align-items-center mb-3">
<label for="parent_section" class="form-label mb-0 col-md-2 col-xl-3">
Section parente
</label>
<div class="col-md-10">
<div class="col-md-10 col-xl-9">
<select
id="parent_section"
class="form-select"
@ -97,8 +99,8 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="row align-items-center mb-3">
<div class="col-md-10 col-xl-9 offset-md-2 offset-xl-3">
<input
type="checkbox"
class="form-check-input me-2"
@ -109,14 +111,14 @@
checked
{% endif %}
/>
<label for="contains_members" class="form-label">
<label for="contains_members" class="form-label mb-0">
Contient des membres
</label>
</div>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="row align-items-center mb-3">
<div class="col-md-10 col-xl-9 offset-md-2 offset-xl-3">
<input
type="checkbox"
class="form-check-input me-2"
@ -127,8 +129,8 @@
checked
{% endif %}
/>
<label for="contains_contacts" class="form-label">
Contient des contacts
<label for="contains_contacts" class="form-label mb-0">
Contient des sympathisants
</label>
</div>
</div>

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container my-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -13,63 +13,74 @@
<hr />
</div>
<div class="my-3 text-end">
<div class="row my-3">
<div class="col-sm-6">
<span class="h2 d-none d-sm-inline">Sections</span>
</div>
<div class="col-sm-6 text-end">
<a class="btn btn-outline-primary" href="/admin/sections/add">
<i class="bi-plus-lg"></i>
Ajouter
</a>
</div>
</div>
{% if Sections %}
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th class="w-25">Nom</th>
<th class="w-25">Section parente</th>
<th class="w-25">Membres</th>
<th class="w-25">Contacts</th>
</tr>
</thead>
<tbody>
{% for Section in Sections %}
<tr>
<td>
<div class="card card-body my-2 py-2 bg-body-tertiary">
<div class="row">
<div class="col-12 col-sm-8 col-md-9 col-xl-3 order-1">
<div class="text-bold fs-7 mt-xxl-0 mt-2">Nom</div>
<div>
<a href="/admin/sections/{{ Section.ID }}">
{{ Section.Name }}
</a>
</td>
<td>
{% if Section.ParentSectionID %}
{{ Section.ParentSection.Name }}
{% else %}
<i class="bi-x-lg text-danger me-1"></i>
Non
{% endif %}
</td>
<td>
{% if Section.ContainsMembers %}
<i class="bi-check-lg text-success me-1"></i>
Oui
{% else %}
<i class="bi-x-lg text-danger me-1"></i>
Non
{% endif %}
</td>
<td>
{% if Section.ContainsContacts %}
<i class="bi-check-lg text-success me-1"></i>
Oui
{% else %}
<i class="bi-x-lg text-danger me-1"></i>
Non
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div
class="col-12 col-sm-8 col-md-9 col-xl-3 order-2 order-sm-3 order-xl-2"
>
<div class="text-bold fs-7 mt-xxl-0 mt-2">Section parente</div>
<div>
{% if Section.ParentSectionID %}
<a href="/admin/sections/{{ Section.ParentSectionID }}">
{{ Section.ParentSection.Name }}
</a>
{% else %}
<span class="badge text-bg-danger"
>Pas de section parente</span
>
{% endif %}
</div>
</div>
<div
class="col-12 col-sm-4 col-md-3 col-xl-3 order-3 order-sm-2 order-xl-3"
>
<div class="text-bold fs-7 mt-xxl-0 mt-2">Membres</div>
<div>
{% if Section.ContainsMembers %}
<span class="badge text-bg-success">Oui</span>
{% else %}
<span class="badge text-bg-danger">Non</span>
{% endif %}
</div>
</div>
<div class="col-12 col-sm-4 col-md-3 col-xl-3 order-4">
<div class="text-bold fs-7 mt-xxl-0 mt-2">Sympathisants</div>
<div>
{% if Section.ContainsContacts %}
<span class="badge text-bg-success">Oui</span>
{% else %}
<span class="badge text-bg-danger">Non</span>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
{% else %}
<div class="my-4">Pas de section pour le moment</div>
{% endif %}

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -16,9 +16,10 @@
<hr />
</div>
<div class="row mb-3">
<div class="col-md-2">Nom complet</div>
<div class="col-md-10">
<div class="mw-1200">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Nom complet</div>
<div class="col">
<input
type="text"
class="form-control"
@ -29,9 +30,9 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Email</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Email</div>
<div class="col">
<input
type="text"
class="form-control"
@ -42,9 +43,9 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Administrateur</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Administrateur</div>
<div class="col">
{% if User.IsAdmin %}
<div class="input-group">
<span class="input-group-text">
@ -63,9 +64,11 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Ecran de bienvenue à la prochaine connexion</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">
Ecran de bienvenue à la prochaine connexion
</div>
<div class="col">
{% if User.SkipWelcome %}
<div class="input-group">
<span class="input-group-text">
@ -84,9 +87,9 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-2">Double facteur (TOTP)</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">Double facteur (TOTP)</div>
<div class="col">
{% if User.TotpSecret.Valid %}
<div class="input-group">
<span class="input-group-text">
@ -115,9 +118,9 @@
</div>
{% if UserRoles %}
{% for UserRole in UserRoles %}
<div class="row mb-3">
<div class="col-md-2">{{ UserRole.Section.Name }}</div>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<div class="col-md-2 col-xl-3">{{ UserRole.Section.Name }}</div>
<div class="col">
<div class="input-group">
<span class="input-group-text">
<i class="bi-key"></i>
@ -137,7 +140,7 @@
<div>Pas encore de permissions pour cet utilisateur.</div>
{% endif %}
<div class="my-4 row">
<div class="my-4 row align-items-center">
<div class="col-6">
<a
class="btn btn-outline-primary"
@ -167,6 +170,7 @@
</div>
</div>
</div>
</div>
<div id="modal-delete" class="modal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -24,6 +24,7 @@
<hr />
</div>
<form id="user" method="post" class="mw-1200">
{% if Errors %}
<div class="alert alert-danger">
<ul class="m-0">
@ -34,10 +35,11 @@
</div>
{% endif %}
<form id="user" method="post">
<div class="row mb-3">
<label for="name" class="form-label col-md-2"> Nom complet </label>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<label for="name" class="form-label col-md-2 col-xl-3">
Nom complet
</label>
<div class="col">
<input
id="name"
class="form-control"
@ -51,9 +53,9 @@
</div>
</div>
<div class="row mb-3">
<label for="email" class="form-label col-md-2"> Email </label>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<label for="email" class="form-label col-md-2 col-xl-3"> Email </label>
<div class="col">
<input
id="email"
class="form-control"
@ -66,8 +68,8 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="row align-items-center mb-3">
<div class="col offset-md-2 offset-xl-3">
<input
type="checkbox"
class="form-check-input me-2"
@ -82,9 +84,11 @@
</div>
</div>
<div class="row mb-3">
<label for="password" class="form-label col-md-2"> Mot de passe </label>
<div class="col-md-10">
<div class="row align-items-center mb-3">
<label for="password" class="form-label col-md-2 col-xl-3">
Mot de passe
</label>
<div class="col">
<input
id="password"
class="form-control"
@ -100,8 +104,8 @@
</div>
{% if User.ID %}
<div class="row mb-3">
<div class="col-md-10 offset-md-2">
<div class="row align-items-center mb-3">
<div class="col offset-md-2 offset-xl-3">
<input
type="checkbox"
class="form-check-input me-2"

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -19,6 +19,8 @@
<hr />
</div>
{% if Sections %}
<form id="user" method="post" class="mw-1200">
{% if Errors %}
<div class="alert alert-danger">
<ul class="m-0">
@ -29,12 +31,10 @@
</div>
{% endif %}
{% if Sections %}
<form id="user" method="post">
{% for Section in Sections %}
<div class="row mb-3">
<div class="col-md-2">{{ Section.Name }}</div>
<div class="col-md-10">
<div class="col-md-2 col-xl-3">{{ Section.Name }}</div>
<div class="col">
<div class="input-group">
<span class="input-group-text">
<i class="bi-key"></i>

View file

@ -1,7 +1,7 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container my-4">
<div class="container-fluid my-4 px-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
@ -13,45 +13,47 @@
<hr />
</div>
<div class="my-3 text-end">
<div class="row my-3">
<div class="col-sm-6">
<span class="h2 d-none d-sm-inline">Utilisateurs</span>
</div>
<div class="col-sm-6 text-end">
<a class="btn btn-outline-primary" href="/admin/users/add">
<i class="bi-plus-lg"></i>
Ajouter
</a>
</div>
</div>
{% if Users %}
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th class="w-50">Nom complet</th>
<th class="w-25">Email</th>
<th class="w-25">Administrateur</th>
</tr>
</thead>
<tbody>
{% for User in Users %}
<tr>
<td>
<span class="user-photo me-2">{{ User.Name|first }}</span>
<div class="card card-body my-2 py-2 bg-body-tertiary">
<div class="row">
<div class="col-12 col-sm-8 col-md-9 col-xl-5 order-1">
<div class="text-bold fs-7 mt-xxl-0 mt-2">Nom</div>
<div>
<a href="/admin/users/{{ User.ID }}"> {{ User.Name }} </a>
</td>
<td>{{ User.Email }}</td>
<td>
{% if User.IsAdmin %}
<i class="bi-check-lg text-success me-1"></i>
Oui
{% else %}
<i class="bi-x-lg text-danger me-1"></i>
Non
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="col-12 col-xl-5 order-2 order-sm-3 order-xl-2">
<div class="text-bold fs-7 mt-xxl-0 mt-2">Email</div>
<div>{{ User.Email }}</div>
</div>
<div class="col order-3 order-sm-2 order-xl-3">
<div class="text-bold fs-7 mt-xxl-0 mt-2">Administrateur</div>
<div>
{% if User.IsAdmin %}
<span class="badge text-bg-success">Oui</span>
{% else %}
<span class="badge text-bg-danger">Non</span>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
{% else %}
<div class="my-4">Pas d'utilisateurs pour le moment</div>
{% endif %}