diff --git a/deploy/company_user_profile.sql b/deploy/company_user_profile.sql new file mode 100644 index 0000000..11d1265 --- /dev/null +++ b/deploy/company_user_profile.sql @@ -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; diff --git a/pkg/app/admin.go b/pkg/app/admin.go index 8846a9b..4c2a64b 100644 --- a/pkg/app/admin.go +++ b/pkg/app/admin.go @@ -22,6 +22,7 @@ import ( "dev.tandem.ws/tandem/camper/pkg/services" "dev.tandem.ws/tandem/camper/pkg/surroundings" "dev.tandem.ws/tandem/camper/pkg/template" + "dev.tandem.ws/tandem/camper/pkg/user" ) type adminHandler struct { @@ -35,6 +36,7 @@ type adminHandler struct { season *season.AdminHandler services *services.AdminHandler surroundings *surroundings.AdminHandler + user *user.AdminHandler } func newAdminHandler(mediaDir string) *adminHandler { @@ -49,6 +51,7 @@ func newAdminHandler(mediaDir string) *adminHandler { season: season.NewAdminHandler(), services: services.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) case "surroundings": h.surroundings.Handler(user, company, conn).ServeHTTP(w, r) + case "users": + h.user.Handler(user, company, conn).ServeHTTP(w, r) case "": switch r.Method { case http.MethodGet: diff --git a/pkg/user/admin.go b/pkg/user/admin.go new file mode 100644 index 0000000..9d5f060 --- /dev/null +++ b/pkg/user/admin.go @@ -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) +} diff --git a/po/ca.po b/po/ca.po index d85ecaf..7fca88f 100644 --- a/po/ca.po +++ b/po/ca.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: camper\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" "Last-Translator: jordi fita mas \n" "Language-Team: Catalan \n" @@ -67,24 +67,24 @@ msgctxt "title" msgid "Home" msgstr "Inici" -#: web/templates/public/home.gohtml:24 +#: web/templates/public/home.gohtml:25 msgctxt "link" msgid "Booking" msgstr "Reserva" -#: web/templates/public/home.gohtml:31 +#: web/templates/public/home.gohtml:28 msgid "The pleasure of camping in the middle of nature…" msgstr "El plaer d’acampar en plena natura…" -#: web/templates/public/home.gohtml:43 +#: web/templates/public/home.gohtml:40 msgid "Our services" msgstr "Els nostres serveis" -#: web/templates/public/home.gohtml:45 +#: web/templates/public/home.gohtml:42 msgid "Come and enjoy!" 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:12 #: web/templates/public/layout.gohtml:68 web/templates/public/layout.gohtml:96 @@ -93,19 +93,19 @@ msgctxt "title" msgid "Surroundings" msgstr "L’entorn" -#: web/templates/public/home.gohtml:50 +#: web/templates/public/home.gohtml:47 msgid "Located in Alta Garrotxa, between the Pyrenees and the Costa Brava." msgstr "Situats a l’Alta Garrotxa, entre els Pirineus i la Costa Brava." -#: web/templates/public/home.gohtml:51 +#: web/templates/public/home.gohtml:48 msgid "Nearby there are the gorges of Sadernes, volcanoes, La Fageda d’en Jordà, the Jewish quarter of Besalú, the basaltic cliff of Castellfollit de la Roca… much to see and much to do." msgstr "A prop teniu els gorgs de Sadernes, volcans, La Fageda d’en Jordà, el call jueu de Besalú, la cinglera basàltica de Castellfollit de la Roca… 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 Girona, one from La Bisbal d’Empordà, and two from Barcelona." msgstr "A menys d’una hora de Girona, a una de La Bisbal d’Empordà i a dues de Barcelona." -#: web/templates/public/home.gohtml:53 +#: web/templates/public/home.gohtml:50 msgid "Discover the surroundings" msgstr "Descobreix l’entorn" @@ -120,7 +120,7 @@ msgid "Check-out Date" msgstr "Data de sortida" #: web/templates/public/campsite/type.gohtml:54 -#: web/templates/public/booking.gohtml:156 +#: web/templates/public/booking.gohtml:164 msgctxt "action" msgid "Book" msgstr "Reserva" @@ -301,91 +301,91 @@ msgctxt "title" msgid "Campground" 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 msgctxt "title" msgid "Booking" msgstr "Reserva" -#: web/templates/public/booking.gohtml:15 +#: web/templates/public/booking.gohtml:16 msgctxt "title" msgid "Customer Details" msgstr "Detalls del client" -#: web/templates/public/booking.gohtml:18 +#: web/templates/public/booking.gohtml:19 msgctxt "input" msgid "Full name" msgstr "Nom i cognoms" -#: web/templates/public/booking.gohtml:27 +#: web/templates/public/booking.gohtml:28 msgctxt "input" msgid "Address (optional)" msgstr "Adreça (opcional)" -#: web/templates/public/booking.gohtml:36 +#: web/templates/public/booking.gohtml:37 msgctxt "input" msgid "Postcode (optional)" msgstr "Codi postal (opcional)" -#: web/templates/public/booking.gohtml:45 +#: web/templates/public/booking.gohtml:46 msgctxt "input" msgid "Town or village (optional)" msgstr "Població (opcional)" -#: web/templates/public/booking.gohtml:54 +#: web/templates/public/booking.gohtml:55 #: web/templates/admin/taxDetails.gohtml:98 msgctxt "input" msgid "Country" msgstr "País" -#: web/templates/public/booking.gohtml:57 +#: web/templates/public/booking.gohtml:58 msgid "Choose a country" 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/taxDetails.gohtml:50 msgctxt "input" msgid "Email" msgstr "Correu-e" -#: web/templates/public/booking.gohtml:74 +#: web/templates/public/booking.gohtml:75 #: web/templates/admin/taxDetails.gohtml:42 msgctxt "input" msgid "Phone" msgstr "Telèfon" -#: web/templates/public/booking.gohtml:83 +#: web/templates/public/booking.gohtml:84 msgctxt "title" msgid "Accommodation" msgstr "Allotjaments" -#: web/templates/public/booking.gohtml:98 +#: web/templates/public/booking.gohtml:99 msgctxt "input" msgid "Area preferences (optional)" msgstr "Preferències d’àrea (opcional)" -#: web/templates/public/booking.gohtml:120 +#: web/templates/public/booking.gohtml:121 msgctxt "title" msgid "Booking Period" msgstr "Període de reserva" -#: web/templates/public/booking.gohtml:123 +#: web/templates/public/booking.gohtml:124 msgctxt "input" msgid "Arrival date" msgstr "Data d’arribada" -#: web/templates/public/booking.gohtml:132 +#: web/templates/public/booking.gohtml:133 msgctxt "input" msgid "Departure date" msgstr "Data de sortida" -#: web/templates/public/booking.gohtml:143 +#: web/templates/public/booking.gohtml:144 msgctxt "input" msgid "ACSI card? (optional)" msgstr "Targeta ACSI? (opcional)" -#: web/templates/public/booking.gohtml:150 +#: web/templates/public/booking.gohtml:151 msgctxt "input" msgid "I have read and I accept the reservation conditions" msgstr "He llegit i accepto les condicions de reserves" @@ -406,7 +406,7 @@ msgstr "Menú" #: 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: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" msgid "Campsites" msgstr "Allotjaments" @@ -505,12 +505,14 @@ msgstr "Afegeix text legal" #: web/templates/admin/campsite/option/index.gohtml:25 #: web/templates/admin/campsite/type/index.gohtml:25 #: web/templates/admin/season/index.gohtml:26 +#: web/templates/admin/user/index.gohtml:17 #: web/templates/admin/surroundings/index.gohtml:26 msgctxt "header" msgid "Name" msgstr "Nom" #: web/templates/admin/legal/index.gohtml:29 +#: web/templates/admin/user/index.gohtml:42 msgid "No legal texts added yet." msgstr "No s’ha afegit cap text legal encara." @@ -637,6 +639,7 @@ msgstr "Llegenda" #: web/templates/admin/campsite/carousel/index.gohtml:27 #: web/templates/admin/services/index.gohtml:27 #: web/templates/admin/services/index.gohtml:72 +#: web/templates/admin/user/index.gohtml:20 #: web/templates/admin/surroundings/index.gohtml:27 #: web/templates/admin/home/index.gohtml:27 #: 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/services/index.gohtml:44 #: web/templates/admin/services/index.gohtml:88 +#: web/templates/admin/user/index.gohtml:34 #: web/templates/admin/surroundings/index.gohtml:44 #: web/templates/admin/home/index.gohtml:44 #: web/templates/admin/home/index.gohtml:89 @@ -965,7 +969,7 @@ msgid "Integration" msgstr "Integració" #: 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" msgid "Dashboard" msgstr "Tauler" @@ -1058,6 +1062,32 @@ msgctxt "input" msgid "Language" 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:12 msgctxt "title" @@ -1197,7 +1227,7 @@ msgctxt "title" msgid "Home Page" msgstr "Pàgina d’inici" -#: web/templates/admin/layout.gohtml:72 +#: web/templates/admin/layout.gohtml:75 msgctxt "action" msgid "Logout" msgstr "Surt" @@ -1352,7 +1382,7 @@ msgstr "L’idioma escollit no és vàlid." msgid "File must be a valid PNG or JPEG image." 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" 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." 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 msgctxt "input" msgid "Highlight image" diff --git a/po/es.po b/po/es.po index db83867..dea7f88 100644 --- a/po/es.po +++ b/po/es.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: camper\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" "Last-Translator: jordi fita mas \n" "Language-Team: Spanish \n" @@ -67,24 +67,24 @@ msgctxt "title" msgid "Home" msgstr "Inicio" -#: web/templates/public/home.gohtml:24 +#: web/templates/public/home.gohtml:25 msgctxt "link" msgid "Booking" msgstr "Reservar" -#: web/templates/public/home.gohtml:31 +#: web/templates/public/home.gohtml:28 msgid "The pleasure of camping in the middle of nature…" msgstr "El placer de acampar en plena naturaleza…" -#: web/templates/public/home.gohtml:43 +#: web/templates/public/home.gohtml:40 msgid "Our services" msgstr "Nuestros servicios" -#: web/templates/public/home.gohtml:45 +#: web/templates/public/home.gohtml:42 msgid "Come and enjoy!" 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:12 #: web/templates/public/layout.gohtml:68 web/templates/public/layout.gohtml:96 @@ -93,19 +93,19 @@ msgctxt "title" msgid "Surroundings" msgstr "El entorno" -#: web/templates/public/home.gohtml:50 +#: web/templates/public/home.gohtml:47 msgid "Located in Alta Garrotxa, between the Pyrenees and the Costa Brava." msgstr "Situados en la Alta Garrotxa, entre los Pirineos y la Costa Brava." -#: web/templates/public/home.gohtml:51 +#: web/templates/public/home.gohtml:48 msgid "Nearby there are the gorges of Sadernes, volcanoes, La Fageda d’en Jordà, the Jewish quarter of Besalú, the basaltic cliff of Castellfollit de la Roca… much to see and much to do." msgstr "Cerca tenéis los piletones de Sadernes, volcanes, La Fageda d’en Jordà, la judería de Besalú, el riscal basáltico de Castellfollit de la Roca… 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 Girona, one from La Bisbal d’Empordà, and two from Barcelona." msgstr "A menos de una hora de Girona, a una de La Bisbal d’Empordà y a dos de Barcelona." -#: web/templates/public/home.gohtml:53 +#: web/templates/public/home.gohtml:50 msgid "Discover the surroundings" msgstr "Descubre el entorno" @@ -120,7 +120,7 @@ msgid "Check-out Date" msgstr "Fecha de salida" #: web/templates/public/campsite/type.gohtml:54 -#: web/templates/public/booking.gohtml:156 +#: web/templates/public/booking.gohtml:164 msgctxt "action" msgid "Book" msgstr "Reservar" @@ -301,91 +301,91 @@ msgctxt "title" msgid "Campground" 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 msgctxt "title" msgid "Booking" msgstr "Reserva" -#: web/templates/public/booking.gohtml:15 +#: web/templates/public/booking.gohtml:16 msgctxt "title" msgid "Customer Details" msgstr "Detalles del cliente" -#: web/templates/public/booking.gohtml:18 +#: web/templates/public/booking.gohtml:19 msgctxt "input" msgid "Full name" msgstr "Nombre y apellidos" -#: web/templates/public/booking.gohtml:27 +#: web/templates/public/booking.gohtml:28 msgctxt "input" msgid "Address (optional)" msgstr "Dirección (opcional)" -#: web/templates/public/booking.gohtml:36 +#: web/templates/public/booking.gohtml:37 msgctxt "input" msgid "Postcode (optional)" msgstr "Código postal (opcional)" -#: web/templates/public/booking.gohtml:45 +#: web/templates/public/booking.gohtml:46 msgctxt "input" msgid "Town or village (optional)" msgstr "Población (opcional)" -#: web/templates/public/booking.gohtml:54 +#: web/templates/public/booking.gohtml:55 #: web/templates/admin/taxDetails.gohtml:98 msgctxt "input" msgid "Country" msgstr "País" -#: web/templates/public/booking.gohtml:57 +#: web/templates/public/booking.gohtml:58 msgid "Choose a country" 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/taxDetails.gohtml:50 msgctxt "input" msgid "Email" msgstr "Correo-e" -#: web/templates/public/booking.gohtml:74 +#: web/templates/public/booking.gohtml:75 #: web/templates/admin/taxDetails.gohtml:42 msgctxt "input" msgid "Phone" msgstr "Teléfono" -#: web/templates/public/booking.gohtml:83 +#: web/templates/public/booking.gohtml:84 msgctxt "title" msgid "Accommodation" msgstr "Alojamientos" -#: web/templates/public/booking.gohtml:98 +#: web/templates/public/booking.gohtml:99 msgctxt "input" msgid "Area preferences (optional)" msgstr "Preferencias de área (opcional)" -#: web/templates/public/booking.gohtml:120 +#: web/templates/public/booking.gohtml:121 msgctxt "title" msgid "Booking Period" msgstr "Periodo de reserva" -#: web/templates/public/booking.gohtml:123 +#: web/templates/public/booking.gohtml:124 msgctxt "input" msgid "Arrival date" msgstr "Fecha de llegada" -#: web/templates/public/booking.gohtml:132 +#: web/templates/public/booking.gohtml:133 msgctxt "input" msgid "Departure date" msgstr "Fecha de salida" -#: web/templates/public/booking.gohtml:143 +#: web/templates/public/booking.gohtml:144 msgctxt "input" msgid "ACSI card? (optional)" msgstr "¿Tarjeta ACSI? (opcional)" -#: web/templates/public/booking.gohtml:150 +#: web/templates/public/booking.gohtml:151 msgctxt "input" msgid "I have read and I accept the reservation conditions" msgstr "He leído y acepto las condiciones de reserva" @@ -406,7 +406,7 @@ msgstr "Menú" #: 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: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" msgid "Campsites" msgstr "Alojamientos" @@ -505,12 +505,14 @@ msgstr "Añadir texto legal" #: web/templates/admin/campsite/option/index.gohtml:25 #: web/templates/admin/campsite/type/index.gohtml:25 #: web/templates/admin/season/index.gohtml:26 +#: web/templates/admin/user/index.gohtml:17 #: web/templates/admin/surroundings/index.gohtml:26 msgctxt "header" msgid "Name" msgstr "Nombre" #: web/templates/admin/legal/index.gohtml:29 +#: web/templates/admin/user/index.gohtml:42 msgid "No legal texts added yet." 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/services/index.gohtml:27 #: web/templates/admin/services/index.gohtml:72 +#: web/templates/admin/user/index.gohtml:20 #: web/templates/admin/surroundings/index.gohtml:27 #: web/templates/admin/home/index.gohtml:27 #: 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/services/index.gohtml:44 #: web/templates/admin/services/index.gohtml:88 +#: web/templates/admin/user/index.gohtml:34 #: web/templates/admin/surroundings/index.gohtml:44 #: web/templates/admin/home/index.gohtml:44 #: web/templates/admin/home/index.gohtml:89 @@ -965,7 +969,7 @@ msgid "Integration" msgstr "Integración" #: 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" msgid "Dashboard" msgstr "Panel" @@ -1058,6 +1062,32 @@ msgctxt "input" msgid "Language" 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:12 msgctxt "title" @@ -1197,7 +1227,7 @@ msgctxt "title" msgid "Home Page" msgstr "Página de inicio" -#: web/templates/admin/layout.gohtml:72 +#: web/templates/admin/layout.gohtml:75 msgctxt "action" msgid "Logout" msgstr "Salir" @@ -1352,7 +1382,7 @@ msgstr "El idioma escogido no es válido." msgid "File must be a valid PNG or JPEG image." 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" 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." 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 msgctxt "input" msgid "Highlight image" diff --git a/po/fr.po b/po/fr.po index e94fa97..fe8b63c 100644 --- a/po/fr.po +++ b/po/fr.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: camper\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" "Last-Translator: Oriol Carbonell \n" "Language-Team: French \n" @@ -68,24 +68,24 @@ msgctxt "title" msgid "Home" msgstr "Accueil" -#: web/templates/public/home.gohtml:24 +#: web/templates/public/home.gohtml:25 msgctxt "link" msgid "Booking" 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…" msgstr "Le plaisir de camper en pleine nature…" -#: web/templates/public/home.gohtml:43 +#: web/templates/public/home.gohtml:40 msgid "Our services" msgstr "Nos services" -#: web/templates/public/home.gohtml:45 +#: web/templates/public/home.gohtml:42 msgid "Come and enjoy!" 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:12 #: web/templates/public/layout.gohtml:68 web/templates/public/layout.gohtml:96 @@ -94,19 +94,19 @@ msgctxt "title" msgid "Surroundings" msgstr "Entourage" -#: web/templates/public/home.gohtml:50 +#: web/templates/public/home.gohtml:47 msgid "Located in Alta Garrotxa, between the Pyrenees and the Costa Brava." msgstr "Situé dans l’Alta Garrotxa, entre les Pyrénées et la Costa Brava." -#: web/templates/public/home.gohtml:51 +#: web/templates/public/home.gohtml:48 msgid "Nearby there are the gorges of Sadernes, volcanoes, La Fageda d’en Jordà, the Jewish quarter of Besalú, the basaltic cliff of Castellfollit de la Roca… much to see and much to do." msgstr "A proximité il y a les gorges de Sadernes, les volcans, La Fageda dâen Jordã , le quartier juif de Besalú, la falaise basaltique de Castellfollit de la Roca… beaucoup à voir et beaucoup à faire." -#: web/templates/public/home.gohtml:52 +#: web/templates/public/home.gohtml:49 msgid "Less than an hour from Girona, one from La Bisbal d’Empordà, and two from Barcelona." msgstr "À moins d’une heure de Gérone, un de La Bisbal d’Empordàet deux de Barcelone." -#: web/templates/public/home.gohtml:53 +#: web/templates/public/home.gohtml:50 msgid "Discover the surroundings" msgstr "Découvrir les environs" @@ -121,7 +121,7 @@ msgid "Check-out Date" msgstr "Date de départ" #: web/templates/public/campsite/type.gohtml:54 -#: web/templates/public/booking.gohtml:156 +#: web/templates/public/booking.gohtml:164 msgctxt "action" msgid "Book" msgstr "Réserver" @@ -302,91 +302,91 @@ msgctxt "title" msgid "Campground" 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 msgctxt "title" msgid "Booking" msgstr "Reservation" -#: web/templates/public/booking.gohtml:15 +#: web/templates/public/booking.gohtml:16 msgctxt "title" msgid "Customer Details" msgstr "Détails du client" -#: web/templates/public/booking.gohtml:18 +#: web/templates/public/booking.gohtml:19 msgctxt "input" msgid "Full name" msgstr "Nom et prénom" -#: web/templates/public/booking.gohtml:27 +#: web/templates/public/booking.gohtml:28 msgctxt "input" msgid "Address (optional)" msgstr "Adresse (Facultatif)" -#: web/templates/public/booking.gohtml:36 +#: web/templates/public/booking.gohtml:37 msgctxt "input" msgid "Postcode (optional)" msgstr "Code postal (Facultatif)" -#: web/templates/public/booking.gohtml:45 +#: web/templates/public/booking.gohtml:46 msgctxt "input" msgid "Town or village (optional)" msgstr "Ville (Facultatif)" -#: web/templates/public/booking.gohtml:54 +#: web/templates/public/booking.gohtml:55 #: web/templates/admin/taxDetails.gohtml:98 msgctxt "input" msgid "Country" msgstr "Pays" -#: web/templates/public/booking.gohtml:57 +#: web/templates/public/booking.gohtml:58 msgid "Choose a country" 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/taxDetails.gohtml:50 msgctxt "input" msgid "Email" msgstr "E-mail" -#: web/templates/public/booking.gohtml:74 +#: web/templates/public/booking.gohtml:75 #: web/templates/admin/taxDetails.gohtml:42 msgctxt "input" msgid "Phone" msgstr "Téléphone" -#: web/templates/public/booking.gohtml:83 +#: web/templates/public/booking.gohtml:84 msgctxt "title" msgid "Accommodation" msgstr "Hébergement" -#: web/templates/public/booking.gohtml:98 +#: web/templates/public/booking.gohtml:99 msgctxt "input" msgid "Area preferences (optional)" msgstr "Préférences de zone (facultatif)" -#: web/templates/public/booking.gohtml:120 +#: web/templates/public/booking.gohtml:121 msgctxt "title" msgid "Booking Period" msgstr "Période de réservation" -#: web/templates/public/booking.gohtml:123 +#: web/templates/public/booking.gohtml:124 msgctxt "input" msgid "Arrival date" msgstr "Date d’arrivée" -#: web/templates/public/booking.gohtml:132 +#: web/templates/public/booking.gohtml:133 msgctxt "input" msgid "Departure date" msgstr "Date de depart" -#: web/templates/public/booking.gohtml:143 +#: web/templates/public/booking.gohtml:144 msgctxt "input" msgid "ACSI card? (optional)" msgstr "Carte ACSI ? (Facultatif)" -#: web/templates/public/booking.gohtml:150 +#: web/templates/public/booking.gohtml:151 msgctxt "input" msgid "I have read and I accept the reservation conditions" msgstr "J’ai lu et j’accepte les conditions de réservation" @@ -407,7 +407,7 @@ msgstr "Menu" #: 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: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" msgid "Campsites" msgstr "Locatifs" @@ -506,12 +506,14 @@ msgstr "Ajouter un texte juridique" #: web/templates/admin/campsite/option/index.gohtml:25 #: web/templates/admin/campsite/type/index.gohtml:25 #: web/templates/admin/season/index.gohtml:26 +#: web/templates/admin/user/index.gohtml:17 #: web/templates/admin/surroundings/index.gohtml:26 msgctxt "header" msgid "Name" msgstr "Nom" #: web/templates/admin/legal/index.gohtml:29 +#: web/templates/admin/user/index.gohtml:42 msgid "No legal texts added yet." msgstr "Aucune texte juridique n’a encore été ajoutée." @@ -638,6 +640,7 @@ msgstr "Légende" #: web/templates/admin/campsite/carousel/index.gohtml:27 #: web/templates/admin/services/index.gohtml:27 #: web/templates/admin/services/index.gohtml:72 +#: web/templates/admin/user/index.gohtml:20 #: web/templates/admin/surroundings/index.gohtml:27 #: web/templates/admin/home/index.gohtml:27 #: 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/services/index.gohtml:44 #: web/templates/admin/services/index.gohtml:88 +#: web/templates/admin/user/index.gohtml:34 #: web/templates/admin/surroundings/index.gohtml:44 #: web/templates/admin/home/index.gohtml:44 #: web/templates/admin/home/index.gohtml:89 @@ -966,7 +970,7 @@ msgid "Integration" msgstr "Intégration" #: 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" msgid "Dashboard" msgstr "Tableau de bord" @@ -1059,6 +1063,32 @@ msgctxt "input" msgid "Language" 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:12 msgctxt "title" @@ -1198,7 +1228,7 @@ msgctxt "title" msgid "Home Page" msgstr "Page d'accueil" -#: web/templates/admin/layout.gohtml:72 +#: web/templates/admin/layout.gohtml:75 msgctxt "action" msgid "Logout" msgstr "Déconnexion" @@ -1353,7 +1383,7 @@ msgstr "La langue sélectionnée n’est pas valide." msgid "File must be a valid PNG or JPEG image." msgstr "Le fichier doit être une image PNG ou JPEG valide." -#: pkg/app/admin.go:64 +#: pkg/app/admin.go:67 msgid "Access forbidden" 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." 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 msgctxt "input" msgid "Highlight image" diff --git a/revert/company_user_profile.sql b/revert/company_user_profile.sql new file mode 100644 index 0000000..4a683ca --- /dev/null +++ b/revert/company_user_profile.sql @@ -0,0 +1,7 @@ +-- Revert camper:company_user_profile from pg + +begin; + +drop view if exists camper.company_user_profile; + +commit; diff --git a/sqitch.plan b/sqitch.plan index bf299de..0eae170 100644 --- a/sqitch.plan +++ b/sqitch.plan @@ -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 # 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 # 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 # 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 # Add view to list users for admins diff --git a/test/company_user_profile.sql b/test/company_user_profile.sql new file mode 100644 index 0000000..9741f5a --- /dev/null +++ b/test/company_user_profile.sql @@ -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; diff --git a/verify/company_user_profile.sql b/verify/company_user_profile.sql new file mode 100644 index 0000000..9efc687 --- /dev/null +++ b/verify/company_user_profile.sql @@ -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; diff --git a/web/templates/admin/layout.gohtml b/web/templates/admin/layout.gohtml index f30f580..341118e 100644 --- a/web/templates/admin/layout.gohtml +++ b/web/templates/admin/layout.gohtml @@ -66,6 +66,9 @@
  • {{( pgettext "Legal Texts" "title" )}}
  • +
  • + {{( pgettext "Users" "title" )}} +
  • {{- end }}