265 lines
6.6 KiB
Go
265 lines
6.6 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"git.118im.com/im_team/olons_server/internal/portal"
|
|
"git.118im.com/im_team/olons_server/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) popupNotice(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
|
|
}
|
|
result, err := a.portal.PopupNotice(r.Context(), principal.TenantID, principal.MemberID)
|
|
if err != nil {
|
|
writePortalError(w, r, err)
|
|
return
|
|
}
|
|
writeSuccess(w, r, result)
|
|
}
|
|
|
|
func (a *API) noticeResource(w http.ResponseWriter, r *http.Request) {
|
|
path := strings.Trim(strings.TrimPrefix(r.URL.Path, "/v1/notices/"), "/")
|
|
parts := strings.Split(path, "/")
|
|
if len(parts) != 2 || parts[1] != "read" {
|
|
writePortalError(w, r, store.ErrResourceNotFound)
|
|
return
|
|
}
|
|
noticeID, err := strconv.ParseInt(parts[0], 10, 64)
|
|
if err != nil || noticeID <= 0 {
|
|
writePortalError(w, r, store.ErrResourceNotFound)
|
|
return
|
|
}
|
|
if r.Method != http.MethodPost {
|
|
methodNotAllowed(w, r, http.MethodPost)
|
|
return
|
|
}
|
|
if !a.ensurePortal(w, r) {
|
|
return
|
|
}
|
|
principal, ok := a.authenticateMember(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
if err := a.portal.MarkNoticeRead(r.Context(), principal.TenantID, principal.MemberID, noticeID); err != nil {
|
|
writePortalError(w, r, err)
|
|
return
|
|
}
|
|
writeSuccess(w, r, struct{}{})
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|