package httpapi import ( "errors" "net/http" "strings" "git.118im.com/im_team/im_workbench/internal/portal" "git.118im.com/im_team/im_workbench/internal/store" ) var publicContentKeys = map[string]struct{}{ "privacy_policy": {}, "user_agreement": {}, } func (a *API) home(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { methodNotAllowed(w, r, http.MethodGet) return } if !a.ensurePortal(w, r) { return } principal, ok := a.authenticateMember(w, r) if !ok { return } profile, err := a.accounts.Profile(r.Context(), principal.TenantID, principal.MemberID) if err != nil { writeProfileError(w, r, err) return } result, err := a.portal.Home(r.Context(), principal.TenantID, principal.MemberID, profile) if err != nil { writePortalError(w, r, err) return } writeSuccess(w, r, result) } func (a *API) banners(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { methodNotAllowed(w, r, http.MethodGet) return } if !a.ensurePortal(w, r) { return } principal, ok := a.authenticateMember(w, r) if !ok { return } position := strings.TrimSpace(r.URL.Query().Get("position")) if position == "" { position = "home_top" } items, err := a.portal.Banners(r.Context(), principal.TenantID, position) if err != nil { writePortalError(w, r, err) return } writeSuccess(w, r, items) } func (a *API) content(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { methodNotAllowed(w, r, http.MethodGet) return } if !a.ensurePortal(w, r) { return } if a.auth == nil { writeError(w, r, http.StatusServiceUnavailable, 90001, "SERVICE_UNAVAILABLE", "service unavailable", nil) return } key := strings.TrimPrefix(r.URL.Path, "/v1/contents/") key = strings.ToLower(strings.TrimSpace(key)) if strings.Contains(key, "/") { writePortalError(w, r, portal.ErrContentKeyInvalid) return } tenantID := a.auth.DefaultTenantID() if _, public := publicContentKeys[key]; !public { principal, ok := a.authenticateMember(w, r) if !ok { return } tenantID = principal.TenantID } result, err := a.portal.Content(r.Context(), tenantID, key) if err != nil { writePortalError(w, r, err) return } writeSuccess(w, r, result) } func (a *API) memberLevels(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { methodNotAllowed(w, r, http.MethodGet) return } if !a.ensurePortal(w, r) { return } principal, ok := a.authenticateMember(w, r) if !ok { return } items, err := a.portal.MemberLevels(r.Context(), principal.TenantID) if err != nil { writePortalError(w, r, err) return } writeSuccess(w, r, items) } func (a *API) leaderboard(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { methodNotAllowed(w, r, http.MethodGet) return } if !a.ensurePortal(w, r) { return } principal, ok := a.authenticateMember(w, r) if !ok { return } items, err := a.portal.Leaderboard(r.Context(), principal.TenantID) if err != nil { writePortalError(w, r, err) return } writeSuccess(w, r, items) } func (a *API) customerServices(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { methodNotAllowed(w, r, http.MethodGet) return } if !a.ensurePortal(w, r) { return } principal, ok := a.authenticateMember(w, r) if !ok { return } items, err := a.portal.CustomerServices(r.Context(), principal.TenantID) if err != nil { writePortalError(w, r, err) return } writeSuccess(w, r, items) } func (a *API) notices(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { methodNotAllowed(w, r, http.MethodGet) return } if !a.ensurePortal(w, r) { return } principal, ok := a.authenticateMember(w, r) if !ok { return } page, ok := optionalPositiveInt(w, r, "page") if !ok { writePortalError(w, r, portal.ErrPageInvalid) return } pageSize, ok := optionalPositiveInt(w, r, "page_size") if !ok { writePortalError(w, r, portal.ErrPageSizeInvalid) return } result, err := a.portal.Notices(r.Context(), principal.TenantID, principal.MemberID, page, pageSize) if err != nil { writePortalError(w, r, err) return } writeSuccess(w, r, result) } func (a *API) ensurePortal(w http.ResponseWriter, r *http.Request) bool { if a.portal != nil { return true } writeError(w, r, http.StatusServiceUnavailable, 90001, "SERVICE_UNAVAILABLE", "service unavailable", nil) return false } func writePortalError(w http.ResponseWriter, r *http.Request, err error) { switch { case errors.Is(err, portal.ErrPositionInvalid): writeError(w, r, http.StatusBadRequest, 30000, "BANNER_POSITION_INVALID", "validation failed", map[string]any{"field": "position"}) case errors.Is(err, portal.ErrContentKeyInvalid): writeError(w, r, http.StatusBadRequest, 30000, "CONTENT_KEY_INVALID", "validation failed", map[string]any{"field": "content_key"}) case errors.Is(err, portal.ErrPageInvalid): writeError(w, r, http.StatusBadRequest, 30000, "PAGE_INVALID", "validation failed", map[string]any{"field": "page"}) case errors.Is(err, portal.ErrPageSizeInvalid): writeError(w, r, http.StatusBadRequest, 30000, "PAGE_SIZE_INVALID", "validation failed", map[string]any{"field": "page_size"}) case errors.Is(err, store.ErrResourceNotFound): writeError(w, r, http.StatusNotFound, 30044, "RESOURCE_NOT_FOUND", "resource not found", nil) default: writeError(w, r, http.StatusInternalServerError, 90000, reasonInternal, "internal error", nil) } }