package location import ( "context" "golang.org/x/text/language" "net/http" "github.com/jackc/pgx/v4" "dev.tandem.ws/tandem/camper/pkg/auth" "dev.tandem.ws/tandem/camper/pkg/database" "dev.tandem.ws/tandem/camper/pkg/form" 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 { 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: f := newLocationForm(company.Locales) if err := f.FillFromDatabase(r.Context(), company, conn); err != nil { if !database.ErrorIsNotFound(err) { panic(err) } } f.MustRender(w, r, user, company) case http.MethodPut: updateLocationSettings(w, r, user, company, conn) default: httplib.MethodNotAllowed(w, r, http.MethodGet) } default: http.NotFound(w, r) } }) } func updateLocationSettings(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { f := newLocationForm(company.Locales) if ok, err := form.Handle(f, w, r, user); err != nil { return } else if !ok { f.MustRender(w, r, user, company) return } tx := conn.MustBegin(r.Context()) defer tx.Rollback(r.Context()) var defaultLang = company.DefaultLanguage.String() if err := tx.SetupLocation(r.Context(), company.ID, f.Directions[defaultLang].Val, f.MapEmbed.Val, f.OpeningDates[defaultLang].Val); err != nil { panic(err) } for lang := range company.Locales { if lang == company.DefaultLanguage { continue } if err := tx.TranslateLocation(r.Context(), company.ID, lang, f.Directions[lang.String()].Val, f.OpeningDates[lang.String()].Val); err != nil { panic(err) } } tx.MustCommit(r.Context()) httplib.Redirect(w, r, "/admin/location", http.StatusSeeOther) } type locationForm struct { Directions form.I18nInput MapEmbed *form.Input OpeningDates form.I18nInput } func newLocationForm(locales locale.Locales) *locationForm { return &locationForm{ Directions: form.NewI18nInput(locales, "directions"), MapEmbed: &form.Input{ Name: "map_embed", }, OpeningDates: form.NewI18nInput(locales, "opening_dates"), } } func (f *locationForm) FillFromDatabase(ctx context.Context, company *auth.Company, conn *database.Conn) error { var directions database.RecordArray var openingDates database.RecordArray err := conn.QueryRow(ctx, ` select location.directions::text , location.map_embed::text , location.opening_dates::text , array_agg((lang_tag, i18n.directions::text)) , array_agg((lang_tag, i18n.opening_dates::text)) from location left join location_i18n as i18n using (company_id) where company_id = $1 group by location.directions::text , location.map_embed::text , location.opening_dates::text `, pgx.QueryResultFormats{pgx.BinaryFormatCode}, company.ID).Scan( &f.Directions[company.DefaultLanguage.String()].Val, &f.MapEmbed.Val, &f.OpeningDates[company.DefaultLanguage.String()].Val, &directions, &openingDates, ) if err != nil { return err } if err := fillI18nInput(f.Directions, directions); err != nil { return err } if err := fillI18nInput(f.OpeningDates, openingDates); err != nil { return err } return nil } func fillI18nInput(input form.I18nInput, array database.RecordArray) error { for _, el := range array.Elements { tag, err := language.Parse(el.Fields[0].Get().(string)) if err != nil { return err } input[tag.String()].Val = el.Fields[1].Get().(string) } return nil } func (f *locationForm) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) { template.MustRenderAdmin(w, r, user, company, "location.gohtml", f) } func (f *locationForm) Parse(r *http.Request) error { if err := r.ParseForm(); err != nil { return err } f.Directions.FillValue(r) f.MapEmbed.FillValue(r) f.OpeningDates.FillValue(r) return nil } func (f *locationForm) Valid(l *locale.Locale) bool { v := form.NewValidator(l) return v.AllOK }