feat: implement core backend architecture and project management services for the History API
Build and Release / release (push) Successful in 1m33s
Build and Release / release (push) Successful in 1m33s
This commit is contained in:
@@ -61,9 +61,16 @@ func (s *battleReplayService) GetByGeometryIDs(ctx context.Context, req *request
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to get battle replays")
|
||||
}
|
||||
|
||||
result := make(map[string][]*response.BattleReplayResponse)
|
||||
counts := make(map[string]int, len(req.GeometryIDs))
|
||||
for _, replay := range replays {
|
||||
if replay != nil {
|
||||
counts[replay.GeometryID]++
|
||||
}
|
||||
}
|
||||
|
||||
result := make(map[string][]*response.BattleReplayResponse, len(req.GeometryIDs))
|
||||
for _, idStr := range req.GeometryIDs {
|
||||
result[idStr] = make([]*response.BattleReplayResponse, 0)
|
||||
result[idStr] = make([]*response.BattleReplayResponse, 0, counts[idStr])
|
||||
}
|
||||
|
||||
for _, replay := range replays {
|
||||
|
||||
@@ -70,6 +70,7 @@ func (s *chatbotService) Chat(ctx context.Context, userID string, projectID *str
|
||||
}
|
||||
|
||||
var contextBuilder strings.Builder
|
||||
contextBuilder.Grow(len(results) * 96)
|
||||
for i, res := range results {
|
||||
contextBuilder.WriteString(fmt.Sprintf("<doc id=\"%d\" score=\"%.2f\">\n%s\n</doc>\n\n", i+1, res.Similarity, res.Content))
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"history-api/internal/dtos/request"
|
||||
"history-api/internal/dtos/response"
|
||||
"history-api/internal/gen/sqlc"
|
||||
@@ -12,6 +10,7 @@ import (
|
||||
"history-api/pkg/cache"
|
||||
"history-api/pkg/constants"
|
||||
"history-api/pkg/convert"
|
||||
json "history-api/pkg/jsonx"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
@@ -52,7 +51,7 @@ func (s *commitService) checkWritePermission(ctx context.Context, userID string,
|
||||
return fiber.NewError(fiber.StatusNotFound, "Project not found")
|
||||
}
|
||||
|
||||
lockKey := fmt.Sprintf("project:lock:%s", convert.UUIDToString(projectUUID))
|
||||
lockKey := cache.Key("project:lock", convert.UUIDToString(projectUUID))
|
||||
var lockUser string
|
||||
if err := s.c.Get(ctx, lockKey, &lockUser); err == nil && lockUser != "" && lockUser != userID {
|
||||
return fiber.NewError(fiber.StatusConflict, "Cannot commit: Project is locked by another user who is editing")
|
||||
@@ -141,7 +140,7 @@ func (s *commitService) CreateCommit(ctx context.Context, userID string, project
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to commit transaction")
|
||||
}
|
||||
|
||||
_ = s.c.Del(ctx, fmt.Sprintf("project:id:%s", projectID), fmt.Sprintf("commit:project:%s", projectID))
|
||||
_ = s.c.Del(ctx, cache.Key("project:id", projectID), cache.Key("commit:project", projectID))
|
||||
|
||||
return commit.ToResponse(), nil
|
||||
}
|
||||
@@ -178,7 +177,7 @@ func (s *commitService) RestoreCommit(ctx context.Context, userID string, projec
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to restore commit")
|
||||
}
|
||||
|
||||
_ = s.c.Del(ctx, fmt.Sprintf("project:id:%s", projectID), fmt.Sprintf("commit:project:%s", projectID))
|
||||
_ = s.c.Del(ctx, cache.Key("project:id", projectID), cache.Key("commit:project", projectID))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -109,8 +109,13 @@ func (s *entityService) GetEntitiesByGeometryIDs(ctx context.Context, req *reque
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch entity IDs by geometry IDs")
|
||||
}
|
||||
|
||||
entityIDMap := make(map[string]struct{})
|
||||
var allEntityIDs []string
|
||||
totalEntityIDs := 0
|
||||
for _, eIDs := range mapping {
|
||||
totalEntityIDs += len(eIDs)
|
||||
}
|
||||
|
||||
entityIDMap := make(map[string]struct{}, totalEntityIDs)
|
||||
allEntityIDs := make([]string, 0, totalEntityIDs)
|
||||
for _, eIDs := range mapping {
|
||||
for _, eID := range eIDs {
|
||||
if _, ok := entityIDMap[eID]; !ok {
|
||||
@@ -125,15 +130,16 @@ func (s *entityService) GetEntitiesByGeometryIDs(ctx context.Context, req *reque
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch entities")
|
||||
}
|
||||
|
||||
entitiesByID := make(map[string]*models.EntityEntity)
|
||||
entitiesByID := make(map[string]*models.EntityEntity, len(entities))
|
||||
for _, e := range entities {
|
||||
entitiesByID[e.ID] = e
|
||||
}
|
||||
|
||||
result := make(map[string][]*response.EntityResponse)
|
||||
result := make(map[string][]*response.EntityResponse, len(req.GeometryIDs))
|
||||
for _, idStr := range req.GeometryIDs {
|
||||
result[idStr] = make([]*response.EntityResponse, 0)
|
||||
if eIDs, exists := mapping[idStr]; exists {
|
||||
eIDs, exists := mapping[idStr]
|
||||
result[idStr] = make([]*response.EntityResponse, 0, len(eIDs))
|
||||
if exists {
|
||||
for _, eID := range eIDs {
|
||||
if e, found := entitiesByID[eID]; found {
|
||||
result[idStr] = append(result[idStr], e.ToResponse())
|
||||
|
||||
@@ -57,6 +57,9 @@ func (s *geometryService) GetGeometriesByBoundWith(ctx context.Context, boundWit
|
||||
|
||||
func (s *geometryService) SearchGeometries(ctx context.Context, req *request.SearchGeometryDto) ([]*response.GeometryResponse, *fiber.Error) {
|
||||
params := sqlc.SearchGeometriesParams{}
|
||||
if req.Limit > 0 {
|
||||
params.LimitCount = int32(req.Limit)
|
||||
}
|
||||
|
||||
if req.MinLng != nil && req.MinLat != nil && req.MaxLng != nil && req.MaxLat != nil {
|
||||
if *req.MaxLng < *req.MinLng || *req.MaxLat < *req.MinLat {
|
||||
@@ -133,8 +136,8 @@ func (s *geometryService) SearchGeometriesByEntityName(
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to search geometries by entity name")
|
||||
}
|
||||
|
||||
byEntity := make(map[string]*response.EntityGeometriesSearchItem)
|
||||
order := make([]string, 0)
|
||||
byEntity := make(map[string]*response.EntityGeometriesSearchItem, len(rows))
|
||||
order := make([]string, 0, len(rows))
|
||||
|
||||
for _, row := range rows {
|
||||
item := byEntity[row.EntityID]
|
||||
@@ -143,7 +146,7 @@ func (s *geometryService) SearchGeometriesByEntityName(
|
||||
EntityID: row.EntityID,
|
||||
Name: row.EntityName,
|
||||
Description: row.EntityDescription,
|
||||
Geometries: make([]*response.EntityGeometrySearchGeo, 0),
|
||||
Geometries: make([]*response.EntityGeometrySearchGeo, 0, 1),
|
||||
}
|
||||
byEntity[row.EntityID] = item
|
||||
order = append(order, row.EntityID)
|
||||
|
||||
@@ -70,7 +70,7 @@ func (s *goongService) ProxyRequest(ctx context.Context, method string, targetUR
|
||||
parsedUrl.RawQuery = q.Encode()
|
||||
finalURL := parsedUrl.String()
|
||||
|
||||
cacheKey := fmt.Sprintf("goong_proxy_v2:%s", finalURL)
|
||||
cacheKey := cache.Key("goong_proxy_v2", finalURL)
|
||||
|
||||
if method == http.MethodGet {
|
||||
var entry CacheEntry
|
||||
@@ -180,7 +180,7 @@ func (s *goongService) ProxyRequest(ctx context.Context, method string, targetUR
|
||||
Msg("Goong Map proxy request returned non-200 status code")
|
||||
}
|
||||
|
||||
respHeaders := make(map[string]string)
|
||||
respHeaders := make(map[string]string, len(resp.Header))
|
||||
for k, v := range resp.Header {
|
||||
lowerK := strings.ToLower(k)
|
||||
// Skip hop-by-hop/transport headers in response
|
||||
|
||||
@@ -2,7 +2,6 @@ package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"history-api/internal/dtos/request"
|
||||
"history-api/internal/dtos/response"
|
||||
@@ -12,6 +11,7 @@ import (
|
||||
"history-api/pkg/cache"
|
||||
"history-api/pkg/constants"
|
||||
"history-api/pkg/convert"
|
||||
json "history-api/pkg/jsonx"
|
||||
"history-api/pkg/storage"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
@@ -98,8 +98,8 @@ func (m *mediaService) BulkDeleteMedia(ctx context.Context, claims *response.JWT
|
||||
if slices.Contains(claims.Roles, constants.RoleTypeAdmin) || slices.Contains(claims.Roles, constants.RoleTypeMod) {
|
||||
shoudDelete = true
|
||||
}
|
||||
listMediaIds := make([]pgtype.UUID, 0)
|
||||
listMediaStorageEntities := make([]*models.MediaStorageEntity, 0)
|
||||
listMediaIds := make([]pgtype.UUID, 0, len(listMedia))
|
||||
listMediaStorageEntities := make([]*models.MediaStorageEntity, 0, len(listMedia))
|
||||
for _, media := range listMedia {
|
||||
if media.UserID != claims.UId && !shoudDelete {
|
||||
return fiber.NewError(fiber.StatusForbidden, "You don't have permission to delete media "+media.ID)
|
||||
@@ -171,6 +171,7 @@ func (m *mediaService) fillSearchArgs(arg *sqlc.SearchMediasParams, dto *request
|
||||
}
|
||||
|
||||
if len(dto.UserIDs) > 0 {
|
||||
arg.UserIds = make([]pgtype.UUID, 0, len(dto.UserIDs))
|
||||
for _, id := range dto.UserIDs {
|
||||
if u, err := convert.StringToUUID(id); err == nil {
|
||||
arg.UserIds = append(arg.UserIds, u)
|
||||
|
||||
@@ -2,7 +2,6 @@ package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
@@ -87,7 +86,7 @@ func (s *projectService) GetProjectByID(ctx context.Context, id string) (*respon
|
||||
}
|
||||
|
||||
res := project.ToResponse()
|
||||
lockKey := fmt.Sprintf("project:lock:%s", id)
|
||||
lockKey := cache.Key("project:lock", id)
|
||||
var lockUser string
|
||||
if err := s.c.Get(ctx, lockKey, &lockUser); err == nil && lockUser != "" {
|
||||
res.LockedBy = &lockUser
|
||||
@@ -141,6 +140,7 @@ func (s *projectService) fillSearchArgs(arg *sqlc.SearchProjectsParams, dto *req
|
||||
}
|
||||
|
||||
if len(dto.Statuses) > 0 {
|
||||
arg.Statuses = make([]int16, 0, len(dto.Statuses))
|
||||
for _, statusStr := range dto.Statuses {
|
||||
statusType := constants.ParseProjectStatusTypeText(statusStr)
|
||||
if statusType != constants.ProjectStatusTypeUnknow {
|
||||
@@ -150,6 +150,7 @@ func (s *projectService) fillSearchArgs(arg *sqlc.SearchProjectsParams, dto *req
|
||||
}
|
||||
|
||||
if len(dto.UserIDs) > 0 {
|
||||
arg.UserIds = make([]pgtype.UUID, 0, len(dto.UserIDs))
|
||||
for _, id := range dto.UserIDs {
|
||||
if u, err := convert.StringToUUID(id); err == nil {
|
||||
arg.UserIds = append(arg.UserIds, u)
|
||||
@@ -464,7 +465,7 @@ func (s *projectService) LockProject(ctx context.Context, userID string, project
|
||||
return fiber.NewError(fiber.StatusNotFound, "Project not found")
|
||||
}
|
||||
|
||||
lockKey := fmt.Sprintf("project:lock:%s", projectID)
|
||||
lockKey := cache.Key("project:lock", projectID)
|
||||
var lockUser string
|
||||
err = s.c.Get(ctx, lockKey, &lockUser)
|
||||
if err == nil && lockUser != "" {
|
||||
@@ -487,7 +488,7 @@ func (s *projectService) LockProject(ctx context.Context, userID string, project
|
||||
}
|
||||
|
||||
func (s *projectService) UnlockProject(ctx context.Context, userID string, projectID string) *fiber.Error {
|
||||
lockKey := fmt.Sprintf("project:lock:%s", projectID)
|
||||
lockKey := cache.Key("project:lock", projectID)
|
||||
var lockUser string
|
||||
err := s.c.Get(ctx, lockKey, &lockUser)
|
||||
if err != nil || lockUser == "" {
|
||||
@@ -503,7 +504,7 @@ func (s *projectService) UnlockProject(ctx context.Context, userID string, proje
|
||||
}
|
||||
|
||||
func (s *projectService) HeartbeatProject(ctx context.Context, userID string, projectID string) *fiber.Error {
|
||||
lockKey := fmt.Sprintf("project:lock:%s", projectID)
|
||||
lockKey := cache.Key("project:lock", projectID)
|
||||
var lockUser string
|
||||
err := s.c.Get(ctx, lockKey, &lockUser)
|
||||
if err != nil || lockUser == "" {
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
type RasterTileService interface {
|
||||
GetMetadata(ctx context.Context) (map[string]string, *fiber.Error)
|
||||
GetTile(ctx context.Context, z, x, y int) ([]byte, map[string]string, *fiber.Error)
|
||||
GetTile(ctx context.Context, z, x, y int) (TileResponse, *fiber.Error)
|
||||
}
|
||||
|
||||
type rasterTileService struct {
|
||||
@@ -32,26 +32,26 @@ func (t *rasterTileService) GetMetadata(ctx context.Context) (map[string]string,
|
||||
return metaData, nil
|
||||
}
|
||||
|
||||
|
||||
func (t *rasterTileService) GetTile(ctx context.Context, z, x, y int) ([]byte, map[string]string, *fiber.Error) {
|
||||
contentType := make(map[string]string)
|
||||
|
||||
func (t *rasterTileService) GetTile(ctx context.Context, z, x, y int) (TileResponse, *fiber.Error) {
|
||||
data, format, err := t.tileRepo.GetTile(ctx, z, x, y)
|
||||
if err != nil {
|
||||
return nil, contentType, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch tile data")
|
||||
return TileResponse{}, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch tile data")
|
||||
}
|
||||
|
||||
res := TileResponse{
|
||||
Data: data,
|
||||
CacheControl: tileCacheControl,
|
||||
}
|
||||
|
||||
switch format {
|
||||
case "png":
|
||||
contentType["Content-Type"] = "image/png"
|
||||
res.ContentType = "image/png"
|
||||
case "jpg", "jpeg":
|
||||
contentType["Content-Type"] = "image/jpeg"
|
||||
res.ContentType = "image/jpeg"
|
||||
case "webp":
|
||||
contentType["Content-Type"] = "image/webp"
|
||||
res.ContentType = "image/webp"
|
||||
default:
|
||||
contentType["Content-Type"] = "application/octet-stream"
|
||||
res.ContentType = "application/octet-stream"
|
||||
}
|
||||
|
||||
return data, contentType, nil
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"history-api/internal/dtos/request"
|
||||
@@ -14,6 +13,7 @@ import (
|
||||
"history-api/pkg/cache"
|
||||
"history-api/pkg/constants"
|
||||
"history-api/pkg/convert"
|
||||
json "history-api/pkg/jsonx"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strconv"
|
||||
@@ -110,8 +110,8 @@ func (s *submissionService) CreateSubmission(ctx context.Context, userID string,
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to parse commit snapshot")
|
||||
}
|
||||
|
||||
var entitySlugs []string
|
||||
entitySlugToID := make(map[string]string)
|
||||
entitySlugs := make([]string, 0, len(snapshotData.Entities))
|
||||
entitySlugToID := make(map[string]string, len(snapshotData.Entities))
|
||||
for _, entity := range snapshotData.Entities {
|
||||
if entity.Source == "inline" && entity.Slug != nil {
|
||||
entitySlugs = append(entitySlugs, *entity.Slug)
|
||||
@@ -133,8 +133,8 @@ func (s *submissionService) CreateSubmission(ctx context.Context, userID string,
|
||||
}
|
||||
}
|
||||
|
||||
var wikiSlugs []string
|
||||
wikiSlugToID := make(map[string]string)
|
||||
wikiSlugs := make([]string, 0, len(snapshotData.Wikis))
|
||||
wikiSlugToID := make(map[string]string, len(snapshotData.Wikis))
|
||||
for _, wiki := range snapshotData.Wikis {
|
||||
if wiki.Source == "inline" && wiki.Slug != nil {
|
||||
wikiSlugs = append(wikiSlugs, *wiki.Slug)
|
||||
@@ -180,7 +180,7 @@ func (s *submissionService) CreateSubmission(ctx context.Context, userID string,
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create submission")
|
||||
}
|
||||
|
||||
_ = s.c.Del(ctx, fmt.Sprintf("project:id:%s", project.ID))
|
||||
_ = s.c.Del(ctx, cache.Key("project:id", project.ID))
|
||||
|
||||
return submission.ToResponse(), nil
|
||||
}
|
||||
@@ -277,11 +277,11 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
||||
}
|
||||
|
||||
_ = s.c.Del(ctx,
|
||||
fmt.Sprintf("project:id:%s", submission.ProjectID),
|
||||
fmt.Sprintf("entity:project:%s", submission.ProjectID),
|
||||
fmt.Sprintf("geometry:project:%s", submission.ProjectID),
|
||||
fmt.Sprintf("wiki:project:%s", submission.ProjectID),
|
||||
fmt.Sprintf("battle_replay:project:%s", submission.ProjectID),
|
||||
cache.Key("project:id", submission.ProjectID),
|
||||
cache.Key("entity:project", submission.ProjectID),
|
||||
cache.Key("geometry:project", submission.ProjectID),
|
||||
cache.Key("wiki:project", submission.ProjectID),
|
||||
cache.Key("battle_replay:project", submission.ProjectID),
|
||||
)
|
||||
|
||||
return updatedSubmission.ToResponse(), nil
|
||||
@@ -300,6 +300,7 @@ func (m *submissionService) fillSearchArgs(arg *sqlc.SearchSubmissionsParams, dt
|
||||
}
|
||||
|
||||
if len(dto.Statuses) > 0 {
|
||||
arg.Statuses = make([]int16, 0, len(dto.Statuses))
|
||||
for _, id := range dto.Statuses {
|
||||
if u := constants.ParseStatusTypeText(id); u != constants.StatusTypeUnknown {
|
||||
arg.Statuses = append(arg.Statuses, u.Int16())
|
||||
@@ -308,6 +309,7 @@ func (m *submissionService) fillSearchArgs(arg *sqlc.SearchSubmissionsParams, dt
|
||||
}
|
||||
|
||||
if len(dto.UserIDs) > 0 {
|
||||
arg.UserIds = make([]pgtype.UUID, 0, len(dto.UserIDs))
|
||||
for _, id := range dto.UserIDs {
|
||||
if u, err := convert.StringToUUID(id); err == nil {
|
||||
arg.UserIds = append(arg.UserIds, u)
|
||||
@@ -503,11 +505,11 @@ func (s *submissionService) DeleteSubmission(ctx context.Context, userID string,
|
||||
}
|
||||
|
||||
_ = s.c.Del(ctx,
|
||||
fmt.Sprintf("project:id:%s", submission.ProjectID),
|
||||
fmt.Sprintf("entity:project:%s", submission.ProjectID),
|
||||
fmt.Sprintf("geometry:project:%s", submission.ProjectID),
|
||||
fmt.Sprintf("wiki:project:%s", submission.ProjectID),
|
||||
fmt.Sprintf("battle_replay:project:%s", submission.ProjectID),
|
||||
cache.Key("project:id", submission.ProjectID),
|
||||
cache.Key("entity:project", submission.ProjectID),
|
||||
cache.Key("geometry:project", submission.ProjectID),
|
||||
cache.Key("wiki:project", submission.ProjectID),
|
||||
cache.Key("battle_replay:project", submission.ProjectID),
|
||||
)
|
||||
|
||||
return nil
|
||||
@@ -521,10 +523,10 @@ func (s *submissionService) applySnapshot(ctx context.Context, tx pgx.Tx, projec
|
||||
|
||||
projectIDStr := convert.UUIDToString(projectUUID)
|
||||
_ = s.c.Del(ctx,
|
||||
fmt.Sprintf("entity:project:%s", projectIDStr),
|
||||
fmt.Sprintf("geometry:project:%s", projectIDStr),
|
||||
fmt.Sprintf("wiki:project:%s", projectIDStr),
|
||||
fmt.Sprintf("battle_replay:project:%s", projectIDStr),
|
||||
cache.Key("entity:project", projectIDStr),
|
||||
cache.Key("geometry:project", projectIDStr),
|
||||
cache.Key("wiki:project", projectIDStr),
|
||||
cache.Key("battle_replay:project", projectIDStr),
|
||||
)
|
||||
|
||||
currentEntity, err := entityRepo.GetByProjectID(ctx, projectUUID)
|
||||
@@ -547,44 +549,44 @@ func (s *submissionService) applySnapshot(ctx context.Context, tx pgx.Tx, projec
|
||||
return fiber.NewError(fiber.StatusNotFound, "Battle replay not found: "+err.Error())
|
||||
}
|
||||
|
||||
persistEntityIDs := make(map[string]struct{})
|
||||
persistEntityIDs := make(map[string]struct{}, len(snapshotData.Entities))
|
||||
for _, item := range snapshotData.Entities {
|
||||
persistEntityIDs[item.ID] = struct{}{}
|
||||
}
|
||||
persistGeometryIDs := make(map[string]struct{})
|
||||
persistGeometryIDs := make(map[string]struct{}, len(snapshotData.Geometries))
|
||||
for _, item := range snapshotData.Geometries {
|
||||
persistGeometryIDs[item.ID] = struct{}{}
|
||||
}
|
||||
persistWikiIDs := make(map[string]struct{})
|
||||
persistWikiIDs := make(map[string]struct{}, len(snapshotData.Wikis))
|
||||
for _, item := range snapshotData.Wikis {
|
||||
persistWikiIDs[item.ID] = struct{}{}
|
||||
}
|
||||
persistReplayIDs := make(map[string]struct{})
|
||||
persistReplayIDs := make(map[string]struct{}, len(snapshotData.Replays))
|
||||
for _, item := range snapshotData.Replays {
|
||||
persistReplayIDs[item.ID] = struct{}{}
|
||||
}
|
||||
|
||||
persistCurrentEntityIDs := make(map[string]struct{})
|
||||
persistCurrentEntityIDs := make(map[string]struct{}, len(currentEntity))
|
||||
for _, item := range currentEntity {
|
||||
persistCurrentEntityIDs[item.ID] = struct{}{}
|
||||
}
|
||||
persistCurrentGeometryIDs := make(map[string]struct{})
|
||||
persistCurrentGeometryIDs := make(map[string]struct{}, len(currentGeometry))
|
||||
for _, item := range currentGeometry {
|
||||
persistCurrentGeometryIDs[item.ID] = struct{}{}
|
||||
}
|
||||
persistCurrentWikiIDs := make(map[string]struct{})
|
||||
persistCurrentWikiIDs := make(map[string]struct{}, len(currentWiki))
|
||||
for _, item := range currentWiki {
|
||||
persistCurrentWikiIDs[item.ID] = struct{}{}
|
||||
}
|
||||
persistCurrentReplayIDs := make(map[string]struct{})
|
||||
persistCurrentReplayIDs := make(map[string]struct{}, len(currentBattleReplay))
|
||||
for _, item := range currentBattleReplay {
|
||||
persistCurrentReplayIDs[item.ID] = struct{}{}
|
||||
}
|
||||
|
||||
listDeleteEntities := make([]pgtype.UUID, 0)
|
||||
listDeleteWikis := make([]pgtype.UUID, 0)
|
||||
listDeleteGeometries := make([]pgtype.UUID, 0)
|
||||
listDeleteBattleReplays := make([]pgtype.UUID, 0)
|
||||
listDeleteEntities := make([]pgtype.UUID, 0, len(currentEntity))
|
||||
listDeleteWikis := make([]pgtype.UUID, 0, len(currentWiki))
|
||||
listDeleteGeometries := make([]pgtype.UUID, 0, len(currentGeometry))
|
||||
listDeleteBattleReplays := make([]pgtype.UUID, 0, len(currentBattleReplay))
|
||||
|
||||
for _, e := range currentEntity {
|
||||
if _, ok := persistEntityIDs[e.ID]; !ok {
|
||||
@@ -654,7 +656,7 @@ func (s *submissionService) applySnapshot(ctx context.Context, tx pgx.Tx, projec
|
||||
}
|
||||
}
|
||||
|
||||
refEntityIDs := []string{}
|
||||
refEntityIDs := make([]string, 0, len(snapshotData.Entities))
|
||||
for _, e := range snapshotData.Entities {
|
||||
if e.Source == "ref" {
|
||||
refEntityIDs = append(refEntityIDs, e.ID)
|
||||
@@ -662,7 +664,7 @@ func (s *submissionService) applySnapshot(ctx context.Context, tx pgx.Tx, projec
|
||||
}
|
||||
|
||||
refEntities, _ := entityRepo.GetByIDs(ctx, refEntityIDs)
|
||||
refEntityMap := make(map[string]bool)
|
||||
refEntityMap := make(map[string]bool, len(refEntities))
|
||||
for _, e := range refEntities {
|
||||
refEntityMap[e.ID] = true
|
||||
}
|
||||
@@ -722,19 +724,19 @@ func (s *submissionService) applySnapshot(ctx context.Context, tx pgx.Tx, projec
|
||||
}
|
||||
snapshotData.Entities = newEntities
|
||||
|
||||
refGeometryIDs := []string{}
|
||||
refGeometryIDs := make([]string, 0, len(snapshotData.Geometries))
|
||||
for _, g := range snapshotData.Geometries {
|
||||
if g.Source == "ref" {
|
||||
refGeometryIDs = append(refGeometryIDs, g.ID)
|
||||
}
|
||||
}
|
||||
refGeometries, _ := geometryRepo.GetByIDs(ctx, refGeometryIDs)
|
||||
refGeometryMap := make(map[string]bool)
|
||||
refGeometryMap := make(map[string]bool, len(refGeometries))
|
||||
for _, g := range refGeometries {
|
||||
refGeometryMap[g.ID] = true
|
||||
}
|
||||
|
||||
validGeometries := make(map[string]bool)
|
||||
validGeometries := make(map[string]bool, len(snapshotData.Geometries))
|
||||
for _, g := range snapshotData.Geometries {
|
||||
if g.Operation != "delete" {
|
||||
validGeometries[g.ID] = true
|
||||
@@ -851,14 +853,14 @@ func (s *submissionService) applySnapshot(ctx context.Context, tx pgx.Tx, projec
|
||||
}
|
||||
}
|
||||
|
||||
refWikiIDs := []string{}
|
||||
refWikiIDs := make([]string, 0, len(snapshotData.Wikis))
|
||||
for _, w := range snapshotData.Wikis {
|
||||
if w.Source == "ref" {
|
||||
refWikiIDs = append(refWikiIDs, w.ID)
|
||||
}
|
||||
}
|
||||
refWikis, _ := wikiRepo.GetByIDs(ctx, refWikiIDs)
|
||||
refWikiMap := make(map[string]bool)
|
||||
refWikiMap := make(map[string]bool, len(refWikis))
|
||||
for _, w := range refWikis {
|
||||
refWikiMap[w.ID] = true
|
||||
}
|
||||
@@ -906,7 +908,7 @@ func (s *submissionService) applySnapshot(ctx context.Context, tx pgx.Tx, projec
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create wiki content: "+err.Error())
|
||||
}
|
||||
|
||||
_ = s.c.Del(ctx, fmt.Sprintf("wiki:id:%s", wikiUUID.String()), fmt.Sprintf("wiki:slug:%s", *wiki.Slug))
|
||||
_ = s.c.Del(ctx, cache.Key("wiki:id", wikiUUID.String()), cache.Key("wiki:slug", *wiki.Slug))
|
||||
|
||||
newWikis = append(newWikis, snapshotData.Wikis[i])
|
||||
|
||||
@@ -936,7 +938,7 @@ func (s *submissionService) applySnapshot(ctx context.Context, tx pgx.Tx, projec
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create wiki content: "+err.Error())
|
||||
}
|
||||
|
||||
_ = s.c.Del(ctx, fmt.Sprintf("wiki:id:%s", wikiUUID.String()), fmt.Sprintf("wiki:slug:%s", *wiki.Slug))
|
||||
_ = s.c.Del(ctx, cache.Key("wiki:id", wikiUUID.String()), cache.Key("wiki:slug", *wiki.Slug))
|
||||
|
||||
newWikis = append(newWikis, snapshotData.Wikis[i])
|
||||
|
||||
@@ -998,17 +1000,17 @@ func (s *submissionService) applySnapshot(ctx context.Context, tx pgx.Tx, projec
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete wiki entity: "+err.Error())
|
||||
}
|
||||
|
||||
validEntities := make(map[string]bool)
|
||||
validEntities := make(map[string]bool, len(snapshotData.Entities))
|
||||
for _, e := range snapshotData.Entities {
|
||||
validEntities[e.ID] = true
|
||||
}
|
||||
validWikis := make(map[string]bool)
|
||||
validWikis := make(map[string]bool, len(snapshotData.Wikis))
|
||||
for _, w := range snapshotData.Wikis {
|
||||
validWikis[w.ID] = true
|
||||
}
|
||||
|
||||
if len(snapshotData.GeometryEntity) > 0 {
|
||||
geomLinks := make(map[string][]pgtype.UUID)
|
||||
geomLinks := make(map[string][]pgtype.UUID, len(snapshotData.GeometryEntity))
|
||||
for _, link := range snapshotData.GeometryEntity {
|
||||
if link.Operation == "delete" {
|
||||
continue
|
||||
@@ -1034,7 +1036,7 @@ func (s *submissionService) applySnapshot(ctx context.Context, tx pgx.Tx, projec
|
||||
}
|
||||
|
||||
if len(snapshotData.EntityWiki) > 0 {
|
||||
wikiLinks := make(map[string][]pgtype.UUID)
|
||||
wikiLinks := make(map[string][]pgtype.UUID, len(snapshotData.EntityWiki))
|
||||
for _, link := range snapshotData.EntityWiki {
|
||||
if link.Operation == "delete" || (link.IsDeleted != nil && *link.IsDeleted == 1) {
|
||||
continue
|
||||
@@ -1059,8 +1061,8 @@ func (s *submissionService) applySnapshot(ctx context.Context, tx pgx.Tx, projec
|
||||
}
|
||||
}
|
||||
|
||||
wikiDeleteIDs := make([]string, 0)
|
||||
entityDeleteIDs := make([]string, 0)
|
||||
wikiDeleteIDs := make([]string, 0, len(listDeleteWikis)+len(snapshotData.Wikis))
|
||||
entityDeleteIDs := make([]string, 0, len(listDeleteEntities)+len(snapshotData.Entities))
|
||||
|
||||
for _, id := range listDeleteWikis {
|
||||
wikiDeleteIDs = append(wikiDeleteIDs, convert.UUIDToString(id))
|
||||
@@ -1084,6 +1086,8 @@ func (s *submissionService) applySnapshot(ctx context.Context, tx pgx.Tx, projec
|
||||
ProjectID: convert.UUIDToString(projectUUID),
|
||||
DeleteWikiIDs: wikiDeleteIDs,
|
||||
DeleteEntityIDs: entityDeleteIDs,
|
||||
Wikis: make([]*models.RagWikiItem, 0, len(snapshotData.Wikis)),
|
||||
Entities: make([]*models.RagEntityItem, 0, len(snapshotData.Entities)),
|
||||
}
|
||||
|
||||
for _, wiki := range snapshotData.Wikis {
|
||||
@@ -1118,10 +1122,10 @@ func (s *submissionService) clearProjectItems(ctx context.Context, tx pgx.Tx, pr
|
||||
|
||||
projectIDStr := convert.UUIDToString(projectUUID)
|
||||
_ = s.c.Del(ctx,
|
||||
fmt.Sprintf("entity:project:%s", projectIDStr),
|
||||
fmt.Sprintf("geometry:project:%s", projectIDStr),
|
||||
fmt.Sprintf("wiki:project:%s", projectIDStr),
|
||||
fmt.Sprintf("battle_replay:project:%s", projectIDStr),
|
||||
cache.Key("entity:project", projectIDStr),
|
||||
cache.Key("geometry:project", projectIDStr),
|
||||
cache.Key("wiki:project", projectIDStr),
|
||||
cache.Key("battle_replay:project", projectIDStr),
|
||||
)
|
||||
|
||||
currentEntity, _ := entityRepo.GetByProjectID(ctx, projectUUID)
|
||||
@@ -1129,28 +1133,28 @@ func (s *submissionService) clearProjectItems(ctx context.Context, tx pgx.Tx, pr
|
||||
currentWiki, _ := wikiRepo.GetByProjectID(ctx, projectUUID)
|
||||
currentBattleReplay, _ := battleReplayRepo.GetByProjectID(ctx, projectUUID)
|
||||
|
||||
var entityIDs []pgtype.UUID
|
||||
entityIDs := make([]pgtype.UUID, 0, len(currentEntity))
|
||||
for _, e := range currentEntity {
|
||||
id, err := convert.StringToUUID(e.ID)
|
||||
if err == nil {
|
||||
entityIDs = append(entityIDs, id)
|
||||
}
|
||||
}
|
||||
var geometryIDs []pgtype.UUID
|
||||
geometryIDs := make([]pgtype.UUID, 0, len(currentGeometry))
|
||||
for _, g := range currentGeometry {
|
||||
id, err := convert.StringToUUID(g.ID)
|
||||
if err == nil {
|
||||
geometryIDs = append(geometryIDs, id)
|
||||
}
|
||||
}
|
||||
var wikiIDs []pgtype.UUID
|
||||
wikiIDs := make([]pgtype.UUID, 0, len(currentWiki))
|
||||
for _, w := range currentWiki {
|
||||
id, err := convert.StringToUUID(w.ID)
|
||||
if err == nil {
|
||||
wikiIDs = append(wikiIDs, id)
|
||||
}
|
||||
}
|
||||
var replayIDs []pgtype.UUID
|
||||
replayIDs := make([]pgtype.UUID, 0, len(currentBattleReplay))
|
||||
for _, br := range currentBattleReplay {
|
||||
id, err := convert.StringToUUID(br.ID)
|
||||
if err == nil {
|
||||
@@ -1161,7 +1165,7 @@ func (s *submissionService) clearProjectItems(ctx context.Context, tx pgx.Tx, pr
|
||||
if len(entityIDs) > 0 {
|
||||
_ = entityRepo.DeleteByIDs(ctx, entityIDs)
|
||||
for _, e := range currentEntity {
|
||||
_ = s.c.Del(ctx, fmt.Sprintf("entity:slug:%s", e.Slug))
|
||||
_ = s.c.Del(ctx, cache.Key("entity:slug", e.Slug))
|
||||
}
|
||||
}
|
||||
if len(geometryIDs) > 0 {
|
||||
@@ -1170,7 +1174,7 @@ func (s *submissionService) clearProjectItems(ctx context.Context, tx pgx.Tx, pr
|
||||
if len(wikiIDs) > 0 {
|
||||
_ = wikiRepo.DeleteByIDs(ctx, wikiIDs)
|
||||
for _, w := range currentWiki {
|
||||
_ = s.c.Del(ctx, fmt.Sprintf("wiki:slug:%s", w.Slug))
|
||||
_ = s.c.Del(ctx, cache.Key("wiki:slug", w.Slug))
|
||||
}
|
||||
}
|
||||
if len(replayIDs) > 0 {
|
||||
@@ -1180,11 +1184,11 @@ func (s *submissionService) clearProjectItems(ctx context.Context, tx pgx.Tx, pr
|
||||
_ = geometryRepo.DeleteEntityGeometriesByProjectID(ctx, projectUUID)
|
||||
_ = wikiRepo.DeleteEntityWikisByProjectID(ctx, projectUUID)
|
||||
|
||||
var entityDeleteIDs []string
|
||||
entityDeleteIDs := make([]string, 0, len(currentEntity))
|
||||
for _, e := range currentEntity {
|
||||
entityDeleteIDs = append(entityDeleteIDs, e.ID)
|
||||
}
|
||||
var wikiDeleteIDs []string
|
||||
wikiDeleteIDs := make([]string, 0, len(currentWiki))
|
||||
for _, w := range currentWiki {
|
||||
wikiDeleteIDs = append(wikiDeleteIDs, w.ID)
|
||||
}
|
||||
|
||||
@@ -7,9 +7,18 @@ import (
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
const tileCacheControl = "public, max-age=31536000, immutable"
|
||||
|
||||
type TileResponse struct {
|
||||
Data []byte
|
||||
ContentType string
|
||||
ContentEncoding string
|
||||
CacheControl string
|
||||
}
|
||||
|
||||
type TileService interface {
|
||||
GetMetadata(ctx context.Context) (map[string]string, *fiber.Error)
|
||||
GetTile(ctx context.Context, z, x, y int) ([]byte, map[string]string, *fiber.Error)
|
||||
GetTile(ctx context.Context, z, x, y int) (TileResponse, *fiber.Error)
|
||||
}
|
||||
|
||||
type tileService struct {
|
||||
@@ -32,29 +41,30 @@ func (t *tileService) GetMetadata(ctx context.Context) (map[string]string, *fibe
|
||||
return metaData, nil
|
||||
}
|
||||
|
||||
|
||||
func (t *tileService) GetTile(ctx context.Context, z, x, y int) ([]byte, map[string]string, *fiber.Error) {
|
||||
contentType := make(map[string]string)
|
||||
|
||||
func (t *tileService) GetTile(ctx context.Context, z, x, y int) (TileResponse, *fiber.Error) {
|
||||
data, format, isPBF, err := t.tileRepo.GetTile(ctx, z, x, y)
|
||||
if err != nil {
|
||||
return nil, contentType, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch tile data")
|
||||
return TileResponse{}, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch tile data")
|
||||
}
|
||||
|
||||
res := TileResponse{
|
||||
Data: data,
|
||||
CacheControl: tileCacheControl,
|
||||
}
|
||||
switch format {
|
||||
case "pbf":
|
||||
contentType["Content-Type"] = "application/x-protobuf"
|
||||
res.ContentType = "application/x-protobuf"
|
||||
case "png":
|
||||
contentType["Content-Type"] = "image/png"
|
||||
res.ContentType = "image/png"
|
||||
case "jpg", "jpeg":
|
||||
contentType["Content-Type"] = "image/jpeg"
|
||||
res.ContentType = "image/jpeg"
|
||||
default:
|
||||
contentType["Content-Type"] = "application/octet-stream"
|
||||
res.ContentType = "application/octet-stream"
|
||||
}
|
||||
|
||||
if isPBF {
|
||||
contentType["Content-Encoding"] = "gzip"
|
||||
res.ContentEncoding = "gzip"
|
||||
}
|
||||
|
||||
return data, contentType, nil
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"history-api/internal/dtos/request"
|
||||
"history-api/internal/dtos/response"
|
||||
"history-api/internal/gen/sqlc"
|
||||
@@ -103,7 +102,7 @@ func (u *userService) CreateUser(ctx context.Context, dto *request.CreateUserDto
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create user profile")
|
||||
}
|
||||
|
||||
var roleIdList []pgtype.UUID
|
||||
roleIdList := make([]pgtype.UUID, 0, len(dto.Roles))
|
||||
for _, rId := range dto.Roles {
|
||||
rid, err := convert.StringToUUID(rId)
|
||||
if err == nil {
|
||||
@@ -339,8 +338,8 @@ func (u *userService) ChangeRoleUser(ctx context.Context, userId string, claims
|
||||
}
|
||||
}
|
||||
|
||||
user.Roles = make([]*models.RoleSimple, 0)
|
||||
roleIdList := make([]pgtype.UUID, 0)
|
||||
user.Roles = make([]*models.RoleSimple, 0, len(newListRole))
|
||||
roleIdList := make([]pgtype.UUID, 0, len(newListRole))
|
||||
for _, role := range newListRole {
|
||||
roleID, err := convert.StringToUUID(role.ID)
|
||||
if err != nil {
|
||||
@@ -378,8 +377,8 @@ func (u *userService) ChangeRoleUser(ctx context.Context, userId string, claims
|
||||
}
|
||||
|
||||
mapCache := map[string]any{
|
||||
fmt.Sprintf("user:email:%s", user.Email): user,
|
||||
fmt.Sprintf("user:id:%s", user.ID): user,
|
||||
cache.Key("user:email", user.Email): user,
|
||||
cache.Key("user:id", user.ID): user,
|
||||
}
|
||||
_ = u.c.MSet(ctx, mapCache, constants.NormalCacheDuration)
|
||||
|
||||
@@ -489,6 +488,7 @@ func (m *userService) fillSearchArgs(arg *sqlc.SearchUsersParams, dto *request.S
|
||||
}
|
||||
|
||||
if len(dto.RoleIDs) > 0 {
|
||||
arg.RoleIds = make([]pgtype.UUID, 0, len(dto.RoleIDs))
|
||||
for _, id := range dto.RoleIDs {
|
||||
if u, err := convert.StringToUUID(id); err == nil {
|
||||
arg.RoleIds = append(arg.RoleIds, u)
|
||||
|
||||
@@ -2,7 +2,6 @@ package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"history-api/internal/dtos/request"
|
||||
"history-api/internal/dtos/response"
|
||||
"history-api/internal/gen/sqlc"
|
||||
@@ -92,7 +91,8 @@ func (v *verificationService) CreateVerification(ctx context.Context, userId str
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Invalid verification ID")
|
||||
}
|
||||
|
||||
mediaIdList := make([]pgtype.UUID, 0)
|
||||
mediaIdList := make([]pgtype.UUID, 0, len(mediaList))
|
||||
item.Media = make([]*models.MediaSimpleEntity, 0, len(mediaList))
|
||||
for _, it := range mediaList {
|
||||
mediaId, err := convert.StringToUUID(it.ID)
|
||||
if err != nil {
|
||||
@@ -185,6 +185,7 @@ func (m *verificationService) fillSearchArgs(arg *sqlc.SearchUserVerificationsPa
|
||||
}
|
||||
|
||||
if len(dto.Statuses) > 0 {
|
||||
arg.Statuses = make([]int16, 0, len(dto.Statuses))
|
||||
for _, id := range dto.Statuses {
|
||||
if u := constants.ParseStatusTypeText(id); u != constants.StatusTypeUnknown {
|
||||
arg.Statuses = append(arg.Statuses, u.Int16())
|
||||
@@ -193,6 +194,7 @@ func (m *verificationService) fillSearchArgs(arg *sqlc.SearchUserVerificationsPa
|
||||
}
|
||||
|
||||
if len(dto.VerifyTypes) > 0 {
|
||||
arg.VerifyTypes = make([]int16, 0, len(dto.VerifyTypes))
|
||||
for _, id := range dto.VerifyTypes {
|
||||
if u := constants.ParseVerifyTypeText(id); u != constants.VerifyTypeUnknown {
|
||||
arg.VerifyTypes = append(arg.VerifyTypes, u.Int16())
|
||||
@@ -201,6 +203,7 @@ func (m *verificationService) fillSearchArgs(arg *sqlc.SearchUserVerificationsPa
|
||||
}
|
||||
|
||||
if len(dto.UserIDs) > 0 {
|
||||
arg.UserIds = make([]pgtype.UUID, 0, len(dto.UserIDs))
|
||||
for _, id := range dto.UserIDs {
|
||||
if u, err := convert.StringToUUID(id); err == nil {
|
||||
arg.UserIds = append(arg.UserIds, u)
|
||||
@@ -355,8 +358,8 @@ func (v *verificationService) UpdateStatusVerification(ctx context.Context, user
|
||||
}
|
||||
|
||||
if statusType == constants.StatusTypeApproved {
|
||||
roleIdList := make([]pgtype.UUID, 0)
|
||||
userVerification.Roles = append(userVerification.Roles, historianRole.ToRoleSimple())
|
||||
roleIdList := make([]pgtype.UUID, 0, len(userVerification.Roles)+1)
|
||||
|
||||
roleIdList = append(roleIdList, historianRoleID)
|
||||
|
||||
@@ -395,8 +398,8 @@ func (v *verificationService) UpdateStatusVerification(ctx context.Context, user
|
||||
}
|
||||
|
||||
mapCache := map[string]any{
|
||||
fmt.Sprintf("user:email:%s", userVerification.Email): userVerification,
|
||||
fmt.Sprintf("user:id:%s", userVerification.ID): userVerification,
|
||||
cache.Key("user:email", userVerification.Email): userVerification,
|
||||
cache.Key("user:id", userVerification.ID): userVerification,
|
||||
}
|
||||
_ = v.c.MSet(ctx, mapCache, constants.NormalCacheDuration)
|
||||
} else {
|
||||
|
||||
@@ -137,8 +137,13 @@ func (s *wikiService) GetWikisByEntityIDs(ctx context.Context, req *request.GetW
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch wiki IDs by entity IDs")
|
||||
}
|
||||
|
||||
wikiIDMap := make(map[string]struct{})
|
||||
var allWikiIDs []string
|
||||
totalWikiIDs := 0
|
||||
for _, wIDs := range mapping {
|
||||
totalWikiIDs += len(wIDs)
|
||||
}
|
||||
|
||||
wikiIDMap := make(map[string]struct{}, totalWikiIDs)
|
||||
allWikiIDs := make([]string, 0, totalWikiIDs)
|
||||
for _, wIDs := range mapping {
|
||||
for _, wID := range wIDs {
|
||||
if _, ok := wikiIDMap[wID]; !ok {
|
||||
@@ -153,15 +158,16 @@ func (s *wikiService) GetWikisByEntityIDs(ctx context.Context, req *request.GetW
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch wikis")
|
||||
}
|
||||
|
||||
wikisByID := make(map[string]*models.WikiEntity)
|
||||
wikisByID := make(map[string]*models.WikiEntity, len(wikis))
|
||||
for _, w := range wikis {
|
||||
wikisByID[w.ID] = w
|
||||
}
|
||||
|
||||
result := make(map[string][]*response.WikiResponse)
|
||||
result := make(map[string][]*response.WikiResponse, len(req.EntityIDs))
|
||||
for _, idStr := range req.EntityIDs {
|
||||
result[idStr] = make([]*response.WikiResponse, 0)
|
||||
if wIDs, exists := mapping[idStr]; exists {
|
||||
wIDs, exists := mapping[idStr]
|
||||
result[idStr] = make([]*response.WikiResponse, 0, len(wIDs))
|
||||
if exists {
|
||||
for _, wID := range wIDs {
|
||||
if w, found := wikisByID[wID]; found {
|
||||
result[idStr] = append(result[idStr], w.ToResponse())
|
||||
@@ -179,7 +185,7 @@ func (s *wikiService) GetWikiContentsPreviewByIDs(ctx context.Context, req *requ
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch wiki contents")
|
||||
}
|
||||
|
||||
var results []*response.WikiContentPreviewResponse
|
||||
results := make([]*response.WikiContentPreviewResponse, 0, len(contents))
|
||||
for _, c := range contents {
|
||||
results = append(results, &response.WikiContentPreviewResponse{
|
||||
ID: c.ID,
|
||||
|
||||
Reference in New Issue
Block a user