summaryrefslogtreecommitdiff
path: root/utils/storage/minio.go
blob: 0d6e36431c46988eceab3c748d01967eba1d7ae7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package storage

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"lain/config"
	"path/filepath"
	"time"

	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
)

var minioClient *minio.Client

func InitMinIO() error {
	client, err := minio.New(config.MinIO.Endpoint, &minio.Options{
		Creds:  credentials.NewStaticV4(config.MinIO.AccessKey, config.MinIO.SecretKey, ""),
		Secure: config.MinIO.UseSSL,
	})
	if err != nil {
		return fmt.Errorf("failed to create minio client: %w", err)
	}

	ctx := context.Background()
	exists, err := client.BucketExists(ctx, config.MinIO.BucketName)
	if err != nil {
		return fmt.Errorf("failed to check bucket existence: %w", err)
	}

	if !exists {
		err = client.MakeBucket(ctx, config.MinIO.BucketName, minio.MakeBucketOptions{})
		if err != nil {
			return fmt.Errorf("failed to create bucket: %w", err)
		}
	}

	minioClient = client
	return nil
}

func UploadAttachment(userEmail string, emailID uint, filename string, data []byte, contentType string) (string, error) {
	if minioClient == nil {
		return "", fmt.Errorf("minio client not initialized")
	}

	path := fmt.Sprintf("attachments/%s/%d/%s", userEmail, emailID, filename)

	ctx := context.Background()

	_, err := minioClient.PutObject(
		ctx,
		config.MinIO.BucketName,
		path,
		bytes.NewReader(data),
		int64(len(data)),
		minio.PutObjectOptions{
			ContentType: contentType,
		},
	)

	if err != nil {
		return "", fmt.Errorf("failed to upload attachment: %w", err)
	}

	return path, nil
}

func DownloadAttachment(path string) ([]byte, error) {
	if minioClient == nil {
		return nil, fmt.Errorf("minio client not initialized")
	}

	ctx := context.Background()

	object, err := minioClient.GetObject(ctx, config.MinIO.BucketName, path, minio.GetObjectOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to get attachment object: %w", err)
	}
	defer object.Close()

	data, err := io.ReadAll(object)
	if err != nil {
		return nil, fmt.Errorf("failed to read attachment data: %w", err)
	}

	return data, nil
}

func DeleteAttachment(path string) error {
	if minioClient == nil {
		return fmt.Errorf("minio client not initialized")
	}

	ctx := context.Background()

	err := minioClient.RemoveObject(ctx, config.MinIO.BucketName, path, minio.RemoveObjectOptions{})
	if err != nil {
		return fmt.Errorf("failed to delete attachment: %w", err)
	}

	return nil
}

func DeleteAttachmentsByEmail(userEmail string, emailID uint) error {
	if minioClient == nil {
		return fmt.Errorf("minio client not initialized")
	}

	ctx := context.Background()
	prefix := fmt.Sprintf("attachments/%s/%d/", userEmail, emailID)

	objectCh := minioClient.ListObjects(ctx, config.MinIO.BucketName, minio.ListObjectsOptions{
		Prefix:    prefix,
		Recursive: true,
	})

	for object := range objectCh {
		if object.Err != nil {
			return fmt.Errorf("failed to list attachments: %w", object.Err)
		}

		err := minioClient.RemoveObject(ctx, config.MinIO.BucketName, object.Key, minio.RemoveObjectOptions{})
		if err != nil {
			return fmt.Errorf("failed to delete attachment %s: %w", object.Key, err)
		}
	}

	return nil
}

func GetAttachmentURL(path string, expiryDuration time.Duration) (string, error) {
	if minioClient == nil {
		return "", fmt.Errorf("minio client not initialized")
	}

	ctx := context.Background()

	url, err := minioClient.PresignedGetObject(ctx, config.MinIO.BucketName, path, expiryDuration, nil)
	if err != nil {
		return "", fmt.Errorf("failed to generate presigned url: %w", err)
	}

	return url.String(), nil
}

func GetAttachmentFilename(path string) string {
	return filepath.Base(path)
}

func AttachmentExists(path string) (bool, error) {
	if minioClient == nil {
		return false, fmt.Errorf("minio client not initialized")
	}

	ctx := context.Background()

	_, err := minioClient.StatObject(ctx, config.MinIO.BucketName, path, minio.StatObjectOptions{})
	if err != nil {
		errResponse := minio.ToErrorResponse(err)
		if errResponse.Code == "NoSuchKey" {
			return false, nil
		}
		return false, fmt.Errorf("failed to check attachment existence: %w", err)
	}

	return true, nil
}