feat: site languages, setup and site URL settings
This commit is contained in:
1 parent
0806733d5c
commit
d9158025d4
106 files changed
+10184
-56
No files matched your search
@@ -0,0 +1,164 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"RenewCMS/api/pkg/apperr"
|
||||
validator "RenewCMS/api/pkg/validator"
|
||||
domainLanguage "RenewCMS/internal/domain/language"
|
||||
"RenewCMS/internal/domain/localization"
|
||||
"RenewCMS/internal/domain/site"
|
||||
"RenewCMS/internal/infrastructure/useCases"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
type SiteLanguagesHandler struct {
|
||||
GetUseCase *useCases.GetSiteLanguagesUseCase
|
||||
UpdateUseCase *useCases.UpdateSiteLanguagesUseCase
|
||||
}
|
||||
|
||||
func NewSiteLanguagesHandler(get *useCases.GetSiteLanguagesUseCase, update *useCases.UpdateSiteLanguagesUseCase) *SiteLanguagesHandler {
|
||||
return &SiteLanguagesHandler{GetUseCase: get, UpdateUseCase: update}
|
||||
}
|
||||
|
||||
type PutLanguage struct {
|
||||
Lang string `json:"lang"`
|
||||
Enabled *bool `json:"enabled" validate:"required"`
|
||||
SocialLocale *string `json:"social_locale"`
|
||||
}
|
||||
|
||||
type PutSiteLanguages struct {
|
||||
Revision *string `json:"revision" validate:"required"`
|
||||
Default *string `json:"default" validate:"required"`
|
||||
Languages []PutLanguage `json:"languages" validate:"required,dive"`
|
||||
}
|
||||
|
||||
func (p PutSiteLanguages) command(key string) useCases.UpdateSiteLanguagesCommand {
|
||||
entries := make([]useCases.SiteLanguageEntry, 0, len(p.Languages))
|
||||
for _, entry := range p.Languages {
|
||||
entries = append(entries, useCases.SiteLanguageEntry{Lang: entry.Lang, Enabled: *entry.Enabled, SocialLocale: entry.SocialLocale})
|
||||
}
|
||||
return useCases.UpdateSiteLanguagesCommand{Key: key, Revision: *p.Revision, Default: *p.Default, Languages: entries}
|
||||
}
|
||||
|
||||
func (h *SiteLanguagesHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
view, err := h.GetUseCase.Get(chi.URLParam(r, "key"))
|
||||
if err != nil {
|
||||
writeLocalizationError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, view)
|
||||
}
|
||||
|
||||
func (h *SiteLanguagesHandler) Update(w http.ResponseWriter, r *http.Request) {
|
||||
var request PutSiteLanguages
|
||||
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
|
||||
http.Error(w, apperr.BodyErrorMessage, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if err := validator.Validate.Struct(request); err != nil {
|
||||
http.Error(w, apperr.BodyErrorMessage, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
view, err := h.UpdateUseCase.Update(r.Context(), request.command(chi.URLParam(r, "key")))
|
||||
if err != nil {
|
||||
writeLocalizationError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, view)
|
||||
}
|
||||
|
||||
type SetupHandler struct {
|
||||
GetUseCase *useCases.GetLanguageSetupUseCase
|
||||
ApplyUseCase *useCases.ApplyLanguageSetupUseCase
|
||||
}
|
||||
|
||||
func NewSetupHandler(get *useCases.GetLanguageSetupUseCase, apply *useCases.ApplyLanguageSetupUseCase) *SetupHandler {
|
||||
return &SetupHandler{GetUseCase: get, ApplyUseCase: apply}
|
||||
}
|
||||
|
||||
type PostSetupSite struct {
|
||||
Key string `json:"key" validate:"required"`
|
||||
Lang string `json:"lang"`
|
||||
}
|
||||
|
||||
type PostSetup struct {
|
||||
Sites []PostSetupSite `json:"sites" validate:"required,dive"`
|
||||
}
|
||||
|
||||
func (h *SetupHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
view, err := h.GetUseCase.Get()
|
||||
if err != nil {
|
||||
writeLocalizationError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, view)
|
||||
}
|
||||
|
||||
func (h *SetupHandler) Apply(w http.ResponseWriter, r *http.Request) {
|
||||
var request PostSetup
|
||||
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
|
||||
http.Error(w, apperr.BodyErrorMessage, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if err := validator.Validate.Struct(request); err != nil {
|
||||
http.Error(w, apperr.BodyErrorMessage, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
choices := make([]localization.SetupChoice, 0, len(request.Sites))
|
||||
for _, entry := range request.Sites {
|
||||
choices = append(choices, localization.SetupChoice{Key: entry.Key, Lang: entry.Lang})
|
||||
}
|
||||
result, err := h.ApplyUseCase.Apply(r.Context(), choices)
|
||||
if err != nil {
|
||||
writeLocalizationError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, result)
|
||||
}
|
||||
|
||||
func writeJSON(w http.ResponseWriter, value any) {
|
||||
body, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if _, err := w.Write(body); err != nil {
|
||||
log.Printf("Failed to write response: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
type localizationFailure struct {
|
||||
sentinel error
|
||||
status int
|
||||
body string
|
||||
}
|
||||
|
||||
var localizationFailures = []localizationFailure{
|
||||
{site.ErrSiteNotFound, http.StatusNotFound, apperr.SiteNotFoundErrorMessage},
|
||||
{localization.ErrSetupRequired, http.StatusConflict, apperr.SetupRequiredErrorMessage},
|
||||
{localization.ErrLanguagesChanged, http.StatusConflict, apperr.LanguagesChangedErrorMessage},
|
||||
{localization.ErrLanguageInUse, http.StatusConflict, apperr.LanguageInUseErrorMessage},
|
||||
{localization.ErrSetupInProgress, http.StatusConflict, apperr.SetupInProgressErrorMessage},
|
||||
{localization.ErrDefaultNotEnabled, http.StatusUnprocessableEntity, apperr.DefaultNotEnabledErrorMessage},
|
||||
{localization.ErrNoEnabledLanguage, http.StatusUnprocessableEntity, apperr.NoEnabledLanguageErrorMessage},
|
||||
{localization.ErrDuplicateLanguage, http.StatusUnprocessableEntity, apperr.DuplicateLanguageErrorMessage},
|
||||
{localization.ErrInvalidSocialLocale, http.StatusUnprocessableEntity, apperr.InvalidSocialLocaleErrorMessage},
|
||||
{localization.ErrSetupIncomplete, http.StatusUnprocessableEntity, apperr.SetupIncompleteErrorMessage},
|
||||
{localization.ErrDuplicateSite, http.StatusUnprocessableEntity, apperr.DuplicateSiteErrorMessage},
|
||||
{domainLanguage.ErrInvalidLanguage, http.StatusUnprocessableEntity, apperr.InvalidLanguageErrorMessage},
|
||||
{domainLanguage.ErrUnsupportedLanguage, http.StatusUnprocessableEntity, apperr.UnsupportedLanguageErrorMessage},
|
||||
}
|
||||
|
||||
func writeLocalizationError(w http.ResponseWriter, err error) {
|
||||
for _, failure := range localizationFailures {
|
||||
if errors.Is(err, failure.sentinel) {
|
||||
http.Error(w, failure.body, failure.status)
|
||||
return
|
||||
}
|
||||
}
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
}
|
||||
Reference in new issue
Block a user