package logic import ( "context" "database/sql" "fmt" "time" "git.cialloo.com/CiallooWeb/Blog/app/internal/svc" "git.cialloo.com/CiallooWeb/Blog/app/internal/types" "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/zeromicro/go-zero/core/logx" ) type GetPostLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } // Get a blog post by ID func NewGetPostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetPostLogic { return &GetPostLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } func (l *GetPostLogic) GetPost(req *types.GetPostReq) (resp *types.GetPostResp, err error) { var post types.GetPostResp var coverID sql.NullInt64 // Query post with cover image query := ` SELECT p.id, p.title, p.content, p.created_at, p.updated_at, p.cover_id FROM posts p WHERE p.id = $1 ` err = l.svcCtx.DB.QueryRowContext(l.ctx, query, req.PostId).Scan( &post.PostId, &post.Title, &post.Content, &post.CreatedAt, &post.UpdatedAt, &coverID, ) if err != nil { if err == sql.ErrNoRows { l.Errorf("Post not found with id: %s", req.PostId) return nil, fmt.Errorf("post not found") } l.Errorf("Failed to get post: %v", err) return nil, err } // If cover image exists, get its URL if coverID.Valid { coverQuery := `SELECT file_key FROM files WHERE id = $1` var fileKey string err = l.svcCtx.DB.QueryRowContext(l.ctx, coverQuery, coverID.Int64).Scan(&fileKey) if err == nil { // Generate presigned URL for cover image expiration := time.Duration(l.svcCtx.Config.S3.PresignedURLExpiration) * time.Second presignClient := s3.NewPresignClient(l.svcCtx.S3Client) getObjectInput := &s3.GetObjectInput{ Bucket: &l.svcCtx.Config.S3.Bucket, Key: &fileKey, } presignedReq, err := presignClient.PresignGetObject(l.ctx, getObjectInput, func(opts *s3.PresignOptions) { opts.Expires = expiration }) if err == nil { post.CoverImageUrl = presignedReq.URL } } } // Convert timestamps to Unix post.CreatedAt = post.CreatedAt * 1000 // Convert to milliseconds if needed post.UpdatedAt = post.UpdatedAt * 1000 return &post, nil }