This commit is contained in:
parent
d71d79dfcc
commit
8e247cdb0d
@ -45,21 +45,21 @@ 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) {
|
func (s *postService) CreateWithS3Upload(ctx context.Context, authorID int, title, s3Key string) (*domain.Post, error) {
|
||||||
const op = "service/postService.CreateWithS3Upload"
|
const op = "service/postService.CreateWithS3Upload"
|
||||||
|
|
||||||
// Валидация
|
// Валидация
|
||||||
if s3TempKey == "" {
|
if s3Key == "" {
|
||||||
return nil, errors.New("S3 temp key cannot be empty")
|
return nil, errors.New("S3 key cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Проверяем что ключ принадлежит пользователю (дополнительная валидация)
|
// Проверяем что ключ принадлежит пользователю и находится в правильной папке
|
||||||
if !isValidUserTempKey(authorID, s3TempKey) {
|
if !isValidUserPostKey(authorID, s3Key) {
|
||||||
return nil, errors.New("invalid temp key for user")
|
return nil, errors.New("invalid S3 key for user")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Генерируем временный URL для модерации
|
// Формируем URL для модерации
|
||||||
tempURL := fmt.Sprintf("https://s3.regru.cloud/tailly/%s", s3TempKey)
|
imageURL := fmt.Sprintf("https://s3.regru.cloud/tailly/%s", s3Key)
|
||||||
|
|
||||||
// Модерация изображения по URL
|
// Модерация изображения по URL
|
||||||
modClient, err := moderation.NewModerationClient("tailly_censor:50051")
|
modClient, err := moderation.NewModerationClient("tailly_censor:50051")
|
||||||
@ -68,29 +68,19 @@ func (s *postService) CreateWithS3Upload(ctx context.Context, authorID int, titl
|
|||||||
}
|
}
|
||||||
defer modClient.Close()
|
defer modClient.Close()
|
||||||
|
|
||||||
allowed, err := modClient.CheckImageURL(ctx, tempURL)
|
allowed, err := modClient.CheckImageURL(ctx, imageURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Удаляем временный файл при ошибке модерации
|
// Удаляем файл при ошибке модерации
|
||||||
S3.DeleteTempFile(s3TempKey)
|
S3.DeleteFromS3(imageURL)
|
||||||
return nil, fmt.Errorf("%s: image moderation failed: %w", op, err)
|
return nil, fmt.Errorf("%s: image moderation failed: %w", op, err)
|
||||||
}
|
}
|
||||||
if !allowed {
|
if !allowed {
|
||||||
// Удаляем временный файл если не прошло модерацию
|
// Удаляем файл если не прошло модерацию
|
||||||
S3.DeleteTempFile(s3TempKey)
|
S3.DeleteFromS3(imageURL)
|
||||||
return nil, errors.New("image rejected by moderation service")
|
return nil, errors.New("image rejected by moderation service")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Перемещаем файл из временной папки в постоянную
|
// Создаем пост с уже готовым URL
|
||||||
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{
|
post := &domain.Post{
|
||||||
Title: title,
|
Title: title,
|
||||||
Content: imageURL,
|
Content: imageURL,
|
||||||
@ -101,22 +91,18 @@ func (s *postService) CreateWithS3Upload(ctx context.Context, authorID int, titl
|
|||||||
|
|
||||||
if err := s.postRepo.Create(ctx, post); err != nil {
|
if err := s.postRepo.Create(ctx, post); err != nil {
|
||||||
// Если не удалось сохранить пост, удаляем файл из S3
|
// Если не удалось сохранить пост, удаляем файл из S3
|
||||||
S3.DeleteTempFile(permanentKey)
|
S3.DeleteFromS3(imageURL)
|
||||||
return nil, fmt.Errorf("%s: failed to save post: %w", op, err)
|
return nil, fmt.Errorf("%s: failed to save post: %w", op, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return post, nil
|
return post, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isValidUserTempKey(userID int, key string) bool {
|
// Новая функция проверки ключа
|
||||||
// Проверяем что ключ принадлежит пользователю
|
func isValidUserPostKey(userID int, key string) bool {
|
||||||
// Формат: temp/{userID}/{timestamp}_{filename}
|
// Проверяем что ключ принадлежит пользователю и находится в папке posts
|
||||||
return strings.Contains(key, fmt.Sprintf("temp/%d/", userID))
|
// Формат: posts/{userID}/{timestamp}_{filename}
|
||||||
}
|
return strings.HasPrefix(key, fmt.Sprintf("posts/%d/", userID))
|
||||||
|
|
||||||
func getFilenameFromKey(key string) string {
|
|
||||||
parts := strings.Split(key, "/")
|
|
||||||
return parts[len(parts)-1]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Создание нового поста
|
// Создание нового поста
|
||||||
|
|||||||
44
pkg/S3/s3.go
44
pkg/S3/s3.go
@ -87,7 +87,8 @@ func GeneratePresignedUploadURL(userID int, filename string) (string, string, er
|
|||||||
return "", "", fmt.Errorf("%s: failed to create S3 client: %w", op, err)
|
return "", "", fmt.Errorf("%s: failed to create S3 client: %w", op, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
uniqueKey := fmt.Sprintf("temp/%d/%d_%s", userID, time.Now().UnixNano(), filename)
|
// Генерируем ключ сразу в конечной папке с уникальным именем
|
||||||
|
uniqueKey := fmt.Sprintf("posts/%d/%d_%s", userID, time.Now().UnixNano(), filename)
|
||||||
|
|
||||||
presignClient := s3.NewPresignClient(client)
|
presignClient := s3.NewPresignClient(client)
|
||||||
|
|
||||||
@ -105,44 +106,3 @@ func GeneratePresignedUploadURL(userID int, filename string) (string, string, er
|
|||||||
|
|
||||||
return result.URL, uniqueKey, nil
|
return result.URL, uniqueKey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func MoveFile(sourceKey, destinationKey string) error {
|
|
||||||
const op = "s3.MoveFile"
|
|
||||||
|
|
||||||
client, err := getS3Client()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("%s: failed to create S3 client: %w", op, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Копируем файл
|
|
||||||
_, err = client.CopyObject(context.TODO(), &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"
|
|
||||||
|
|
||||||
client, err := getS3Client()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("%s: failed to create S3 client: %w", op, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = client.DeleteObject(context.TODO(), &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
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user