Add admin page to list the users

There is no way, for now, to add, edit or remove users, because
currently we only need to list users.

I can not give admins access to the user table, for security
permissions, so i had to create a new view.  I could name it also ‘user’
in ‘camper’ scheme, but then i was afraid i would have problems with
unit tests and their search_path, so instead i called it
‘company_user_profile’, which is like ‘user_profile’ but for all users
in ‘company_user’.

I created a new Go package for it, rather than add the admin handler in
‘auth’, because ‘template’ depends on ‘auth’, and rendering from ‘auth’
would cause a dependency loop.

I needed to have the roles in gettext to translate them, but there is
no obvious place where to put the call to PgettextNoop.  For now, there
are in ‘NewAdminHandler’ because it is called once in the application’s
lifetime and they actually do not matter much.
This commit is contained in:
jordi fita mas 2024-01-17 19:42:47 +01:00
parent c69c715ef3
commit f7fdc594d5
12 changed files with 536 additions and 96 deletions

View File

@ -0,0 +1,25 @@
-- Deploy camper:company_user_profile to pg
-- requires: roles
-- requires: schema_camper
-- requires: user
-- requires: company_user
-- requires: current_company_id
begin;
set search_path to camper, public;
create or replace view company_user_profile with (security_barrier) as
select user_id
, email
, name
, role
, lang_tag
from auth."user"
join company_user using (user_id)
where company_id = current_company_id()
;
grant select on table company_user_profile to admin;
commit;

View File

@ -22,6 +22,7 @@ import (
"dev.tandem.ws/tandem/camper/pkg/services" "dev.tandem.ws/tandem/camper/pkg/services"
"dev.tandem.ws/tandem/camper/pkg/surroundings" "dev.tandem.ws/tandem/camper/pkg/surroundings"
"dev.tandem.ws/tandem/camper/pkg/template" "dev.tandem.ws/tandem/camper/pkg/template"
"dev.tandem.ws/tandem/camper/pkg/user"
) )
type adminHandler struct { type adminHandler struct {
@ -35,6 +36,7 @@ type adminHandler struct {
season *season.AdminHandler season *season.AdminHandler
services *services.AdminHandler services *services.AdminHandler
surroundings *surroundings.AdminHandler surroundings *surroundings.AdminHandler
user *user.AdminHandler
} }
func newAdminHandler(mediaDir string) *adminHandler { func newAdminHandler(mediaDir string) *adminHandler {
@ -49,6 +51,7 @@ func newAdminHandler(mediaDir string) *adminHandler {
season: season.NewAdminHandler(), season: season.NewAdminHandler(),
services: services.NewAdminHandler(), services: services.NewAdminHandler(),
surroundings: surroundings.NewAdminHandler(), surroundings: surroundings.NewAdminHandler(),
user: user.NewAdminHandler(),
} }
} }
@ -88,6 +91,8 @@ func (h *adminHandler) Handle(user *auth.User, company *auth.Company, conn *data
h.services.Handler(user, company, conn).ServeHTTP(w, r) h.services.Handler(user, company, conn).ServeHTTP(w, r)
case "surroundings": case "surroundings":
h.surroundings.Handler(user, company, conn).ServeHTTP(w, r) h.surroundings.Handler(user, company, conn).ServeHTTP(w, r)
case "users":
h.user.Handler(user, company, conn).ServeHTTP(w, r)
case "": case "":
switch r.Method { switch r.Method {
case http.MethodGet: case http.MethodGet:

94
pkg/user/admin.go Normal file
View File

@ -0,0 +1,94 @@
package user
import (
"context"
"net/http"
"dev.tandem.ws/tandem/camper/pkg/auth"
"dev.tandem.ws/tandem/camper/pkg/database"
httplib "dev.tandem.ws/tandem/camper/pkg/http"
"dev.tandem.ws/tandem/camper/pkg/locale"
"dev.tandem.ws/tandem/camper/pkg/template"
)
type AdminHandler struct {
}
func NewAdminHandler() *AdminHandler {
locale.PgettextNoop("guest", "role")
locale.PgettextNoop("employee", "role")
locale.PgettextNoop("admin", "role")
return &AdminHandler{}
}
func (h *AdminHandler) Handler(user *auth.User, company *auth.Company, conn *database.Conn) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var head string
head, r.URL.Path = httplib.ShiftPath(r.URL.Path)
switch head {
case "":
switch r.Method {
case http.MethodGet:
serveUserIndex(w, r, user, company, conn)
default:
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPost)
}
default:
http.NotFound(w, r)
}
})
}
func serveUserIndex(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) {
users, err := collectUserEntries(r.Context(), conn)
if err != nil {
panic(err)
}
page := &userIndex{
Users: users,
}
page.MustRender(w, r, user, company)
}
func collectUserEntries(ctx context.Context, conn *database.Conn) ([]*userEntry, error) {
rows, err := conn.Query(ctx, `
select '/admin/users/' || user_id
, email
, name
, role
from company_user_profile
order by name
`)
if err != nil {
return nil, err
}
defer rows.Close()
var entries []*userEntry
for rows.Next() {
entry := &userEntry{}
if err = rows.Scan(&entry.URL, &entry.Email, &entry.Name, &entry.Role); err != nil {
return nil, err
}
entries = append(entries, entry)
}
return entries, nil
}
type userEntry struct {
URL string
Email string
Name string
Role string
}
type userIndex struct {
Users []*userEntry
}
func (page *userIndex) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) {
template.MustRenderAdmin(w, r, user, company, "user/index.gohtml", page)
}

109
po/ca.po
View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: camper\n" "Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2024-01-16 20:32+0100\n" "POT-Creation-Date: 2024-01-17 19:40+0100\n"
"PO-Revision-Date: 2023-07-22 23:45+0200\n" "PO-Revision-Date: 2023-07-22 23:45+0200\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n" "Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Catalan <ca@dodds.net>\n" "Language-Team: Catalan <ca@dodds.net>\n"
@ -67,24 +67,24 @@ msgctxt "title"
msgid "Home" msgid "Home"
msgstr "Inici" msgstr "Inici"
#: web/templates/public/home.gohtml:24 #: web/templates/public/home.gohtml:25
msgctxt "link" msgctxt "link"
msgid "Booking" msgid "Booking"
msgstr "Reserva" msgstr "Reserva"
#: web/templates/public/home.gohtml:31 #: web/templates/public/home.gohtml:28
msgid "The pleasure of camping in the middle of nature…" msgid "The pleasure of camping in the middle of nature…"
msgstr "El plaer dacampar en plena natura…" msgstr "El plaer dacampar en plena natura…"
#: web/templates/public/home.gohtml:43 #: web/templates/public/home.gohtml:40
msgid "Our services" msgid "Our services"
msgstr "Els nostres serveis" msgstr "Els nostres serveis"
#: web/templates/public/home.gohtml:45 #: web/templates/public/home.gohtml:42
msgid "Come and enjoy!" msgid "Come and enjoy!"
msgstr "Vine a gaudir!" msgstr "Vine a gaudir!"
#: web/templates/public/home.gohtml:47 #: web/templates/public/home.gohtml:44
#: web/templates/public/surroundings.gohtml:7 #: web/templates/public/surroundings.gohtml:7
#: web/templates/public/surroundings.gohtml:12 #: web/templates/public/surroundings.gohtml:12
#: web/templates/public/layout.gohtml:68 web/templates/public/layout.gohtml:96 #: web/templates/public/layout.gohtml:68 web/templates/public/layout.gohtml:96
@ -93,19 +93,19 @@ msgctxt "title"
msgid "Surroundings" msgid "Surroundings"
msgstr "Lentorn" msgstr "Lentorn"
#: web/templates/public/home.gohtml:50 #: web/templates/public/home.gohtml:47
msgid "Located in <strong>Alta Garrotxa</strong>, between the <strong>Pyrenees</strong> and the <strong>Costa Brava</strong>." msgid "Located in <strong>Alta Garrotxa</strong>, between the <strong>Pyrenees</strong> and the <strong>Costa Brava</strong>."
msgstr "Situats a l<strong>Alta Garrotxa</strong>, entre els <strong>Pirineus</strong> i la <strong>Costa Brava</strong>." msgstr "Situats a l<strong>Alta Garrotxa</strong>, entre els <strong>Pirineus</strong> i la <strong>Costa Brava</strong>."
#: web/templates/public/home.gohtml:51 #: web/templates/public/home.gohtml:48
msgid "Nearby there are the <strong>gorges of Sadernes</strong>, <strong>volcanoes</strong>, <strong>La Fageda den Jordà</strong>, the Jewish quarter of <strong>Besalú</strong>, the basaltic cliff of <strong>Castellfollit de la Roca</strong>… much to see and much to do." msgid "Nearby there are the <strong>gorges of Sadernes</strong>, <strong>volcanoes</strong>, <strong>La Fageda den Jordà</strong>, the Jewish quarter of <strong>Besalú</strong>, the basaltic cliff of <strong>Castellfollit de la Roca</strong>… much to see and much to do."
msgstr "A prop teniu els <strong>gorgs de Sadernes</strong>, <strong>volcans</strong>, <strong>La Fageda den Jordà</strong>, el call jueu de <strong>Besalú</strong>, la cinglera basàltica de <strong>Castellfollit de la Roca</strong>… molt per veure i molt per fer." msgstr "A prop teniu els <strong>gorgs de Sadernes</strong>, <strong>volcans</strong>, <strong>La Fageda den Jordà</strong>, el call jueu de <strong>Besalú</strong>, la cinglera basàltica de <strong>Castellfollit de la Roca</strong>… molt per veure i molt per fer."
#: web/templates/public/home.gohtml:52 #: web/templates/public/home.gohtml:49
msgid "Less than an hour from <strong>Girona</strong>, one from <strong>La Bisbal dEmpordà</strong>, and two from <strong>Barcelona</strong>." msgid "Less than an hour from <strong>Girona</strong>, one from <strong>La Bisbal dEmpordà</strong>, and two from <strong>Barcelona</strong>."
msgstr "A menys duna hora de <strong>Girona</strong>, a una de <strong>La Bisbal dEmpordà</strong> i a dues de <strong>Barcelona</strong>." msgstr "A menys duna hora de <strong>Girona</strong>, a una de <strong>La Bisbal dEmpordà</strong> i a dues de <strong>Barcelona</strong>."
#: web/templates/public/home.gohtml:53 #: web/templates/public/home.gohtml:50
msgid "Discover the surroundings" msgid "Discover the surroundings"
msgstr "Descobreix lentorn" msgstr "Descobreix lentorn"
@ -120,7 +120,7 @@ msgid "Check-out Date"
msgstr "Data de sortida" msgstr "Data de sortida"
#: web/templates/public/campsite/type.gohtml:54 #: web/templates/public/campsite/type.gohtml:54
#: web/templates/public/booking.gohtml:156 #: web/templates/public/booking.gohtml:164
msgctxt "action" msgctxt "action"
msgid "Book" msgid "Book"
msgstr "Reserva" msgstr "Reserva"
@ -301,91 +301,91 @@ msgctxt "title"
msgid "Campground" msgid "Campground"
msgstr "El càmping" msgstr "El càmping"
#: web/templates/public/booking.gohtml:6 web/templates/public/booking.gohtml:11 #: web/templates/public/booking.gohtml:7 web/templates/public/booking.gohtml:12
#: web/templates/public/layout.gohtml:70 #: web/templates/public/layout.gohtml:70
msgctxt "title" msgctxt "title"
msgid "Booking" msgid "Booking"
msgstr "Reserva" msgstr "Reserva"
#: web/templates/public/booking.gohtml:15 #: web/templates/public/booking.gohtml:16
msgctxt "title" msgctxt "title"
msgid "Customer Details" msgid "Customer Details"
msgstr "Detalls del client" msgstr "Detalls del client"
#: web/templates/public/booking.gohtml:18 #: web/templates/public/booking.gohtml:19
msgctxt "input" msgctxt "input"
msgid "Full name" msgid "Full name"
msgstr "Nom i cognoms" msgstr "Nom i cognoms"
#: web/templates/public/booking.gohtml:27 #: web/templates/public/booking.gohtml:28
msgctxt "input" msgctxt "input"
msgid "Address (optional)" msgid "Address (optional)"
msgstr "Adreça (opcional)" msgstr "Adreça (opcional)"
#: web/templates/public/booking.gohtml:36 #: web/templates/public/booking.gohtml:37
msgctxt "input" msgctxt "input"
msgid "Postcode (optional)" msgid "Postcode (optional)"
msgstr "Codi postal (opcional)" msgstr "Codi postal (opcional)"
#: web/templates/public/booking.gohtml:45 #: web/templates/public/booking.gohtml:46
msgctxt "input" msgctxt "input"
msgid "Town or village (optional)" msgid "Town or village (optional)"
msgstr "Població (opcional)" msgstr "Població (opcional)"
#: web/templates/public/booking.gohtml:54 #: web/templates/public/booking.gohtml:55
#: web/templates/admin/taxDetails.gohtml:98 #: web/templates/admin/taxDetails.gohtml:98
msgctxt "input" msgctxt "input"
msgid "Country" msgid "Country"
msgstr "País" msgstr "País"
#: web/templates/public/booking.gohtml:57 #: web/templates/public/booking.gohtml:58
msgid "Choose a country" msgid "Choose a country"
msgstr "Esculli un país" msgstr "Esculli un país"
#: web/templates/public/booking.gohtml:65 web/templates/admin/login.gohtml:22 #: web/templates/public/booking.gohtml:66 web/templates/admin/login.gohtml:22
#: web/templates/admin/profile.gohtml:35 #: web/templates/admin/profile.gohtml:35
#: web/templates/admin/taxDetails.gohtml:50 #: web/templates/admin/taxDetails.gohtml:50
msgctxt "input" msgctxt "input"
msgid "Email" msgid "Email"
msgstr "Correu-e" msgstr "Correu-e"
#: web/templates/public/booking.gohtml:74 #: web/templates/public/booking.gohtml:75
#: web/templates/admin/taxDetails.gohtml:42 #: web/templates/admin/taxDetails.gohtml:42
msgctxt "input" msgctxt "input"
msgid "Phone" msgid "Phone"
msgstr "Telèfon" msgstr "Telèfon"
#: web/templates/public/booking.gohtml:83 #: web/templates/public/booking.gohtml:84
msgctxt "title" msgctxt "title"
msgid "Accommodation" msgid "Accommodation"
msgstr "Allotjaments" msgstr "Allotjaments"
#: web/templates/public/booking.gohtml:98 #: web/templates/public/booking.gohtml:99
msgctxt "input" msgctxt "input"
msgid "Area preferences (optional)" msgid "Area preferences (optional)"
msgstr "Preferències dàrea (opcional)" msgstr "Preferències dàrea (opcional)"
#: web/templates/public/booking.gohtml:120 #: web/templates/public/booking.gohtml:121
msgctxt "title" msgctxt "title"
msgid "Booking Period" msgid "Booking Period"
msgstr "Període de reserva" msgstr "Període de reserva"
#: web/templates/public/booking.gohtml:123 #: web/templates/public/booking.gohtml:124
msgctxt "input" msgctxt "input"
msgid "Arrival date" msgid "Arrival date"
msgstr "Data darribada" msgstr "Data darribada"
#: web/templates/public/booking.gohtml:132 #: web/templates/public/booking.gohtml:133
msgctxt "input" msgctxt "input"
msgid "Departure date" msgid "Departure date"
msgstr "Data de sortida" msgstr "Data de sortida"
#: web/templates/public/booking.gohtml:143 #: web/templates/public/booking.gohtml:144
msgctxt "input" msgctxt "input"
msgid "ACSI card? (optional)" msgid "ACSI card? (optional)"
msgstr "Targeta ACSI? (opcional)" msgstr "Targeta ACSI? (opcional)"
#: web/templates/public/booking.gohtml:150 #: web/templates/public/booking.gohtml:151
msgctxt "input" msgctxt "input"
msgid "I have read and I accept <a href=\"%s\" target=\"_blank\">the reservation conditions</a>" msgid "I have read and I accept <a href=\"%s\" target=\"_blank\">the reservation conditions</a>"
msgstr "He llegit i accepto <a href=\"%s\" target=\"_blank\">les condicions de reserves</a>" msgstr "He llegit i accepto <a href=\"%s\" target=\"_blank\">les condicions de reserves</a>"
@ -406,7 +406,7 @@ msgstr "Menú"
#: web/templates/public/layout.gohtml:58 web/templates/public/layout.gohtml:104 #: web/templates/public/layout.gohtml:58 web/templates/public/layout.gohtml:104
#: web/templates/admin/campsite/index.gohtml:6 #: web/templates/admin/campsite/index.gohtml:6
#: web/templates/admin/campsite/index.gohtml:12 #: web/templates/admin/campsite/index.gohtml:12
#: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:86 #: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:89
msgctxt "title" msgctxt "title"
msgid "Campsites" msgid "Campsites"
msgstr "Allotjaments" msgstr "Allotjaments"
@ -505,12 +505,14 @@ msgstr "Afegeix text legal"
#: web/templates/admin/campsite/option/index.gohtml:25 #: web/templates/admin/campsite/option/index.gohtml:25
#: web/templates/admin/campsite/type/index.gohtml:25 #: web/templates/admin/campsite/type/index.gohtml:25
#: web/templates/admin/season/index.gohtml:26 #: web/templates/admin/season/index.gohtml:26
#: web/templates/admin/user/index.gohtml:17
#: web/templates/admin/surroundings/index.gohtml:26 #: web/templates/admin/surroundings/index.gohtml:26
msgctxt "header" msgctxt "header"
msgid "Name" msgid "Name"
msgstr "Nom" msgstr "Nom"
#: web/templates/admin/legal/index.gohtml:29 #: web/templates/admin/legal/index.gohtml:29
#: web/templates/admin/user/index.gohtml:42
msgid "No legal texts added yet." msgid "No legal texts added yet."
msgstr "No sha afegit cap text legal encara." msgstr "No sha afegit cap text legal encara."
@ -637,6 +639,7 @@ msgstr "Llegenda"
#: web/templates/admin/campsite/carousel/index.gohtml:27 #: web/templates/admin/campsite/carousel/index.gohtml:27
#: web/templates/admin/services/index.gohtml:27 #: web/templates/admin/services/index.gohtml:27
#: web/templates/admin/services/index.gohtml:72 #: web/templates/admin/services/index.gohtml:72
#: web/templates/admin/user/index.gohtml:20
#: web/templates/admin/surroundings/index.gohtml:27 #: web/templates/admin/surroundings/index.gohtml:27
#: web/templates/admin/home/index.gohtml:27 #: web/templates/admin/home/index.gohtml:27
#: web/templates/admin/home/index.gohtml:72 #: web/templates/admin/home/index.gohtml:72
@ -653,6 +656,7 @@ msgstr "Esteu segur de voler esborrar aquesta diapositiva?"
#: web/templates/admin/campsite/carousel/index.gohtml:45 #: web/templates/admin/campsite/carousel/index.gohtml:45
#: web/templates/admin/services/index.gohtml:44 #: web/templates/admin/services/index.gohtml:44
#: web/templates/admin/services/index.gohtml:88 #: web/templates/admin/services/index.gohtml:88
#: web/templates/admin/user/index.gohtml:34
#: web/templates/admin/surroundings/index.gohtml:44 #: web/templates/admin/surroundings/index.gohtml:44
#: web/templates/admin/home/index.gohtml:44 #: web/templates/admin/home/index.gohtml:44
#: web/templates/admin/home/index.gohtml:89 #: web/templates/admin/home/index.gohtml:89
@ -965,7 +969,7 @@ msgid "Integration"
msgstr "Integració" msgstr "Integració"
#: web/templates/admin/dashboard.gohtml:6 #: web/templates/admin/dashboard.gohtml:6
#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:83 #: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:86
msgctxt "title" msgctxt "title"
msgid "Dashboard" msgid "Dashboard"
msgstr "Tauler" msgstr "Tauler"
@ -1058,6 +1062,32 @@ msgctxt "input"
msgid "Language" msgid "Language"
msgstr "Idioma" msgstr "Idioma"
#: web/templates/admin/user/index.gohtml:6
#: web/templates/admin/user/index.gohtml:12
#: web/templates/admin/layout.gohtml:70
msgctxt "title"
msgid "Users"
msgstr "Usuaris"
#: web/templates/admin/user/index.gohtml:11
msgctxt "action"
msgid "Add User"
msgstr "Afegeix usuari"
#: web/templates/admin/user/index.gohtml:18
msgctxt "header"
msgid "Email"
msgstr "Correu-e"
#: web/templates/admin/user/index.gohtml:19
msgctxt "header"
msgid "Role"
msgstr "Rol"
#: web/templates/admin/user/index.gohtml:24
msgid "Are you sure you wish to delete this user?"
msgstr "Esteu segur de voler esborrar aquest usuari?"
#: web/templates/admin/taxDetails.gohtml:6 #: web/templates/admin/taxDetails.gohtml:6
#: web/templates/admin/taxDetails.gohtml:12 #: web/templates/admin/taxDetails.gohtml:12
msgctxt "title" msgctxt "title"
@ -1197,7 +1227,7 @@ msgctxt "title"
msgid "Home Page" msgid "Home Page"
msgstr "Pàgina dinici" msgstr "Pàgina dinici"
#: web/templates/admin/layout.gohtml:72 #: web/templates/admin/layout.gohtml:75
msgctxt "action" msgctxt "action"
msgid "Logout" msgid "Logout"
msgstr "Surt" msgstr "Surt"
@ -1352,7 +1382,7 @@ msgstr "Lidioma escollit no és vàlid."
msgid "File must be a valid PNG or JPEG image." msgid "File must be a valid PNG or JPEG image."
msgstr "El fitxer has de ser una imatge PNG o JPEG vàlida." msgstr "El fitxer has de ser una imatge PNG o JPEG vàlida."
#: pkg/app/admin.go:64 #: pkg/app/admin.go:67
msgid "Access forbidden" msgid "Access forbidden"
msgstr "Accés prohibit" msgstr "Accés prohibit"
@ -1535,6 +1565,21 @@ msgstr "No podeu deixar la data de fi en blanc."
msgid "End date must be a valid date." msgid "End date must be a valid date."
msgstr "La data de fi ha de ser una data vàlida." msgstr "La data de fi ha de ser una data vàlida."
#: pkg/user/admin.go:18
msgctxt "role"
msgid "guest"
msgstr "convidat"
#: pkg/user/admin.go:19
msgctxt "role"
msgid "employee"
msgstr "treballador"
#: pkg/user/admin.go:20
msgctxt "role"
msgid "admin"
msgstr "administrador"
#: pkg/surroundings/admin.go:267 #: pkg/surroundings/admin.go:267
msgctxt "input" msgctxt "input"
msgid "Highlight image" msgid "Highlight image"

109
po/es.po
View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: camper\n" "Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2024-01-16 20:32+0100\n" "POT-Creation-Date: 2024-01-17 19:40+0100\n"
"PO-Revision-Date: 2023-07-22 23:46+0200\n" "PO-Revision-Date: 2023-07-22 23:46+0200\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n" "Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Spanish <es@tp.org.es>\n" "Language-Team: Spanish <es@tp.org.es>\n"
@ -67,24 +67,24 @@ msgctxt "title"
msgid "Home" msgid "Home"
msgstr "Inicio" msgstr "Inicio"
#: web/templates/public/home.gohtml:24 #: web/templates/public/home.gohtml:25
msgctxt "link" msgctxt "link"
msgid "Booking" msgid "Booking"
msgstr "Reservar" msgstr "Reservar"
#: web/templates/public/home.gohtml:31 #: web/templates/public/home.gohtml:28
msgid "The pleasure of camping in the middle of nature…" msgid "The pleasure of camping in the middle of nature…"
msgstr "El placer de acampar en plena naturaleza…" msgstr "El placer de acampar en plena naturaleza…"
#: web/templates/public/home.gohtml:43 #: web/templates/public/home.gohtml:40
msgid "Our services" msgid "Our services"
msgstr "Nuestros servicios" msgstr "Nuestros servicios"
#: web/templates/public/home.gohtml:45 #: web/templates/public/home.gohtml:42
msgid "Come and enjoy!" msgid "Come and enjoy!"
msgstr "¡Ven a disfrutar!" msgstr "¡Ven a disfrutar!"
#: web/templates/public/home.gohtml:47 #: web/templates/public/home.gohtml:44
#: web/templates/public/surroundings.gohtml:7 #: web/templates/public/surroundings.gohtml:7
#: web/templates/public/surroundings.gohtml:12 #: web/templates/public/surroundings.gohtml:12
#: web/templates/public/layout.gohtml:68 web/templates/public/layout.gohtml:96 #: web/templates/public/layout.gohtml:68 web/templates/public/layout.gohtml:96
@ -93,19 +93,19 @@ msgctxt "title"
msgid "Surroundings" msgid "Surroundings"
msgstr "El entorno" msgstr "El entorno"
#: web/templates/public/home.gohtml:50 #: web/templates/public/home.gohtml:47
msgid "Located in <strong>Alta Garrotxa</strong>, between the <strong>Pyrenees</strong> and the <strong>Costa Brava</strong>." msgid "Located in <strong>Alta Garrotxa</strong>, between the <strong>Pyrenees</strong> and the <strong>Costa Brava</strong>."
msgstr "Situados en la <strong>Alta Garrotxa</strong>, entre los <strong>Pirineos</strong> y la <strong>Costa Brava</strong>." msgstr "Situados en la <strong>Alta Garrotxa</strong>, entre los <strong>Pirineos</strong> y la <strong>Costa Brava</strong>."
#: web/templates/public/home.gohtml:51 #: web/templates/public/home.gohtml:48
msgid "Nearby there are the <strong>gorges of Sadernes</strong>, <strong>volcanoes</strong>, <strong>La Fageda den Jordà</strong>, the Jewish quarter of <strong>Besalú</strong>, the basaltic cliff of <strong>Castellfollit de la Roca</strong>… much to see and much to do." msgid "Nearby there are the <strong>gorges of Sadernes</strong>, <strong>volcanoes</strong>, <strong>La Fageda den Jordà</strong>, the Jewish quarter of <strong>Besalú</strong>, the basaltic cliff of <strong>Castellfollit de la Roca</strong>… much to see and much to do."
msgstr "Cerca tenéis los <strong>piletones de Sadernes</strong>, <strong>volcanes</strong>, <strong>La Fageda den Jordà</strong>, la judería de <strong>Besalú</strong>, el riscal basáltico de <strong>Castellfollit de la Roca</strong>… mucho por ver y mucho por hacer." msgstr "Cerca tenéis los <strong>piletones de Sadernes</strong>, <strong>volcanes</strong>, <strong>La Fageda den Jordà</strong>, la judería de <strong>Besalú</strong>, el riscal basáltico de <strong>Castellfollit de la Roca</strong>… mucho por ver y mucho por hacer."
#: web/templates/public/home.gohtml:52 #: web/templates/public/home.gohtml:49
msgid "Less than an hour from <strong>Girona</strong>, one from <strong>La Bisbal dEmpordà</strong>, and two from <strong>Barcelona</strong>." msgid "Less than an hour from <strong>Girona</strong>, one from <strong>La Bisbal dEmpordà</strong>, and two from <strong>Barcelona</strong>."
msgstr "A menos de una hora de <strong>Girona</strong>, a una de <strong>La Bisbal dEmpordà</strong> y a dos de <strong>Barcelona</strong>." msgstr "A menos de una hora de <strong>Girona</strong>, a una de <strong>La Bisbal dEmpordà</strong> y a dos de <strong>Barcelona</strong>."
#: web/templates/public/home.gohtml:53 #: web/templates/public/home.gohtml:50
msgid "Discover the surroundings" msgid "Discover the surroundings"
msgstr "Descubre el entorno" msgstr "Descubre el entorno"
@ -120,7 +120,7 @@ msgid "Check-out Date"
msgstr "Fecha de salida" msgstr "Fecha de salida"
#: web/templates/public/campsite/type.gohtml:54 #: web/templates/public/campsite/type.gohtml:54
#: web/templates/public/booking.gohtml:156 #: web/templates/public/booking.gohtml:164
msgctxt "action" msgctxt "action"
msgid "Book" msgid "Book"
msgstr "Reservar" msgstr "Reservar"
@ -301,91 +301,91 @@ msgctxt "title"
msgid "Campground" msgid "Campground"
msgstr "El camping" msgstr "El camping"
#: web/templates/public/booking.gohtml:6 web/templates/public/booking.gohtml:11 #: web/templates/public/booking.gohtml:7 web/templates/public/booking.gohtml:12
#: web/templates/public/layout.gohtml:70 #: web/templates/public/layout.gohtml:70
msgctxt "title" msgctxt "title"
msgid "Booking" msgid "Booking"
msgstr "Reserva" msgstr "Reserva"
#: web/templates/public/booking.gohtml:15 #: web/templates/public/booking.gohtml:16
msgctxt "title" msgctxt "title"
msgid "Customer Details" msgid "Customer Details"
msgstr "Detalles del cliente" msgstr "Detalles del cliente"
#: web/templates/public/booking.gohtml:18 #: web/templates/public/booking.gohtml:19
msgctxt "input" msgctxt "input"
msgid "Full name" msgid "Full name"
msgstr "Nombre y apellidos" msgstr "Nombre y apellidos"
#: web/templates/public/booking.gohtml:27 #: web/templates/public/booking.gohtml:28
msgctxt "input" msgctxt "input"
msgid "Address (optional)" msgid "Address (optional)"
msgstr "Dirección (opcional)" msgstr "Dirección (opcional)"
#: web/templates/public/booking.gohtml:36 #: web/templates/public/booking.gohtml:37
msgctxt "input" msgctxt "input"
msgid "Postcode (optional)" msgid "Postcode (optional)"
msgstr "Código postal (opcional)" msgstr "Código postal (opcional)"
#: web/templates/public/booking.gohtml:45 #: web/templates/public/booking.gohtml:46
msgctxt "input" msgctxt "input"
msgid "Town or village (optional)" msgid "Town or village (optional)"
msgstr "Población (opcional)" msgstr "Población (opcional)"
#: web/templates/public/booking.gohtml:54 #: web/templates/public/booking.gohtml:55
#: web/templates/admin/taxDetails.gohtml:98 #: web/templates/admin/taxDetails.gohtml:98
msgctxt "input" msgctxt "input"
msgid "Country" msgid "Country"
msgstr "País" msgstr "País"
#: web/templates/public/booking.gohtml:57 #: web/templates/public/booking.gohtml:58
msgid "Choose a country" msgid "Choose a country"
msgstr "Escoja un país" msgstr "Escoja un país"
#: web/templates/public/booking.gohtml:65 web/templates/admin/login.gohtml:22 #: web/templates/public/booking.gohtml:66 web/templates/admin/login.gohtml:22
#: web/templates/admin/profile.gohtml:35 #: web/templates/admin/profile.gohtml:35
#: web/templates/admin/taxDetails.gohtml:50 #: web/templates/admin/taxDetails.gohtml:50
msgctxt "input" msgctxt "input"
msgid "Email" msgid "Email"
msgstr "Correo-e" msgstr "Correo-e"
#: web/templates/public/booking.gohtml:74 #: web/templates/public/booking.gohtml:75
#: web/templates/admin/taxDetails.gohtml:42 #: web/templates/admin/taxDetails.gohtml:42
msgctxt "input" msgctxt "input"
msgid "Phone" msgid "Phone"
msgstr "Teléfono" msgstr "Teléfono"
#: web/templates/public/booking.gohtml:83 #: web/templates/public/booking.gohtml:84
msgctxt "title" msgctxt "title"
msgid "Accommodation" msgid "Accommodation"
msgstr "Alojamientos" msgstr "Alojamientos"
#: web/templates/public/booking.gohtml:98 #: web/templates/public/booking.gohtml:99
msgctxt "input" msgctxt "input"
msgid "Area preferences (optional)" msgid "Area preferences (optional)"
msgstr "Preferencias de área (opcional)" msgstr "Preferencias de área (opcional)"
#: web/templates/public/booking.gohtml:120 #: web/templates/public/booking.gohtml:121
msgctxt "title" msgctxt "title"
msgid "Booking Period" msgid "Booking Period"
msgstr "Periodo de reserva" msgstr "Periodo de reserva"
#: web/templates/public/booking.gohtml:123 #: web/templates/public/booking.gohtml:124
msgctxt "input" msgctxt "input"
msgid "Arrival date" msgid "Arrival date"
msgstr "Fecha de llegada" msgstr "Fecha de llegada"
#: web/templates/public/booking.gohtml:132 #: web/templates/public/booking.gohtml:133
msgctxt "input" msgctxt "input"
msgid "Departure date" msgid "Departure date"
msgstr "Fecha de salida" msgstr "Fecha de salida"
#: web/templates/public/booking.gohtml:143 #: web/templates/public/booking.gohtml:144
msgctxt "input" msgctxt "input"
msgid "ACSI card? (optional)" msgid "ACSI card? (optional)"
msgstr "¿Tarjeta ACSI? (opcional)" msgstr "¿Tarjeta ACSI? (opcional)"
#: web/templates/public/booking.gohtml:150 #: web/templates/public/booking.gohtml:151
msgctxt "input" msgctxt "input"
msgid "I have read and I accept <a href=\"%s\" target=\"_blank\">the reservation conditions</a>" msgid "I have read and I accept <a href=\"%s\" target=\"_blank\">the reservation conditions</a>"
msgstr "He leído y acepto <a href=\"%s\" target=\"_blank\">las condiciones de reserva</a>" msgstr "He leído y acepto <a href=\"%s\" target=\"_blank\">las condiciones de reserva</a>"
@ -406,7 +406,7 @@ msgstr "Menú"
#: web/templates/public/layout.gohtml:58 web/templates/public/layout.gohtml:104 #: web/templates/public/layout.gohtml:58 web/templates/public/layout.gohtml:104
#: web/templates/admin/campsite/index.gohtml:6 #: web/templates/admin/campsite/index.gohtml:6
#: web/templates/admin/campsite/index.gohtml:12 #: web/templates/admin/campsite/index.gohtml:12
#: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:86 #: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:89
msgctxt "title" msgctxt "title"
msgid "Campsites" msgid "Campsites"
msgstr "Alojamientos" msgstr "Alojamientos"
@ -505,12 +505,14 @@ msgstr "Añadir texto legal"
#: web/templates/admin/campsite/option/index.gohtml:25 #: web/templates/admin/campsite/option/index.gohtml:25
#: web/templates/admin/campsite/type/index.gohtml:25 #: web/templates/admin/campsite/type/index.gohtml:25
#: web/templates/admin/season/index.gohtml:26 #: web/templates/admin/season/index.gohtml:26
#: web/templates/admin/user/index.gohtml:17
#: web/templates/admin/surroundings/index.gohtml:26 #: web/templates/admin/surroundings/index.gohtml:26
msgctxt "header" msgctxt "header"
msgid "Name" msgid "Name"
msgstr "Nombre" msgstr "Nombre"
#: web/templates/admin/legal/index.gohtml:29 #: web/templates/admin/legal/index.gohtml:29
#: web/templates/admin/user/index.gohtml:42
msgid "No legal texts added yet." msgid "No legal texts added yet."
msgstr "No se ha añadido ningún texto legal todavía." msgstr "No se ha añadido ningún texto legal todavía."
@ -637,6 +639,7 @@ msgstr "Leyenda"
#: web/templates/admin/campsite/carousel/index.gohtml:27 #: web/templates/admin/campsite/carousel/index.gohtml:27
#: web/templates/admin/services/index.gohtml:27 #: web/templates/admin/services/index.gohtml:27
#: web/templates/admin/services/index.gohtml:72 #: web/templates/admin/services/index.gohtml:72
#: web/templates/admin/user/index.gohtml:20
#: web/templates/admin/surroundings/index.gohtml:27 #: web/templates/admin/surroundings/index.gohtml:27
#: web/templates/admin/home/index.gohtml:27 #: web/templates/admin/home/index.gohtml:27
#: web/templates/admin/home/index.gohtml:72 #: web/templates/admin/home/index.gohtml:72
@ -653,6 +656,7 @@ msgstr "¿Estáis seguro de querer borrar esta diapositiva?"
#: web/templates/admin/campsite/carousel/index.gohtml:45 #: web/templates/admin/campsite/carousel/index.gohtml:45
#: web/templates/admin/services/index.gohtml:44 #: web/templates/admin/services/index.gohtml:44
#: web/templates/admin/services/index.gohtml:88 #: web/templates/admin/services/index.gohtml:88
#: web/templates/admin/user/index.gohtml:34
#: web/templates/admin/surroundings/index.gohtml:44 #: web/templates/admin/surroundings/index.gohtml:44
#: web/templates/admin/home/index.gohtml:44 #: web/templates/admin/home/index.gohtml:44
#: web/templates/admin/home/index.gohtml:89 #: web/templates/admin/home/index.gohtml:89
@ -965,7 +969,7 @@ msgid "Integration"
msgstr "Integración" msgstr "Integración"
#: web/templates/admin/dashboard.gohtml:6 #: web/templates/admin/dashboard.gohtml:6
#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:83 #: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:86
msgctxt "title" msgctxt "title"
msgid "Dashboard" msgid "Dashboard"
msgstr "Panel" msgstr "Panel"
@ -1058,6 +1062,32 @@ msgctxt "input"
msgid "Language" msgid "Language"
msgstr "Idioma" msgstr "Idioma"
#: web/templates/admin/user/index.gohtml:6
#: web/templates/admin/user/index.gohtml:12
#: web/templates/admin/layout.gohtml:70
msgctxt "title"
msgid "Users"
msgstr ""
#: web/templates/admin/user/index.gohtml:11
msgctxt "action"
msgid "Add User"
msgstr "Añadir usuario"
#: web/templates/admin/user/index.gohtml:18
msgctxt "header"
msgid "Email"
msgstr "Correo-e"
#: web/templates/admin/user/index.gohtml:19
msgctxt "header"
msgid "Role"
msgstr "Rol"
#: web/templates/admin/user/index.gohtml:24
msgid "Are you sure you wish to delete this user?"
msgstr "¿Estáis seguro de querer borrar este usuario?"
#: web/templates/admin/taxDetails.gohtml:6 #: web/templates/admin/taxDetails.gohtml:6
#: web/templates/admin/taxDetails.gohtml:12 #: web/templates/admin/taxDetails.gohtml:12
msgctxt "title" msgctxt "title"
@ -1197,7 +1227,7 @@ msgctxt "title"
msgid "Home Page" msgid "Home Page"
msgstr "Página de inicio" msgstr "Página de inicio"
#: web/templates/admin/layout.gohtml:72 #: web/templates/admin/layout.gohtml:75
msgctxt "action" msgctxt "action"
msgid "Logout" msgid "Logout"
msgstr "Salir" msgstr "Salir"
@ -1352,7 +1382,7 @@ msgstr "El idioma escogido no es válido."
msgid "File must be a valid PNG or JPEG image." msgid "File must be a valid PNG or JPEG image."
msgstr "El archivo tiene que ser una imagen PNG o JPEG válida." msgstr "El archivo tiene que ser una imagen PNG o JPEG válida."
#: pkg/app/admin.go:64 #: pkg/app/admin.go:67
msgid "Access forbidden" msgid "Access forbidden"
msgstr "Acceso prohibido" msgstr "Acceso prohibido"
@ -1535,6 +1565,21 @@ msgstr "No podéis dejar la fecha final en blanco."
msgid "End date must be a valid date." msgid "End date must be a valid date."
msgstr "La fecha final tiene que ser una fecha válida." msgstr "La fecha final tiene que ser una fecha válida."
#: pkg/user/admin.go:18
msgctxt "role"
msgid "guest"
msgstr "invitado"
#: pkg/user/admin.go:19
msgctxt "role"
msgid "employee"
msgstr "trabajador"
#: pkg/user/admin.go:20
msgctxt "role"
msgid "admin"
msgstr "administrador"
#: pkg/surroundings/admin.go:267 #: pkg/surroundings/admin.go:267
msgctxt "input" msgctxt "input"
msgid "Highlight image" msgid "Highlight image"

109
po/fr.po
View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: camper\n" "Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2024-01-16 20:32+0100\n" "POT-Creation-Date: 2024-01-17 19:40+0100\n"
"PO-Revision-Date: 2023-12-20 10:13+0100\n" "PO-Revision-Date: 2023-12-20 10:13+0100\n"
"Last-Translator: Oriol Carbonell <info@oriolcarbonell.cat>\n" "Last-Translator: Oriol Carbonell <info@oriolcarbonell.cat>\n"
"Language-Team: French <traduc@traduc.org>\n" "Language-Team: French <traduc@traduc.org>\n"
@ -68,24 +68,24 @@ msgctxt "title"
msgid "Home" msgid "Home"
msgstr "Accueil" msgstr "Accueil"
#: web/templates/public/home.gohtml:24 #: web/templates/public/home.gohtml:25
msgctxt "link" msgctxt "link"
msgid "Booking" msgid "Booking"
msgstr "Réservation" msgstr "Réservation"
#: web/templates/public/home.gohtml:31 #: web/templates/public/home.gohtml:28
msgid "The pleasure of camping in the middle of nature…" msgid "The pleasure of camping in the middle of nature…"
msgstr "Le plaisir de camper en pleine nature…" msgstr "Le plaisir de camper en pleine nature…"
#: web/templates/public/home.gohtml:43 #: web/templates/public/home.gohtml:40
msgid "Our services" msgid "Our services"
msgstr "Nos services" msgstr "Nos services"
#: web/templates/public/home.gohtml:45 #: web/templates/public/home.gohtml:42
msgid "Come and enjoy!" msgid "Come and enjoy!"
msgstr "Venez et profitez-en !" msgstr "Venez et profitez-en !"
#: web/templates/public/home.gohtml:47 #: web/templates/public/home.gohtml:44
#: web/templates/public/surroundings.gohtml:7 #: web/templates/public/surroundings.gohtml:7
#: web/templates/public/surroundings.gohtml:12 #: web/templates/public/surroundings.gohtml:12
#: web/templates/public/layout.gohtml:68 web/templates/public/layout.gohtml:96 #: web/templates/public/layout.gohtml:68 web/templates/public/layout.gohtml:96
@ -94,19 +94,19 @@ msgctxt "title"
msgid "Surroundings" msgid "Surroundings"
msgstr "Entourage" msgstr "Entourage"
#: web/templates/public/home.gohtml:50 #: web/templates/public/home.gohtml:47
msgid "Located in <strong>Alta Garrotxa</strong>, between the <strong>Pyrenees</strong> and the <strong>Costa Brava</strong>." msgid "Located in <strong>Alta Garrotxa</strong>, between the <strong>Pyrenees</strong> and the <strong>Costa Brava</strong>."
msgstr "Situé dans <strong>lAlta Garrotxa</strong>, entre les <strong>Pyrénées</strong> et la <strong>Costa Brava</strong>." msgstr "Situé dans <strong>lAlta Garrotxa</strong>, entre les <strong>Pyrénées</strong> et la <strong>Costa Brava</strong>."
#: web/templates/public/home.gohtml:51 #: web/templates/public/home.gohtml:48
msgid "Nearby there are the <strong>gorges of Sadernes</strong>, <strong>volcanoes</strong>, <strong>La Fageda den Jordà</strong>, the Jewish quarter of <strong>Besalú</strong>, the basaltic cliff of <strong>Castellfollit de la Roca</strong>… much to see and much to do." msgid "Nearby there are the <strong>gorges of Sadernes</strong>, <strong>volcanoes</strong>, <strong>La Fageda den Jordà</strong>, the Jewish quarter of <strong>Besalú</strong>, the basaltic cliff of <strong>Castellfollit de la Roca</strong>… much to see and much to do."
msgstr "A proximité il y a les <strong>gorges de Sadernes</strong>, les <strong>volcans</strong>, <strong>La Fageda dâen Jordã </strong>, le quartier juif de <strong>Besalú</strong>, la falaise basaltique de <strong>Castellfollit de la Roca</strong>… beaucoup à voir et beaucoup à faire." msgstr "A proximité il y a les <strong>gorges de Sadernes</strong>, les <strong>volcans</strong>, <strong>La Fageda dâen Jordã </strong>, le quartier juif de <strong>Besalú</strong>, la falaise basaltique de <strong>Castellfollit de la Roca</strong>… beaucoup à voir et beaucoup à faire."
#: web/templates/public/home.gohtml:52 #: web/templates/public/home.gohtml:49
msgid "Less than an hour from <strong>Girona</strong>, one from <strong>La Bisbal dEmpordà</strong>, and two from <strong>Barcelona</strong>." msgid "Less than an hour from <strong>Girona</strong>, one from <strong>La Bisbal dEmpordà</strong>, and two from <strong>Barcelona</strong>."
msgstr "À moins dune heure de <strong>Gérone</strong>, un de <strong>La Bisbal dEmpordà</strong>et deux de <strong>Barcelone</strong>." msgstr "À moins dune heure de <strong>Gérone</strong>, un de <strong>La Bisbal dEmpordà</strong>et deux de <strong>Barcelone</strong>."
#: web/templates/public/home.gohtml:53 #: web/templates/public/home.gohtml:50
msgid "Discover the surroundings" msgid "Discover the surroundings"
msgstr "Découvrir les environs" msgstr "Découvrir les environs"
@ -121,7 +121,7 @@ msgid "Check-out Date"
msgstr "Date de départ" msgstr "Date de départ"
#: web/templates/public/campsite/type.gohtml:54 #: web/templates/public/campsite/type.gohtml:54
#: web/templates/public/booking.gohtml:156 #: web/templates/public/booking.gohtml:164
msgctxt "action" msgctxt "action"
msgid "Book" msgid "Book"
msgstr "Réserver" msgstr "Réserver"
@ -302,91 +302,91 @@ msgctxt "title"
msgid "Campground" msgid "Campground"
msgstr "Camping" msgstr "Camping"
#: web/templates/public/booking.gohtml:6 web/templates/public/booking.gohtml:11 #: web/templates/public/booking.gohtml:7 web/templates/public/booking.gohtml:12
#: web/templates/public/layout.gohtml:70 #: web/templates/public/layout.gohtml:70
msgctxt "title" msgctxt "title"
msgid "Booking" msgid "Booking"
msgstr "Reservation" msgstr "Reservation"
#: web/templates/public/booking.gohtml:15 #: web/templates/public/booking.gohtml:16
msgctxt "title" msgctxt "title"
msgid "Customer Details" msgid "Customer Details"
msgstr "Détails du client" msgstr "Détails du client"
#: web/templates/public/booking.gohtml:18 #: web/templates/public/booking.gohtml:19
msgctxt "input" msgctxt "input"
msgid "Full name" msgid "Full name"
msgstr "Nom et prénom" msgstr "Nom et prénom"
#: web/templates/public/booking.gohtml:27 #: web/templates/public/booking.gohtml:28
msgctxt "input" msgctxt "input"
msgid "Address (optional)" msgid "Address (optional)"
msgstr "Adresse (Facultatif)" msgstr "Adresse (Facultatif)"
#: web/templates/public/booking.gohtml:36 #: web/templates/public/booking.gohtml:37
msgctxt "input" msgctxt "input"
msgid "Postcode (optional)" msgid "Postcode (optional)"
msgstr "Code postal (Facultatif)" msgstr "Code postal (Facultatif)"
#: web/templates/public/booking.gohtml:45 #: web/templates/public/booking.gohtml:46
msgctxt "input" msgctxt "input"
msgid "Town or village (optional)" msgid "Town or village (optional)"
msgstr "Ville (Facultatif)" msgstr "Ville (Facultatif)"
#: web/templates/public/booking.gohtml:54 #: web/templates/public/booking.gohtml:55
#: web/templates/admin/taxDetails.gohtml:98 #: web/templates/admin/taxDetails.gohtml:98
msgctxt "input" msgctxt "input"
msgid "Country" msgid "Country"
msgstr "Pays" msgstr "Pays"
#: web/templates/public/booking.gohtml:57 #: web/templates/public/booking.gohtml:58
msgid "Choose a country" msgid "Choose a country"
msgstr "Choisissez un pays" msgstr "Choisissez un pays"
#: web/templates/public/booking.gohtml:65 web/templates/admin/login.gohtml:22 #: web/templates/public/booking.gohtml:66 web/templates/admin/login.gohtml:22
#: web/templates/admin/profile.gohtml:35 #: web/templates/admin/profile.gohtml:35
#: web/templates/admin/taxDetails.gohtml:50 #: web/templates/admin/taxDetails.gohtml:50
msgctxt "input" msgctxt "input"
msgid "Email" msgid "Email"
msgstr "E-mail" msgstr "E-mail"
#: web/templates/public/booking.gohtml:74 #: web/templates/public/booking.gohtml:75
#: web/templates/admin/taxDetails.gohtml:42 #: web/templates/admin/taxDetails.gohtml:42
msgctxt "input" msgctxt "input"
msgid "Phone" msgid "Phone"
msgstr "Téléphone" msgstr "Téléphone"
#: web/templates/public/booking.gohtml:83 #: web/templates/public/booking.gohtml:84
msgctxt "title" msgctxt "title"
msgid "Accommodation" msgid "Accommodation"
msgstr "Hébergement" msgstr "Hébergement"
#: web/templates/public/booking.gohtml:98 #: web/templates/public/booking.gohtml:99
msgctxt "input" msgctxt "input"
msgid "Area preferences (optional)" msgid "Area preferences (optional)"
msgstr "Préférences de zone (facultatif)" msgstr "Préférences de zone (facultatif)"
#: web/templates/public/booking.gohtml:120 #: web/templates/public/booking.gohtml:121
msgctxt "title" msgctxt "title"
msgid "Booking Period" msgid "Booking Period"
msgstr "Période de réservation" msgstr "Période de réservation"
#: web/templates/public/booking.gohtml:123 #: web/templates/public/booking.gohtml:124
msgctxt "input" msgctxt "input"
msgid "Arrival date" msgid "Arrival date"
msgstr "Date darrivée" msgstr "Date darrivée"
#: web/templates/public/booking.gohtml:132 #: web/templates/public/booking.gohtml:133
msgctxt "input" msgctxt "input"
msgid "Departure date" msgid "Departure date"
msgstr "Date de depart" msgstr "Date de depart"
#: web/templates/public/booking.gohtml:143 #: web/templates/public/booking.gohtml:144
msgctxt "input" msgctxt "input"
msgid "ACSI card? (optional)" msgid "ACSI card? (optional)"
msgstr "Carte ACSI ? (Facultatif)" msgstr "Carte ACSI ? (Facultatif)"
#: web/templates/public/booking.gohtml:150 #: web/templates/public/booking.gohtml:151
msgctxt "input" msgctxt "input"
msgid "I have read and I accept <a href=\"%s\" target=\"_blank\">the reservation conditions</a>" msgid "I have read and I accept <a href=\"%s\" target=\"_blank\">the reservation conditions</a>"
msgstr "Jai lu et jaccepte <a href=\"%s\" target=\"_blank\">les conditions de réservation</a>" msgstr "Jai lu et jaccepte <a href=\"%s\" target=\"_blank\">les conditions de réservation</a>"
@ -407,7 +407,7 @@ msgstr "Menu"
#: web/templates/public/layout.gohtml:58 web/templates/public/layout.gohtml:104 #: web/templates/public/layout.gohtml:58 web/templates/public/layout.gohtml:104
#: web/templates/admin/campsite/index.gohtml:6 #: web/templates/admin/campsite/index.gohtml:6
#: web/templates/admin/campsite/index.gohtml:12 #: web/templates/admin/campsite/index.gohtml:12
#: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:86 #: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:89
msgctxt "title" msgctxt "title"
msgid "Campsites" msgid "Campsites"
msgstr "Locatifs" msgstr "Locatifs"
@ -506,12 +506,14 @@ msgstr "Ajouter un texte juridique"
#: web/templates/admin/campsite/option/index.gohtml:25 #: web/templates/admin/campsite/option/index.gohtml:25
#: web/templates/admin/campsite/type/index.gohtml:25 #: web/templates/admin/campsite/type/index.gohtml:25
#: web/templates/admin/season/index.gohtml:26 #: web/templates/admin/season/index.gohtml:26
#: web/templates/admin/user/index.gohtml:17
#: web/templates/admin/surroundings/index.gohtml:26 #: web/templates/admin/surroundings/index.gohtml:26
msgctxt "header" msgctxt "header"
msgid "Name" msgid "Name"
msgstr "Nom" msgstr "Nom"
#: web/templates/admin/legal/index.gohtml:29 #: web/templates/admin/legal/index.gohtml:29
#: web/templates/admin/user/index.gohtml:42
msgid "No legal texts added yet." msgid "No legal texts added yet."
msgstr "Aucune texte juridique na encore été ajoutée." msgstr "Aucune texte juridique na encore été ajoutée."
@ -638,6 +640,7 @@ msgstr "Légende"
#: web/templates/admin/campsite/carousel/index.gohtml:27 #: web/templates/admin/campsite/carousel/index.gohtml:27
#: web/templates/admin/services/index.gohtml:27 #: web/templates/admin/services/index.gohtml:27
#: web/templates/admin/services/index.gohtml:72 #: web/templates/admin/services/index.gohtml:72
#: web/templates/admin/user/index.gohtml:20
#: web/templates/admin/surroundings/index.gohtml:27 #: web/templates/admin/surroundings/index.gohtml:27
#: web/templates/admin/home/index.gohtml:27 #: web/templates/admin/home/index.gohtml:27
#: web/templates/admin/home/index.gohtml:72 #: web/templates/admin/home/index.gohtml:72
@ -654,6 +657,7 @@ msgstr "Êtes-vous sûr de vouloir supprimer cette diapositive ?"
#: web/templates/admin/campsite/carousel/index.gohtml:45 #: web/templates/admin/campsite/carousel/index.gohtml:45
#: web/templates/admin/services/index.gohtml:44 #: web/templates/admin/services/index.gohtml:44
#: web/templates/admin/services/index.gohtml:88 #: web/templates/admin/services/index.gohtml:88
#: web/templates/admin/user/index.gohtml:34
#: web/templates/admin/surroundings/index.gohtml:44 #: web/templates/admin/surroundings/index.gohtml:44
#: web/templates/admin/home/index.gohtml:44 #: web/templates/admin/home/index.gohtml:44
#: web/templates/admin/home/index.gohtml:89 #: web/templates/admin/home/index.gohtml:89
@ -966,7 +970,7 @@ msgid "Integration"
msgstr "Intégration" msgstr "Intégration"
#: web/templates/admin/dashboard.gohtml:6 #: web/templates/admin/dashboard.gohtml:6
#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:83 #: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:86
msgctxt "title" msgctxt "title"
msgid "Dashboard" msgid "Dashboard"
msgstr "Tableau de bord" msgstr "Tableau de bord"
@ -1059,6 +1063,32 @@ msgctxt "input"
msgid "Language" msgid "Language"
msgstr "Langue" msgstr "Langue"
#: web/templates/admin/user/index.gohtml:6
#: web/templates/admin/user/index.gohtml:12
#: web/templates/admin/layout.gohtml:70
msgctxt "title"
msgid "Users"
msgstr "Utilisateurs"
#: web/templates/admin/user/index.gohtml:11
msgctxt "action"
msgid "Add User"
msgstr "Ajouter un utilisateur"
#: web/templates/admin/user/index.gohtml:18
msgctxt "header"
msgid "Email"
msgstr "E-mail"
#: web/templates/admin/user/index.gohtml:19
msgctxt "header"
msgid "Role"
msgstr "Rôle"
#: web/templates/admin/user/index.gohtml:24
msgid "Are you sure you wish to delete this user?"
msgstr "Êtes-vous sûr de vouloir supprimer ce utilisateur ?"
#: web/templates/admin/taxDetails.gohtml:6 #: web/templates/admin/taxDetails.gohtml:6
#: web/templates/admin/taxDetails.gohtml:12 #: web/templates/admin/taxDetails.gohtml:12
msgctxt "title" msgctxt "title"
@ -1198,7 +1228,7 @@ msgctxt "title"
msgid "Home Page" msgid "Home Page"
msgstr "Page d'accueil" msgstr "Page d'accueil"
#: web/templates/admin/layout.gohtml:72 #: web/templates/admin/layout.gohtml:75
msgctxt "action" msgctxt "action"
msgid "Logout" msgid "Logout"
msgstr "Déconnexion" msgstr "Déconnexion"
@ -1353,7 +1383,7 @@ msgstr "La langue sélectionnée nest pas valide."
msgid "File must be a valid PNG or JPEG image." msgid "File must be a valid PNG or JPEG image."
msgstr "Le fichier doit être une image PNG ou JPEG valide." msgstr "Le fichier doit être une image PNG ou JPEG valide."
#: pkg/app/admin.go:64 #: pkg/app/admin.go:67
msgid "Access forbidden" msgid "Access forbidden"
msgstr "Accès interdit" msgstr "Accès interdit"
@ -1536,6 +1566,21 @@ msgstr "La date de fin ne peut pas être vide."
msgid "End date must be a valid date." msgid "End date must be a valid date."
msgstr "La date de fin doit être une date valide." msgstr "La date de fin doit être une date valide."
#: pkg/user/admin.go:18
msgctxt "role"
msgid "guest"
msgstr "invité"
#: pkg/user/admin.go:19
msgctxt "role"
msgid "employee"
msgstr "employé"
#: pkg/user/admin.go:20
msgctxt "role"
msgid "admin"
msgstr "administrateur"
#: pkg/surroundings/admin.go:267 #: pkg/surroundings/admin.go:267
msgctxt "input" msgctxt "input"
msgid "Highlight image" msgid "Highlight image"

View File

@ -0,0 +1,7 @@
-- Revert camper:company_user_profile from pg
begin;
drop view if exists camper.company_user_profile;
commit;

View File

@ -154,3 +154,4 @@ add_cover_carousel_slide [roles schema_camper cover_carousel] 2024-01-16T17:49:2
translate_cover_carousel_slide [roles schema_camper cover_carousel_i18n] 2024-01-16T18:17:36Z jordi fita mas <jordi@tandem.blog> # Add function to translate a cover carousel slider translate_cover_carousel_slide [roles schema_camper cover_carousel_i18n] 2024-01-16T18:17:36Z jordi fita mas <jordi@tandem.blog> # Add function to translate a cover carousel slider
remove_cover_carousel_slide [roles schema_camper cover_carousel cover_carousel_i18n] 2024-01-16T18:27:48Z jordi fita mas <jordi@tandem.blog> # Add function to remove sliders from the cover carousel remove_cover_carousel_slide [roles schema_camper cover_carousel cover_carousel_i18n] 2024-01-16T18:27:48Z jordi fita mas <jordi@tandem.blog> # Add function to remove sliders from the cover carousel
order_cover_carousel [schema_camper roles cover_carousel] 2024-01-16T18:40:12Z jordi fita mas <jordi@tandem.blog> # Add function to order cover carousel order_cover_carousel [schema_camper roles cover_carousel] 2024-01-16T18:40:12Z jordi fita mas <jordi@tandem.blog> # Add function to order cover carousel
company_user_profile [roles schema_camper user company_user current_company_id] 2024-01-17T17:37:19Z jordi fita mas <jordi@tandem.blog> # Add view to list users for admins

View File

@ -0,0 +1,113 @@
-- Test company_user_profile
set client_min_messages to warning;
create extension if not exists pgtap;
reset client_min_messages;
begin;
select plan(37);
set search_path to camper, auth, public;
select has_view('company_user_profile');
select table_privs_are('company_user_profile', 'guest', array []::text[]);
select table_privs_are('company_user_profile', 'employee', array []::text[]);
select table_privs_are('company_user_profile', 'admin', array ['SELECT']);
select table_privs_are('company_user_profile', 'authenticator', array []::text[]);
select has_column('company_user_profile', 'user_id');
select col_type_is('company_user_profile', 'user_id', 'integer');
select column_privs_are('company_user_profile', 'user_id', 'guest', array []::text[]);
select column_privs_are('company_user_profile', 'user_id', 'employee', array []::text[]);
select column_privs_are('company_user_profile', 'user_id', 'admin', array ['SELECT']);
select column_privs_are('company_user_profile', 'user_id', 'authenticator', array []::text[]);
select has_column('company_user_profile', 'email');
select col_type_is('company_user_profile', 'email', 'email');
select column_privs_are('company_user_profile', 'email', 'guest', array []::text[]);
select column_privs_are('company_user_profile', 'email', 'employee', array []::text[]);
select column_privs_are('company_user_profile', 'email', 'admin', array ['SELECT']);
select column_privs_are('company_user_profile', 'email', 'authenticator', array []::text[]);
select has_column('company_user_profile', 'name');
select col_type_is('company_user_profile', 'name', 'text');
select column_privs_are('company_user_profile', 'name', 'guest', array []::text[]);
select column_privs_are('company_user_profile', 'name', 'employee', array []::text[]);
select column_privs_are('company_user_profile', 'name', 'admin', array ['SELECT']);
select column_privs_are('company_user_profile', 'name', 'authenticator', array []::text[]);
select has_column('company_user_profile', 'role');
select col_type_is('company_user_profile', 'role', 'name');
select column_privs_are('company_user_profile', 'role', 'guest', array []::text[]);
select column_privs_are('company_user_profile', 'role', 'employee', array []::text[]);
select column_privs_are('company_user_profile', 'role', 'admin', array ['SELECT']);
select column_privs_are('company_user_profile', 'role', 'authenticator', array []::text[]);
select has_column('company_user_profile', 'lang_tag');
select col_type_is('company_user_profile', 'lang_tag', 'text');
select column_privs_are('company_user_profile', 'lang_tag', 'guest', array []::text[]);
select column_privs_are('company_user_profile', 'lang_tag', 'employee', array []::text[]);
select column_privs_are('company_user_profile', 'lang_tag', 'admin', array ['SELECT']);
select column_privs_are('company_user_profile', 'lang_tag', 'authenticator', array []::text[]);
set client_min_messages to warning;
truncate company_host cascade;
truncate company_user cascade;
truncate company cascade;
truncate auth."user" cascade;
reset client_min_messages;
insert into auth."user" (user_id, email, name, password, cookie, cookie_expires_at, lang_tag)
values (1, 'demo@tandem.blog', 'Demo', 'test', '44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e', current_timestamp + interval '1 month', 'ca')
, (5, 'admin@tandem.blog', 'Admin', 'test', '12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524', current_timestamp + interval '1 month', 'es')
, (7, 'another@tandem.blog', 'Another Employee', 'test', default, default, default)
;
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, rtc_number, tourist_tax, country_code, currency_code, default_lang_tag)
values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 60, 'ES', 'EUR', 'ca')
, (4, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', '', 60, 'FR', 'USD', 'es')
;
insert into company_user (company_id, user_id, role)
values (2, 1, 'admin')
, (4, 5, 'admin')
, (4, 7, 'employee')
;
insert into company_host (company_id, host)
values (2, 'co2')
, (4, 'co4')
;
prepare profile as
select user_id, email::text, name, role::text, lang_tag
from company_user_profile
;
select set_cookie('44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e/demo@tandem.blog', 'co2');
select bag_eq(
'profile',
$$ values (1, 'demo@tandem.blog', 'Demo', 'admin', 'ca') $$,
'Should only see profiles from the first company'
);
reset role;
select set_cookie('12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524/admin@tandem.blog', 'co4');
select bag_eq(
'profile',
$$ values (5, 'admin@tandem.blog', 'Admin', 'admin', 'es')
, (7, 'another@tandem.blog', 'Another Employee', 'employee', 'und')
$$,
'Should only see profiles from the second company'
);
reset role;
select *
from finish();
rollback;

View File

@ -0,0 +1,13 @@
-- Verify camper:company_user_profile on pg
begin;
select user_id
, email
, name
, role
, lang_tag
from camper.company_user_profile
where false;
rollback;

View File

@ -66,6 +66,9 @@
<li> <li>
<a href="/admin/legal">{{( pgettext "Legal Texts" "title" )}}</a> <a href="/admin/legal">{{( pgettext "Legal Texts" "title" )}}</a>
</li> </li>
<li>
<a href="/admin/users">{{( pgettext "Users" "title" )}}</a>
</li>
{{- end }} {{- end }}
<li class="icon_logout"> <li class="icon_logout">
<button data-hx-delete="/me/session" data-hx-headers='{ {{ CSRFHeader }} }' <button data-hx-delete="/me/session" data-hx-headers='{ {{ CSRFHeader }} }'

View File

@ -0,0 +1,44 @@
<!--
SPDX-FileCopyrightText: 2023 jordi fita mas <jordi@tandem.blog>
SPDX-License-Identifier: AGPL-3.0-only
-->
{{ define "title" -}}
{{( pgettext "Users" "title" )}}
{{- end }}
{{ define "content" -}}
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/user.userIndex*/ -}}
<a href="/admin/users/new">{{( pgettext "Add User" "action" )}}</a>
<h2>{{( pgettext "Users" "title" )}}</h2>
{{ if .Users -}}
<table>
<thead>
<tr>
<th scope="col">{{( pgettext "Name" "header" )}}</th>
<th scope="col">{{( pgettext "Email" "header" )}}</th>
<th scope="col">{{( pgettext "Role" "header" )}}</th>
<th scope="col">{{( pgettext "Actions" "header" )}}</th>
</tr>
</thead>
<tbody>
{{ $confirm := ( gettext "Are you sure you wish to delete this user?" )}}
{{ range .Users -}}
<tr>
<td><a href="{{ .URL }}">{{ .Name }}</a></td>
<td><a href="{{ .URL }}">{{ .Email }}</a></td>
<td>{{( pgettext .Role "role" )}}</td>
<td>
<button data-hx-delete="{{ .URL }}"
data-hx-confirm="{{ $confirm }}"
data-hx-headers='{ {{ CSRFHeader }} }'>
{{( pgettext "Delete" "action" )}}
</button>
</td>
</tr>
{{- end }}
</tbody>
</table>
{{ else -}}
<p>{{( gettext "No legal texts added yet." )}}</p>
{{- end }}
{{- end }}