357 lines
10 KiB
Go
357 lines
10 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.118im.com/im_team/im_workbench/internal/store"
|
|
)
|
|
|
|
func (a *API) adminWorkbenchApps(w http.ResponseWriter, r *http.Request) {
|
|
st, ok := a.internalAdminStore(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
page := queryInt(r, "page", 1)
|
|
perPage := queryInt(r, "per_page", 20)
|
|
var enabled *int
|
|
if raw := strings.TrimSpace(r.URL.Query().Get("enabled")); raw != "" {
|
|
if value, err := strconv.Atoi(raw); err == nil {
|
|
enabled = &value
|
|
}
|
|
}
|
|
items, total, err := st.AdminWorkbenchModules(r.Context(), page, perPage, r.URL.Query().Get("code"), r.URL.Query().Get("name"), enabled)
|
|
if err != nil {
|
|
writeStoreError(w, r, err)
|
|
return
|
|
}
|
|
writeSuccess(w, r, map[string]any{"items": adminWorkbenchModulePayloads(items), "total": total, "page": page, "per_page": perPage})
|
|
case http.MethodPost:
|
|
var body adminWorkbenchModuleRequest
|
|
if !decodeJSON(w, r, &body) {
|
|
return
|
|
}
|
|
item, err := st.UpsertAdminWorkbenchModule(r.Context(), store.AdminWorkbenchModuleInput{
|
|
ID: body.ID, Code: body.Code, Name: body.Name, IconFileID: body.IconFileID, Route: body.Route,
|
|
SortOrder: body.SortOrder, UnreadKey: body.UnreadKey, Enabled: body.Enabled, Permission: body.Permission,
|
|
})
|
|
if err != nil {
|
|
writeStoreError(w, r, err)
|
|
return
|
|
}
|
|
writeSuccess(w, r, adminWorkbenchModulePayload(*item))
|
|
default:
|
|
methodNotAllowed(w, r)
|
|
}
|
|
}
|
|
|
|
func (a *API) adminWorkbenchAppDisable(w http.ResponseWriter, r *http.Request) {
|
|
st, ok := a.internalAdminStore(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
if r.Method != http.MethodPost {
|
|
methodNotAllowed(w, r)
|
|
return
|
|
}
|
|
var body struct {
|
|
ID int64 `json:"id"`
|
|
Code string `json:"code"`
|
|
}
|
|
if !decodeJSON(w, r, &body) {
|
|
return
|
|
}
|
|
if err := st.DisableAdminWorkbenchModule(r.Context(), body.ID, body.Code); err != nil {
|
|
writeStoreError(w, r, err)
|
|
return
|
|
}
|
|
writeSuccess(w, r, map[string]any{"ok": true})
|
|
}
|
|
|
|
func (a *API) adminWorkbenchAppsReorder(w http.ResponseWriter, r *http.Request) {
|
|
st, ok := a.internalAdminStore(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
if r.Method != http.MethodPost {
|
|
methodNotAllowed(w, r)
|
|
return
|
|
}
|
|
var body struct {
|
|
Items []struct {
|
|
Code string `json:"code"`
|
|
SortOrder int `json:"sort_order"`
|
|
} `json:"items"`
|
|
}
|
|
if !decodeJSON(w, r, &body) {
|
|
return
|
|
}
|
|
items := make([]store.AdminWorkbenchReorderItem, 0, len(body.Items))
|
|
for _, item := range body.Items {
|
|
items = append(items, store.AdminWorkbenchReorderItem{Code: item.Code, SortOrder: item.SortOrder})
|
|
}
|
|
if err := st.ReorderAdminWorkbenchModules(r.Context(), items); err != nil {
|
|
writeStoreError(w, r, err)
|
|
return
|
|
}
|
|
writeSuccess(w, r, map[string]any{"ok": true})
|
|
}
|
|
|
|
func (a *API) adminOrganizationDepartments(w http.ResponseWriter, r *http.Request) {
|
|
st, ok := a.internalAdminStore(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
if r.Method != http.MethodGet {
|
|
methodNotAllowed(w, r)
|
|
return
|
|
}
|
|
page := queryInt(r, "page", 1)
|
|
perPage := queryInt(r, "per_page", 20)
|
|
items, total, err := st.AdminOrganizationDepartments(r.Context(), page, perPage,
|
|
r.URL.Query().Get("parent_id"), r.URL.Query().Get("name"), r.URL.Query().Get("state"))
|
|
if err != nil {
|
|
writeStoreError(w, r, err)
|
|
return
|
|
}
|
|
writeSuccess(w, r, map[string]any{"items": adminOrganizationDepartmentPayloads(items), "total": total, "page": page, "per_page": perPage})
|
|
}
|
|
|
|
func (a *API) adminOrganizationMembers(w http.ResponseWriter, r *http.Request) {
|
|
st, ok := a.internalAdminStore(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
if r.Method != http.MethodGet {
|
|
methodNotAllowed(w, r)
|
|
return
|
|
}
|
|
page := queryInt(r, "page", 1)
|
|
perPage := queryInt(r, "per_page", 20)
|
|
userID, _ := strconv.ParseInt(strings.TrimSpace(r.URL.Query().Get("user_id")), 10, 64)
|
|
items, total, err := st.AdminOrganizationMembers(r.Context(), page, perPage,
|
|
r.URL.Query().Get("department_id"), firstNonEmpty(r.URL.Query().Get("q"), r.URL.Query().Get("keyword")),
|
|
r.URL.Query().Get("employment_state"), userID)
|
|
if err != nil {
|
|
writeStoreError(w, r, err)
|
|
return
|
|
}
|
|
writeSuccess(w, r, map[string]any{"items": adminOrganizationMemberPayloads(items), "total": total, "page": page, "per_page": perPage})
|
|
}
|
|
|
|
func (a *API) adminMailboxConfig(w http.ResponseWriter, r *http.Request) {
|
|
st, ok := a.internalAdminStore(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
cfg, err := st.AdminMailboxConfig(r.Context())
|
|
if err != nil {
|
|
writeStoreError(w, r, err)
|
|
return
|
|
}
|
|
writeSuccess(w, r, adminMailboxConfigPayload(*cfg))
|
|
case http.MethodPost:
|
|
var body adminMailboxConfigRequest
|
|
if !decodeJSON(w, r, &body) {
|
|
return
|
|
}
|
|
if err := st.UpdateAdminMailboxConfig(r.Context(), store.AdminMailboxConfig{
|
|
Enabled: body.Enabled, AllowAnonymous: body.AllowAnonymous, RequiredFields: body.RequiredFields,
|
|
MaxLength: body.MaxLength, AttachmentPolicy: body.AttachmentPolicy, NoticeTitle: body.NoticeTitle, NoticeContent: body.NoticeContent,
|
|
}); err != nil {
|
|
writeStoreError(w, r, err)
|
|
return
|
|
}
|
|
writeSuccess(w, r, map[string]any{"ok": true})
|
|
default:
|
|
methodNotAllowed(w, r)
|
|
}
|
|
}
|
|
|
|
func (a *API) adminFeedbackConfig(w http.ResponseWriter, r *http.Request) {
|
|
st, ok := a.internalAdminStore(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
cfg, err := st.AdminFeedbackConfig(r.Context())
|
|
if err != nil {
|
|
writeStoreError(w, r, err)
|
|
return
|
|
}
|
|
writeSuccess(w, r, adminFeedbackConfigPayload(*cfg))
|
|
case http.MethodPost:
|
|
var body adminFeedbackConfigRequest
|
|
if !decodeJSON(w, r, &body) {
|
|
return
|
|
}
|
|
if err := st.UpdateAdminFeedbackConfig(r.Context(), store.AdminFeedbackConfig{
|
|
Categories: body.Categories, MaxLength: body.MaxLength, AttachmentPolicy: body.AttachmentPolicy,
|
|
AllowContact: body.AllowContact, DiagnosticsNotice: body.DiagnosticsNotice,
|
|
}); err != nil {
|
|
writeStoreError(w, r, err)
|
|
return
|
|
}
|
|
writeSuccess(w, r, map[string]any{"ok": true})
|
|
default:
|
|
methodNotAllowed(w, r)
|
|
}
|
|
}
|
|
|
|
func (a *API) internalAdminStore(w http.ResponseWriter, r *http.Request) (*store.Store, bool) {
|
|
tenantID, _ := strconv.ParseInt(firstNonEmpty(r.Header.Get("X-Tenant-ID"), r.URL.Query().Get("tenant_id")), 10, 64)
|
|
tenantCode := firstNonEmpty(r.Header.Get("X-Tenant-Code"), r.URL.Query().Get("tenant_code"), "default")
|
|
st, err := a.store.ForTenant(r.Context(), tenantID, tenantCode)
|
|
if err != nil {
|
|
writeStoreError(w, r, err)
|
|
return nil, false
|
|
}
|
|
return st, true
|
|
}
|
|
|
|
type adminWorkbenchModuleRequest struct {
|
|
ID int64 `json:"id"`
|
|
Code string `json:"code"`
|
|
Name string `json:"name"`
|
|
IconFileID string `json:"icon_file_id"`
|
|
Route string `json:"route"`
|
|
SortOrder int `json:"sort_order"`
|
|
UnreadKey string `json:"unread_key"`
|
|
Enabled int `json:"enabled"`
|
|
Permission string `json:"permission"`
|
|
}
|
|
|
|
type adminMailboxConfigRequest struct {
|
|
Enabled int `json:"enabled"`
|
|
AllowAnonymous int `json:"allow_anonymous"`
|
|
RequiredFields string `json:"required_fields"`
|
|
MaxLength int `json:"max_length"`
|
|
AttachmentPolicy string `json:"attachment_policy"`
|
|
NoticeTitle string `json:"notice_title"`
|
|
NoticeContent string `json:"notice_content"`
|
|
}
|
|
|
|
type adminFeedbackConfigRequest struct {
|
|
Categories string `json:"categories"`
|
|
MaxLength int `json:"max_length"`
|
|
AttachmentPolicy string `json:"attachment_policy"`
|
|
AllowContact int `json:"allow_contact"`
|
|
DiagnosticsNotice string `json:"diagnostics_notice"`
|
|
}
|
|
|
|
func adminWorkbenchModulePayloads(items []store.AdminWorkbenchModule) []map[string]any {
|
|
res := make([]map[string]any, 0, len(items))
|
|
for _, item := range items {
|
|
res = append(res, adminWorkbenchModulePayload(item))
|
|
}
|
|
return res
|
|
}
|
|
|
|
func adminWorkbenchModulePayload(item store.AdminWorkbenchModule) map[string]any {
|
|
return map[string]any{
|
|
"id": item.ID,
|
|
"code": item.Code,
|
|
"name": item.Name,
|
|
"iconFileId": item.IconFileID,
|
|
"route": item.Route,
|
|
"sortOrder": item.SortOrder,
|
|
"unreadKey": item.UnreadKey,
|
|
"enabled": item.Enabled,
|
|
"permission": item.Permission,
|
|
"createdAt": formatAdminTime(item.CreatedAt),
|
|
"updatedAt": formatAdminTime(item.UpdatedAt),
|
|
}
|
|
}
|
|
|
|
func adminOrganizationDepartmentPayloads(items []store.OrganizationDepartment) []map[string]any {
|
|
res := make([]map[string]any, 0, len(items))
|
|
for _, item := range items {
|
|
res = append(res, map[string]any{
|
|
"department_id": item.DepartmentID,
|
|
"name": item.Name,
|
|
"parent_id": item.ParentID,
|
|
"child_count": item.ChildCount,
|
|
"member_count": item.MemberCount,
|
|
"version": item.Version,
|
|
})
|
|
}
|
|
return res
|
|
}
|
|
|
|
func adminOrganizationMemberPayloads(items []store.OrganizationMember) []map[string]any {
|
|
res := make([]map[string]any, 0, len(items))
|
|
for _, item := range items {
|
|
res = append(res, map[string]any{
|
|
"user_id": item.UserID,
|
|
"department_id": item.DepartmentID,
|
|
"display_name": item.DisplayName,
|
|
"position": item.Position,
|
|
"mobile": item.Mobile,
|
|
"email": item.Email,
|
|
"avatar_file_id": item.AvatarFileID,
|
|
"status": item.Status,
|
|
"contactable": item.Contactable,
|
|
"version": item.Version,
|
|
})
|
|
}
|
|
return res
|
|
}
|
|
|
|
func adminMailboxConfigPayload(cfg store.AdminMailboxConfig) map[string]any {
|
|
return map[string]any{
|
|
"id": cfg.ID,
|
|
"enabled": cfg.Enabled,
|
|
"allowAnonymous": cfg.AllowAnonymous,
|
|
"requiredFields": cfg.RequiredFields,
|
|
"maxLength": cfg.MaxLength,
|
|
"attachmentPolicy": cfg.AttachmentPolicy,
|
|
"noticeTitle": cfg.NoticeTitle,
|
|
"noticeContent": cfg.NoticeContent,
|
|
"noticeUpdatedAt": formatAdminTime(cfg.NoticeUpdatedAt),
|
|
"updatedAt": formatAdminTime(cfg.UpdatedAt),
|
|
}
|
|
}
|
|
|
|
func adminFeedbackConfigPayload(cfg store.AdminFeedbackConfig) map[string]any {
|
|
return map[string]any{
|
|
"id": cfg.ID,
|
|
"categories": cfg.Categories,
|
|
"maxLength": cfg.MaxLength,
|
|
"attachmentPolicy": cfg.AttachmentPolicy,
|
|
"allowContact": cfg.AllowContact,
|
|
"diagnosticsNotice": cfg.DiagnosticsNotice,
|
|
"updatedAt": formatAdminTime(cfg.UpdatedAt),
|
|
}
|
|
}
|
|
|
|
func decodeJSON(w http.ResponseWriter, r *http.Request, out any) bool {
|
|
if err := json.NewDecoder(r.Body).Decode(out); err != nil {
|
|
writeError(w, r, http.StatusBadRequest, 30000, reasonMalformedRequest, "malformed request", nil)
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func queryInt(r *http.Request, key string, fallback int) int {
|
|
value, err := strconv.Atoi(strings.TrimSpace(r.URL.Query().Get(key)))
|
|
if err != nil || value <= 0 {
|
|
return fallback
|
|
}
|
|
return value
|
|
}
|
|
|
|
func formatAdminTime(t time.Time) string {
|
|
if t.IsZero() {
|
|
return ""
|
|
}
|
|
return t.UTC().Format(time.RFC3339Nano)
|
|
}
|