diff --git a/.env b/.env index ceac08d..11d0f87 100644 --- a/.env +++ b/.env @@ -13,4 +13,4 @@ SMTP_FROM=info@tailly.ru AppURL="https://tailly.ru" MESSAGE_SERVICE_ADDRESS="tailly_messages:50052" SUBSCRIBE_SERVICE_ADDRESS="tailly_subscribers:50053" -CLIP_SERVICE_ADDRESS="tailly_clips:50054" \ No newline at end of file +CLIP_SERVICE_ADDRESS="localhost:50054" \ No newline at end of file diff --git a/internal/domain/clip.go b/internal/domain/clip.go index 8339590..0017a15 100644 --- a/internal/domain/clip.go +++ b/internal/domain/clip.go @@ -8,7 +8,6 @@ type Clip struct { VideoURL string `json:"videoUrl"` ThumbnailURL string `json:"thumbnailUrl"` AuthorID int `json:"-"` - Author *User `json:"author"` LikesCount int `json:"likesCount"` CommentsCount int `json:"commentsCount"` CreatedAt time.Time `json:"createdAt"` diff --git a/internal/http/graph/clip_resolvers.go b/internal/http/graph/clip_resolvers.go index b174ee9..77172c1 100644 --- a/internal/http/graph/clip_resolvers.go +++ b/internal/http/graph/clip_resolvers.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "io" - "log" "tailly_back_v2/internal/domain" "tailly_back_v2/proto" "time" @@ -31,47 +30,15 @@ func (r *clipResolver) IsLiked(ctx context.Context, obj *domain.Clip) (bool, err } func (r *clipResolver) Author(ctx context.Context, obj *domain.Clip) (*domain.User, error) { - log.Printf("Resolving author for clip %d, authorID: %d", obj.ID, obj.AuthorID) - if obj.AuthorID == 0 { - log.Printf("WARNING: Clip %d has no authorID, returning stub", obj.ID) - return &domain.User{ - ID: 0, - Username: "Unknown User", - Avatar: "/img/logo.png", - Email: "unknown@example.com", - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - }, nil + return nil, fmt.Errorf("clip has no author ID") } - // Получаем пользователя из сервиса author, err := r.Services.User.GetByID(ctx, obj.AuthorID) if err != nil { - log.Printf("ERROR: Failed to get author %d for clip %d: %v", obj.AuthorID, obj.ID, err) - return &domain.User{ - ID: obj.AuthorID, - Username: "Error Loading User", - Avatar: "/img/logo.png", - Email: "error@example.com", - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - }, nil - } - log.Printf("Resolved author for clip %d", author) - if author == nil { - log.Printf("WARNING: Author %d not found for clip %d", obj.AuthorID, obj.ID) - return &domain.User{ - ID: obj.AuthorID, - Username: "Deleted User", - Avatar: "/img/logo.png", - Email: "deleted@example.com", - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - }, nil + return nil, fmt.Errorf("failed to get author: %w", err) } - log.Printf("Successfully resolved author %d for clip %d", obj.AuthorID, obj.ID) return author, nil } @@ -252,24 +219,10 @@ func (r *queryResolver) Clips(ctx context.Context, limit *int, offset *int) ([]* Offset: int32(offsetVal), }) if err != nil { - log.Printf("ERROR: Failed to get clips from gRPC service: %v", err) return nil, fmt.Errorf("failed to get clips: %w", err) } - clips := r.protoClipsToDomain(resp.Clips) - - // Детальное логирование - log.Printf("Retrieved %d clips from gRPC service", len(clips)) - for i, clip := range clips { - log.Printf("Clip %d: ID=%d, Title=%s, AuthorID=%d", i, clip.ID, clip.Title, clip.AuthorID) - - // Проверяем, что AuthorID заполнен - if clip.AuthorID == 0 { - log.Printf("ERROR: Clip %d has AuthorID=0!", clip.ID) - } - } - - return clips, nil + return r.protoClipsToDomain(resp.Clips), nil } // UserClips is the resolver for the userClips field. diff --git a/internal/http/graph/generated.go b/internal/http/graph/generated.go index 4de8332..fe2d2b5 100644 --- a/internal/http/graph/generated.go +++ b/internal/http/graph/generated.go @@ -303,6 +303,8 @@ type ChatResolver interface { UpdatedAt(ctx context.Context, obj *domain.Chat) (string, error) } type ClipResolver interface { + Author(ctx context.Context, obj *domain.Clip) (*domain.User, error) + IsLiked(ctx context.Context, obj *domain.Clip) (bool, error) CreatedAt(ctx context.Context, obj *domain.Clip) (string, error) UpdatedAt(ctx context.Context, obj *domain.Clip) (string, error) @@ -3274,7 +3276,7 @@ func (ec *executionContext) _Clip_author(ctx context.Context, field graphql.Coll }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.Author, nil + return ec.resolvers.Clip().Author(rctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -3295,8 +3297,8 @@ func (ec *executionContext) fieldContext_Clip_author(_ context.Context, field gr fc = &graphql.FieldContext{ Object: "Clip", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": @@ -13905,10 +13907,41 @@ func (ec *executionContext) _Clip(ctx context.Context, sel ast.SelectionSet, obj atomic.AddUint32(&out.Invalids, 1) } case "author": - out.Values[i] = ec._Clip_author(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Clip_author(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "commentsCount": out.Values[i] = ec._Clip_commentsCount(ctx, field, obj) if out.Values[i] == graphql.Null {