v0.0.27 Изменен принцип загрузки изображения в s3
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
a9865fdc3c
commit
ef9bb2c484
@ -140,7 +140,7 @@ type ComplexityRoot struct {
|
|||||||
ConfirmEmail func(childComplexity int, token string) int
|
ConfirmEmail func(childComplexity int, token string) int
|
||||||
CreateChat func(childComplexity int, user1Id int, user2Id int) int
|
CreateChat func(childComplexity int, user1Id int, user2Id int) int
|
||||||
CreateComment func(childComplexity int, postID int, content string) int
|
CreateComment func(childComplexity int, postID int, content string) int
|
||||||
CreatePost func(childComplexity int, title string, content string) int
|
CreatePost func(childComplexity int, input CreatePostInput) int
|
||||||
DeletePost func(childComplexity int, id int) int
|
DeletePost func(childComplexity int, id int) int
|
||||||
FollowUser func(childComplexity int, followingID int) int
|
FollowUser func(childComplexity int, followingID int) int
|
||||||
LikePost func(childComplexity int, postID int) int
|
LikePost func(childComplexity int, postID int) int
|
||||||
@ -180,6 +180,7 @@ type ComplexityRoot struct {
|
|||||||
|
|
||||||
Query struct {
|
Query struct {
|
||||||
Comments func(childComplexity int, postID int) int
|
Comments func(childComplexity int, postID int) int
|
||||||
|
GenerateUploadURL func(childComplexity int, filename string) int
|
||||||
GetChat func(childComplexity int, user1Id int, user2Id int) int
|
GetChat func(childComplexity int, user1Id int, user2Id int) int
|
||||||
GetChatMessages func(childComplexity int, chatID int, limit int, offset int) int
|
GetChatMessages func(childComplexity int, chatID int, limit int, offset int) int
|
||||||
GetFollowers func(childComplexity int, userID int, limit *int, offset *int) int
|
GetFollowers func(childComplexity int, userID int, limit *int, offset *int) int
|
||||||
@ -234,6 +235,12 @@ type ComplexityRoot struct {
|
|||||||
Success func(childComplexity int) int
|
Success func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UploadURL struct {
|
||||||
|
ExpiresAt func(childComplexity int) int
|
||||||
|
Key func(childComplexity int) int
|
||||||
|
URL func(childComplexity int) int
|
||||||
|
}
|
||||||
|
|
||||||
User struct {
|
User struct {
|
||||||
Avatar func(childComplexity int) int
|
Avatar func(childComplexity int) int
|
||||||
CreatedAt func(childComplexity int) int
|
CreatedAt func(childComplexity int) int
|
||||||
@ -277,7 +284,7 @@ type MutationResolver interface {
|
|||||||
Register(ctx context.Context, input domain.RegisterInput) (*domain.User, error)
|
Register(ctx context.Context, input domain.RegisterInput) (*domain.User, error)
|
||||||
Login(ctx context.Context, input domain.LoginInput) (*domain.Tokens, error)
|
Login(ctx context.Context, input domain.LoginInput) (*domain.Tokens, error)
|
||||||
RefreshTokens(ctx context.Context, refreshToken string) (*domain.Tokens, error)
|
RefreshTokens(ctx context.Context, refreshToken string) (*domain.Tokens, error)
|
||||||
CreatePost(ctx context.Context, title string, content string) (*domain.Post, error)
|
CreatePost(ctx context.Context, input CreatePostInput) (*domain.Post, error)
|
||||||
CreateComment(ctx context.Context, postID int, content string) (*domain.Comment, error)
|
CreateComment(ctx context.Context, postID int, content string) (*domain.Comment, error)
|
||||||
LikePost(ctx context.Context, postID int) (*domain.Like, error)
|
LikePost(ctx context.Context, postID int) (*domain.Like, error)
|
||||||
UnlikePost(ctx context.Context, postID int) (bool, error)
|
UnlikePost(ctx context.Context, postID int) (bool, error)
|
||||||
@ -310,6 +317,7 @@ type QueryResolver interface {
|
|||||||
Post(ctx context.Context, id int) (*domain.Post, error)
|
Post(ctx context.Context, id int) (*domain.Post, error)
|
||||||
Posts(ctx context.Context) ([]*domain.Post, error)
|
Posts(ctx context.Context) ([]*domain.Post, error)
|
||||||
PostsPaginated(ctx context.Context, limit int, offset int) ([]*domain.Post, error)
|
PostsPaginated(ctx context.Context, limit int, offset int) ([]*domain.Post, error)
|
||||||
|
GenerateUploadURL(ctx context.Context, filename string) (*UploadURL, error)
|
||||||
GetUserPosts(ctx context.Context, userID int) ([]*domain.Post, error)
|
GetUserPosts(ctx context.Context, userID int) ([]*domain.Post, error)
|
||||||
User(ctx context.Context, id int) (*domain.User, error)
|
User(ctx context.Context, id int) (*domain.User, error)
|
||||||
Users(ctx context.Context) ([]*domain.User, error)
|
Users(ctx context.Context) ([]*domain.User, error)
|
||||||
@ -733,7 +741,7 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
|||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.complexity.Mutation.CreatePost(childComplexity, args["title"].(string), args["content"].(string)), true
|
return e.complexity.Mutation.CreatePost(childComplexity, args["input"].(CreatePostInput)), true
|
||||||
|
|
||||||
case "Mutation.deletePost":
|
case "Mutation.deletePost":
|
||||||
if e.complexity.Mutation.DeletePost == nil {
|
if e.complexity.Mutation.DeletePost == nil {
|
||||||
@ -1020,6 +1028,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
|||||||
|
|
||||||
return e.complexity.Query.Comments(childComplexity, args["postID"].(int)), true
|
return e.complexity.Query.Comments(childComplexity, args["postID"].(int)), true
|
||||||
|
|
||||||
|
case "Query.generateUploadURL":
|
||||||
|
if e.complexity.Query.GenerateUploadURL == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
args, err := ec.field_Query_generateUploadURL_args(ctx, rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Query.GenerateUploadURL(childComplexity, args["filename"].(string)), true
|
||||||
|
|
||||||
case "Query.getChat":
|
case "Query.getChat":
|
||||||
if e.complexity.Query.GetChat == nil {
|
if e.complexity.Query.GetChat == nil {
|
||||||
break
|
break
|
||||||
@ -1349,6 +1369,27 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
|||||||
|
|
||||||
return e.complexity.UnfollowResult.Success(childComplexity), true
|
return e.complexity.UnfollowResult.Success(childComplexity), true
|
||||||
|
|
||||||
|
case "UploadURL.expiresAt":
|
||||||
|
if e.complexity.UploadURL.ExpiresAt == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.UploadURL.ExpiresAt(childComplexity), true
|
||||||
|
|
||||||
|
case "UploadURL.key":
|
||||||
|
if e.complexity.UploadURL.Key == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.UploadURL.Key(childComplexity), true
|
||||||
|
|
||||||
|
case "UploadURL.url":
|
||||||
|
if e.complexity.UploadURL.URL == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.UploadURL.URL(childComplexity), true
|
||||||
|
|
||||||
case "User.avatar":
|
case "User.avatar":
|
||||||
if e.complexity.User.Avatar == nil {
|
if e.complexity.User.Avatar == nil {
|
||||||
break
|
break
|
||||||
@ -1468,6 +1509,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
|||||||
opCtx := graphql.GetOperationContext(ctx)
|
opCtx := graphql.GetOperationContext(ctx)
|
||||||
ec := executionContext{opCtx, e, 0, 0, make(chan graphql.DeferredResult)}
|
ec := executionContext{opCtx, e, 0, 0, make(chan graphql.DeferredResult)}
|
||||||
inputUnmarshalMap := graphql.BuildUnmarshalerMap(
|
inputUnmarshalMap := graphql.BuildUnmarshalerMap(
|
||||||
|
ec.unmarshalInputCreatePostInput,
|
||||||
ec.unmarshalInputLoginInput,
|
ec.unmarshalInputLoginInput,
|
||||||
ec.unmarshalInputRegisterInput,
|
ec.unmarshalInputRegisterInput,
|
||||||
)
|
)
|
||||||
@ -1685,16 +1727,11 @@ func (ec *executionContext) field_Mutation_createComment_args(ctx context.Contex
|
|||||||
func (ec *executionContext) field_Mutation_createPost_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
func (ec *executionContext) field_Mutation_createPost_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
||||||
var err error
|
var err error
|
||||||
args := map[string]any{}
|
args := map[string]any{}
|
||||||
arg0, err := processArgField(ctx, rawArgs, "title", ec.unmarshalNString2string)
|
arg0, err := processArgField(ctx, rawArgs, "input", ec.unmarshalNCreatePostInput2tailly_back_v2ᚋinternalᚋhttpᚋgraphᚐCreatePostInput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
args["title"] = arg0
|
args["input"] = arg0
|
||||||
arg1, err := processArgField(ctx, rawArgs, "content", ec.unmarshalNString2string)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
args["content"] = arg1
|
|
||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1899,6 +1936,17 @@ func (ec *executionContext) field_Query_comments_args(ctx context.Context, rawAr
|
|||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) field_Query_generateUploadURL_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
||||||
|
var err error
|
||||||
|
args := map[string]any{}
|
||||||
|
arg0, err := processArgField(ctx, rawArgs, "filename", ec.unmarshalNString2string)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
args["filename"] = arg0
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) field_Query_getChatMessages_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
func (ec *executionContext) field_Query_getChatMessages_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
||||||
var err error
|
var err error
|
||||||
args := map[string]any{}
|
args := map[string]any{}
|
||||||
@ -4519,7 +4567,7 @@ func (ec *executionContext) _Mutation_createPost(ctx context.Context, field grap
|
|||||||
}()
|
}()
|
||||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||||
ctx = rctx // use context from middleware stack in children
|
ctx = rctx // use context from middleware stack in children
|
||||||
return ec.resolvers.Mutation().CreatePost(rctx, fc.Args["title"].(string), fc.Args["content"].(string))
|
return ec.resolvers.Mutation().CreatePost(rctx, fc.Args["input"].(CreatePostInput))
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec.Error(ctx, err)
|
ec.Error(ctx, err)
|
||||||
@ -6541,6 +6589,69 @@ func (ec *executionContext) fieldContext_Query_postsPaginated(ctx context.Contex
|
|||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Query_generateUploadURL(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_Query_generateUploadURL(ctx, field)
|
||||||
|
if err != nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return ec.resolvers.Query().GenerateUploadURL(rctx, fc.Args["filename"].(string))
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*UploadURL)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNUploadURL2ᚖtailly_back_v2ᚋinternalᚋhttpᚋgraphᚐUploadURL(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_Query_generateUploadURL(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "Query",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: true,
|
||||||
|
IsResolver: true,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
switch field.Name {
|
||||||
|
case "url":
|
||||||
|
return ec.fieldContext_UploadURL_url(ctx, field)
|
||||||
|
case "key":
|
||||||
|
return ec.fieldContext_UploadURL_key(ctx, field)
|
||||||
|
case "expiresAt":
|
||||||
|
return ec.fieldContext_UploadURL_expiresAt(ctx, field)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("no field named %q was found under type UploadURL", field.Name)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err = ec.Recover(ctx, r)
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
if fc.Args, err = ec.field_Query_generateUploadURL_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return fc, err
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Query_getUserPosts(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Query_getUserPosts(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_Query_getUserPosts(ctx, field)
|
fc, err := ec.fieldContext_Query_getUserPosts(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -8521,6 +8632,138 @@ func (ec *executionContext) fieldContext_UnfollowResult_message(_ context.Contex
|
|||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _UploadURL_url(ctx context.Context, field graphql.CollectedField, obj *UploadURL) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_UploadURL_url(ctx, field)
|
||||||
|
if err != nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.URL, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(string)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_UploadURL_url(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "UploadURL",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type String does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _UploadURL_key(ctx context.Context, field graphql.CollectedField, obj *UploadURL) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_UploadURL_key(ctx, field)
|
||||||
|
if err != nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.Key, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(string)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_UploadURL_key(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "UploadURL",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type String does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _UploadURL_expiresAt(ctx context.Context, field graphql.CollectedField, obj *UploadURL) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_UploadURL_expiresAt(ctx, field)
|
||||||
|
if err != nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.ExpiresAt, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(string)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_UploadURL_expiresAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "UploadURL",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type String does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _User_id(ctx context.Context, field graphql.CollectedField, obj *domain.User) (ret graphql.Marshaler) {
|
func (ec *executionContext) _User_id(ctx context.Context, field graphql.CollectedField, obj *domain.User) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_User_id(ctx, field)
|
fc, err := ec.fieldContext_User_id(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -11105,6 +11348,40 @@ func (ec *executionContext) fieldContext___Type_isOneOf(_ context.Context, field
|
|||||||
|
|
||||||
// region **************************** input.gotpl *****************************
|
// region **************************** input.gotpl *****************************
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalInputCreatePostInput(ctx context.Context, obj any) (CreatePostInput, error) {
|
||||||
|
var it CreatePostInput
|
||||||
|
asMap := map[string]any{}
|
||||||
|
for k, v := range obj.(map[string]any) {
|
||||||
|
asMap[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldsInOrder := [...]string{"title", "s3TempKey"}
|
||||||
|
for _, k := range fieldsInOrder {
|
||||||
|
v, ok := asMap[k]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch k {
|
||||||
|
case "title":
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("title"))
|
||||||
|
data, err := ec.unmarshalNString2string(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.Title = data
|
||||||
|
case "s3TempKey":
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("s3TempKey"))
|
||||||
|
data, err := ec.unmarshalNString2string(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.S3TempKey = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return it, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalInputLoginInput(ctx context.Context, obj any) (domain.LoginInput, error) {
|
func (ec *executionContext) unmarshalInputLoginInput(ctx context.Context, obj any) (domain.LoginInput, error) {
|
||||||
var it domain.LoginInput
|
var it domain.LoginInput
|
||||||
asMap := map[string]any{}
|
asMap := map[string]any{}
|
||||||
@ -12796,6 +13073,28 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
|
|||||||
func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
|
func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) })
|
||||||
|
case "generateUploadURL":
|
||||||
|
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._Query_generateUploadURL(ctx, field)
|
||||||
|
if res == graphql.Null {
|
||||||
|
atomic.AddUint32(&fs.Invalids, 1)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
rrm := func(ctx context.Context) graphql.Marshaler {
|
||||||
|
return ec.OperationContext.RootResolverMiddleware(ctx,
|
||||||
|
func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
|
||||||
|
}
|
||||||
|
|
||||||
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) })
|
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) })
|
||||||
case "getUserPosts":
|
case "getUserPosts":
|
||||||
field := field
|
field := field
|
||||||
@ -13511,6 +13810,55 @@ func (ec *executionContext) _UnfollowResult(ctx context.Context, sel ast.Selecti
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var uploadURLImplementors = []string{"UploadURL"}
|
||||||
|
|
||||||
|
func (ec *executionContext) _UploadURL(ctx context.Context, sel ast.SelectionSet, obj *UploadURL) graphql.Marshaler {
|
||||||
|
fields := graphql.CollectFields(ec.OperationContext, sel, uploadURLImplementors)
|
||||||
|
|
||||||
|
out := graphql.NewFieldSet(fields)
|
||||||
|
deferred := make(map[string]*graphql.FieldSet)
|
||||||
|
for i, field := range fields {
|
||||||
|
switch field.Name {
|
||||||
|
case "__typename":
|
||||||
|
out.Values[i] = graphql.MarshalString("UploadURL")
|
||||||
|
case "url":
|
||||||
|
out.Values[i] = ec._UploadURL_url(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
out.Invalids++
|
||||||
|
}
|
||||||
|
case "key":
|
||||||
|
out.Values[i] = ec._UploadURL_key(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
out.Invalids++
|
||||||
|
}
|
||||||
|
case "expiresAt":
|
||||||
|
out.Values[i] = ec._UploadURL_expiresAt(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
out.Invalids++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.Dispatch(ctx)
|
||||||
|
if out.Invalids > 0 {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
|
||||||
|
|
||||||
|
for label, dfs := range deferred {
|
||||||
|
ec.processDeferredGroup(graphql.DeferredGroup{
|
||||||
|
Label: label,
|
||||||
|
Path: graphql.GetPath(ctx),
|
||||||
|
FieldSet: dfs,
|
||||||
|
Context: ctx,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
var userImplementors = []string{"User"}
|
var userImplementors = []string{"User"}
|
||||||
|
|
||||||
func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj *domain.User) graphql.Marshaler {
|
func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj *domain.User) graphql.Marshaler {
|
||||||
@ -14353,6 +14701,11 @@ func (ec *executionContext) marshalNComment2ᚖtailly_back_v2ᚋinternalᚋdomai
|
|||||||
return ec._Comment(ctx, sel, v)
|
return ec._Comment(ctx, sel, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalNCreatePostInput2tailly_back_v2ᚋinternalᚋhttpᚋgraphᚐCreatePostInput(ctx context.Context, v any) (CreatePostInput, error) {
|
||||||
|
res, err := ec.unmarshalInputCreatePostInput(ctx, v)
|
||||||
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) marshalNDevice2tailly_back_v2ᚋinternalᚋdomainᚐDevice(ctx context.Context, sel ast.SelectionSet, v domain.Device) graphql.Marshaler {
|
func (ec *executionContext) marshalNDevice2tailly_back_v2ᚋinternalᚋdomainᚐDevice(ctx context.Context, sel ast.SelectionSet, v domain.Device) graphql.Marshaler {
|
||||||
return ec._Device(ctx, sel, &v)
|
return ec._Device(ctx, sel, &v)
|
||||||
}
|
}
|
||||||
@ -14907,6 +15260,20 @@ func (ec *executionContext) marshalNUnfollowResult2ᚖtailly_back_v2ᚋinternal
|
|||||||
return ec._UnfollowResult(ctx, sel, v)
|
return ec._UnfollowResult(ctx, sel, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalNUploadURL2tailly_back_v2ᚋinternalᚋhttpᚋgraphᚐUploadURL(ctx context.Context, sel ast.SelectionSet, v UploadURL) graphql.Marshaler {
|
||||||
|
return ec._UploadURL(ctx, sel, &v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalNUploadURL2ᚖtailly_back_v2ᚋinternalᚋhttpᚋgraphᚐUploadURL(ctx context.Context, sel ast.SelectionSet, v *UploadURL) graphql.Marshaler {
|
||||||
|
if v == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||||
|
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
return ec._UploadURL(ctx, sel, v)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) marshalNUser2tailly_back_v2ᚋinternalᚋdomainᚐUser(ctx context.Context, sel ast.SelectionSet, v domain.User) graphql.Marshaler {
|
func (ec *executionContext) marshalNUser2tailly_back_v2ᚋinternalᚋdomainᚐUser(ctx context.Context, sel ast.SelectionSet, v domain.User) graphql.Marshaler {
|
||||||
return ec._User(ctx, sel, &v)
|
return ec._User(ctx, sel, &v)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,11 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type CreatePostInput struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
S3TempKey string `json:"s3TempKey"`
|
||||||
|
}
|
||||||
|
|
||||||
type FollowResult struct {
|
type FollowResult struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
@ -73,6 +78,12 @@ type UnfollowResult struct {
|
|||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UploadURL struct {
|
||||||
|
URL string `json:"url"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
ExpiresAt string `json:"expiresAt"`
|
||||||
|
}
|
||||||
|
|
||||||
type MessageStatus string
|
type MessageStatus string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"tailly_back_v2/internal/domain"
|
"tailly_back_v2/internal/domain"
|
||||||
|
"tailly_back_v2/pkg/S3"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -124,19 +125,38 @@ func (r *mutationResolver) UnlikePost(ctx context.Context, postID int) (bool, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreatePost is the resolver for the createPost field.
|
// CreatePost is the resolver for the createPost field.
|
||||||
func (r *mutationResolver) CreatePost(ctx context.Context, title string, content string) (*domain.Post, error) {
|
func (r *mutationResolver) CreatePost(ctx context.Context, input CreatePostInput) (*domain.Post, error) {
|
||||||
userID, err := getUserIDFromContext(ctx)
|
userID, err := getUserIDFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unauthorized: %w", err)
|
return nil, fmt.Errorf("unauthorized: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
post, err := r.Services.Post.Create(ctx, userID, title, content)
|
post, err := r.Services.Post.CreateWithS3Upload(ctx, userID, input.Title, input.S3TempKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create post: %w", err)
|
return nil, fmt.Errorf("failed to create post: %w", err)
|
||||||
}
|
}
|
||||||
return post, nil
|
return post, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateUploadURL is the resolver for the generateUploadURL field.
|
||||||
|
func (r *queryResolver) GenerateUploadURL(ctx context.Context, filename string) (*UploadURL, error) {
|
||||||
|
userID, err := getUserIDFromContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unauthorized: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
url, key, err := S3.GeneratePresignedUploadURL(userID, filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to generate upload URL: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &UploadURL{
|
||||||
|
URL: url,
|
||||||
|
Key: key,
|
||||||
|
ExpiresAt: time.Now().Add(15 * time.Minute).Format(time.RFC3339),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// DeletePost is the resolver for the deletePost field.
|
// DeletePost is the resolver for the deletePost field.
|
||||||
func (r *mutationResolver) DeletePost(ctx context.Context, id int) (bool, error) {
|
func (r *mutationResolver) DeletePost(ctx context.Context, id int) (bool, error) {
|
||||||
userID, err := getUserIDFromContext(ctx)
|
userID, err := getUserIDFromContext(ctx)
|
||||||
|
|||||||
@ -170,12 +170,26 @@ type MarkNotificationReadResult {
|
|||||||
message: String!
|
message: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scalar Upload
|
||||||
|
|
||||||
|
input CreatePostInput {
|
||||||
|
title: String!
|
||||||
|
s3TempKey: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
type UploadURL {
|
||||||
|
url: String!
|
||||||
|
key: String!
|
||||||
|
expiresAt: String!
|
||||||
|
}
|
||||||
|
|
||||||
# Запросы (получение данных)
|
# Запросы (получение данных)
|
||||||
type Query {
|
type Query {
|
||||||
me: User! # Получить текущего пользователя
|
me: User! # Получить текущего пользователя
|
||||||
post(id: Int!): Post! # Получить пост по ID
|
post(id: Int!): Post! # Получить пост по ID
|
||||||
posts: [Post!]! # Получить все посты
|
posts: [Post!]! # Получить все посты
|
||||||
postsPaginated(limit: Int!, offset: Int!): [Post!]!
|
postsPaginated(limit: Int!, offset: Int!): [Post!]!
|
||||||
|
generateUploadURL(filename: String!): UploadURL!
|
||||||
getUserPosts(userId: Int!): [Post!]!
|
getUserPosts(userId: Int!): [Post!]!
|
||||||
user(id: Int!): User! # Получить пользователя по ID
|
user(id: Int!): User! # Получить пользователя по ID
|
||||||
users: [User!]!
|
users: [User!]!
|
||||||
@ -186,19 +200,14 @@ type Query {
|
|||||||
comments(postID: Int!): [Comment!]!
|
comments(postID: Int!): [Comment!]!
|
||||||
# Получить количество подписчиков
|
# Получить количество подписчиков
|
||||||
getFollowersCount(userId: Int!): Int!
|
getFollowersCount(userId: Int!): Int!
|
||||||
|
|
||||||
# Получить количество подписок
|
# Получить количество подписок
|
||||||
getFollowingCount(userId: Int!): Int!
|
getFollowingCount(userId: Int!): Int!
|
||||||
|
|
||||||
# Проверить подписку
|
# Проверить подписку
|
||||||
isFollowing(followingId: Int!): Boolean!
|
isFollowing(followingId: Int!): Boolean!
|
||||||
|
|
||||||
# Получить список подписчиков
|
# Получить список подписчиков
|
||||||
getFollowers(userId: Int!, limit: Int = 20, offset: Int = 0): FollowersResponse!
|
getFollowers(userId: Int!, limit: Int = 20, offset: Int = 0): FollowersResponse!
|
||||||
|
|
||||||
# Получить список подписок
|
# Получить список подписок
|
||||||
getFollowing(userId: Int!, limit: Int = 20, offset: Int = 0): FollowingResponse!
|
getFollowing(userId: Int!, limit: Int = 20, offset: Int = 0): FollowingResponse!
|
||||||
|
|
||||||
# Получить уведомления о подписках
|
# Получить уведомления о подписках
|
||||||
getSubscriptionNotifications(
|
getSubscriptionNotifications(
|
||||||
unreadOnly: Boolean = false
|
unreadOnly: Boolean = false
|
||||||
@ -219,8 +228,7 @@ type Mutation {
|
|||||||
refreshTokens(refreshToken: String!): Tokens!
|
refreshTokens(refreshToken: String!): Tokens!
|
||||||
|
|
||||||
# Создание поста
|
# Создание поста
|
||||||
createPost(title: String!, content: String!): Post!
|
createPost(input: CreatePostInput!): Post!
|
||||||
|
|
||||||
# Создание комментария
|
# Создание комментария
|
||||||
createComment(postId: Int!, content: String!): Comment!
|
createComment(postId: Int!, content: String!): Comment!
|
||||||
|
|
||||||
|
|||||||
@ -32,6 +32,7 @@ type PostService interface {
|
|||||||
Update(ctx context.Context, id int, title, content string) (*domain.Post, error)
|
Update(ctx context.Context, id int, title, content string) (*domain.Post, error)
|
||||||
Delete(ctx context.Context, id int) error
|
Delete(ctx context.Context, id int) error
|
||||||
GetPaginated(ctx context.Context, limit, offset int) ([]*domain.Post, error)
|
GetPaginated(ctx context.Context, limit, offset int) ([]*domain.Post, error)
|
||||||
|
CreateWithS3Upload(ctx context.Context, authorID int, title, s3TempKey string) (*domain.Post, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Реализация сервиса постов
|
// Реализация сервиса постов
|
||||||
@ -44,6 +45,80 @@ func NewPostService(postRepo repository.PostRepository) PostService {
|
|||||||
return &postService{postRepo: postRepo}
|
return &postService{postRepo: postRepo}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *postService) CreateWithS3Upload(ctx context.Context, authorID int, title, s3TempKey string) (*domain.Post, error) {
|
||||||
|
const op = "service/postService.CreateWithS3Upload"
|
||||||
|
|
||||||
|
// Валидация
|
||||||
|
if s3TempKey == "" {
|
||||||
|
return nil, errors.New("S3 temp key cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем что ключ принадлежит пользователю (дополнительная валидация)
|
||||||
|
if !isValidUserTempKey(authorID, s3TempKey) {
|
||||||
|
return nil, errors.New("invalid temp key for user")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Генерируем временный URL для модерации
|
||||||
|
tempURL := fmt.Sprintf("https://s3.regru.cloud/tailly/%s", s3TempKey)
|
||||||
|
|
||||||
|
// Модерация изображения по URL
|
||||||
|
modClient, err := moderation.NewModerationClient("tailly_censor:50051")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s: failed to create moderation client: %w", op, err)
|
||||||
|
}
|
||||||
|
defer modClient.Close()
|
||||||
|
|
||||||
|
allowed, err := modClient.CheckImageURL(ctx, tempURL)
|
||||||
|
if err != nil {
|
||||||
|
// Удаляем временный файл при ошибке модерации
|
||||||
|
S3.DeleteTempFile(s3TempKey)
|
||||||
|
return nil, fmt.Errorf("%s: image moderation failed: %w", op, err)
|
||||||
|
}
|
||||||
|
if !allowed {
|
||||||
|
// Удаляем временный файл если не прошло модерацию
|
||||||
|
S3.DeleteTempFile(s3TempKey)
|
||||||
|
return nil, errors.New("image rejected by moderation service")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Перемещаем файл из временной папки в постоянную
|
||||||
|
permanentKey := fmt.Sprintf("posts/%d/%d_%s", authorID, time.Now().UnixNano(), getFilenameFromKey(s3TempKey))
|
||||||
|
|
||||||
|
err = S3.MoveFile(s3TempKey, permanentKey)
|
||||||
|
if err != nil {
|
||||||
|
S3.DeleteTempFile(s3TempKey) // Удаляем временный файл при ошибке
|
||||||
|
return nil, fmt.Errorf("%s: failed to move file to permanent location: %w", op, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
imageURL := fmt.Sprintf("https://s3.regru.cloud/tailly/%s", permanentKey)
|
||||||
|
|
||||||
|
post := &domain.Post{
|
||||||
|
Title: title,
|
||||||
|
Content: imageURL,
|
||||||
|
AuthorID: authorID,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
UpdatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.postRepo.Create(ctx, post); err != nil {
|
||||||
|
// Если не удалось сохранить пост, удаляем файл из S3
|
||||||
|
S3.DeleteTempFile(permanentKey)
|
||||||
|
return nil, fmt.Errorf("%s: failed to save post: %w", op, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return post, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidUserTempKey(userID int, key string) bool {
|
||||||
|
// Проверяем что ключ принадлежит пользователю
|
||||||
|
// Формат: temp/{userID}/{timestamp}_{filename}
|
||||||
|
return strings.Contains(key, fmt.Sprintf("temp/%d/", userID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFilenameFromKey(key string) string {
|
||||||
|
parts := strings.Split(key, "/")
|
||||||
|
return parts[len(parts)-1]
|
||||||
|
}
|
||||||
|
|
||||||
// Создание нового поста
|
// Создание нового поста
|
||||||
func (s *postService) Create(ctx context.Context, authorID int, title, content string) (*domain.Post, error) {
|
func (s *postService) Create(ctx context.Context, authorID int, title, content string) (*domain.Post, error) {
|
||||||
const op = "service/postService.Create"
|
const op = "service/postService.Create"
|
||||||
|
|||||||
91
pkg/S3/s3.go
91
pkg/S3/s3.go
@ -2,11 +2,13 @@ package S3
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
"github.com/aws/aws-sdk-go/aws/session"
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
"github.com/aws/aws-sdk-go/service/s3"
|
"github.com/aws/aws-sdk-go/service/s3"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func DeleteFromS3(imageURL string) error {
|
func DeleteFromS3(imageURL string) error {
|
||||||
@ -50,3 +52,90 @@ func DeleteFromS3(imageURL string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
func GeneratePresignedUploadURL(userID int, filename string) (string, string, error) {
|
||||||
|
const op = "s3.GeneratePresignedUploadURL"
|
||||||
|
|
||||||
|
sess := session.Must(session.NewSession(&aws.Config{
|
||||||
|
Region: aws.String("ru-central1"),
|
||||||
|
Endpoint: aws.String("https://s3.regru.cloud"),
|
||||||
|
Credentials: credentials.NewStaticCredentials(
|
||||||
|
"TJ946G2S1Z5FEI3I7DQQ",
|
||||||
|
"C2H2aITHRDpek8H921yhnrINZwDoADsjW3F6HURl",
|
||||||
|
"",
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
|
||||||
|
svc := s3.New(sess)
|
||||||
|
|
||||||
|
// Генерируем уникальный ключ с userID для безопасности
|
||||||
|
uniqueKey := fmt.Sprintf("temp/%d/%d_%s", userID, time.Now().UnixNano(), filename)
|
||||||
|
|
||||||
|
req, _ := svc.PutObjectRequest(&s3.PutObjectInput{
|
||||||
|
Bucket: aws.String("tailly"),
|
||||||
|
Key: aws.String(uniqueKey),
|
||||||
|
ContentLength: aws.Int64(10 * 1024 * 1024), // Макс 10MB
|
||||||
|
})
|
||||||
|
|
||||||
|
// URL действителен 15 минут
|
||||||
|
url, err := req.Presign(15 * time.Minute)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", fmt.Errorf("%s: failed to generate presigned URL: %w", op, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return url, uniqueKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func MoveFile(sourceKey, destinationKey string) error {
|
||||||
|
const op = "s3.MoveFile"
|
||||||
|
|
||||||
|
sess := session.Must(session.NewSession(&aws.Config{
|
||||||
|
Region: aws.String("ru-central1"),
|
||||||
|
Endpoint: aws.String("https://s3.regru.cloud"),
|
||||||
|
Credentials: credentials.NewStaticCredentials(
|
||||||
|
"TJ946G2S1Z5FEI3I7DQQ",
|
||||||
|
"C2H2aITHRDpek8H921yhnrINZwDoADsjW3F6HURl",
|
||||||
|
"",
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
|
||||||
|
svc := s3.New(sess)
|
||||||
|
|
||||||
|
// Копируем файл
|
||||||
|
_, err := svc.CopyObject(&s3.CopyObjectInput{
|
||||||
|
Bucket: aws.String("tailly"),
|
||||||
|
CopySource: aws.String(fmt.Sprintf("tailly/%s", sourceKey)),
|
||||||
|
Key: aws.String(destinationKey),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%s: failed to copy file: %w", op, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Удаляем исходный файл
|
||||||
|
return DeleteTempFile(sourceKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteTempFile(key string) error {
|
||||||
|
const op = "s3.DeleteTempFile"
|
||||||
|
|
||||||
|
sess := session.Must(session.NewSession(&aws.Config{
|
||||||
|
Region: aws.String("ru-central1"),
|
||||||
|
Endpoint: aws.String("https://s3.regru.cloud"),
|
||||||
|
Credentials: credentials.NewStaticCredentials(
|
||||||
|
"TJ946G2S1Z5FEI3I7DQQ",
|
||||||
|
"C2H2aITHRDpek8H921yhnrINZwDoADsjW3F6HURl",
|
||||||
|
"",
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
|
||||||
|
svc := s3.New(sess)
|
||||||
|
|
||||||
|
_, err := svc.DeleteObject(&s3.DeleteObjectInput{
|
||||||
|
Bucket: aws.String("tailly"),
|
||||||
|
Key: aws.String(key),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%s: failed to delete temp file: %w", op, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@ -3,8 +3,9 @@ package moderation
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
pb "tailly_back_v2/pkg/moderation/proto"
|
pb "tailly_back_v2/pkg/moderation/proto"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ModerationClient struct {
|
type ModerationClient struct {
|
||||||
@ -35,6 +36,16 @@ func (c *ModerationClient) CheckImage(ctx context.Context, imageData []byte) (bo
|
|||||||
return resp.OverallDecision == "allowed", nil
|
return resp.OverallDecision == "allowed", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ModerationClient) CheckImageURL(ctx context.Context, imageURL string) (bool, error) {
|
||||||
|
resp, err := c.client.CheckImage(ctx, &pb.ImageRequest{
|
||||||
|
ImageUrl: imageURL, // ← Передаем URL вместо данных!
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return resp.OverallDecision == "allowed", nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ModerationClient) Close() {
|
func (c *ModerationClient) Close() {
|
||||||
c.conn.Close()
|
c.conn.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user