2023-07-04 16:47:03 -04:00
package media
import (
2023-07-04 20:33:27 -04:00
"context"
2023-07-04 18:41:27 -04:00
"errors"
2023-12-18 17:40:37 -05:00
"fmt"
"mime"
"mime/multipart"
"net/http"
2023-07-04 18:41:27 -04:00
2023-07-04 16:47:03 -04:00
"git.agecem.com/agecem/agecem-org/config"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
"github.com/spf13/viper"
)
func NewMediaClient ( endpoint , accessKeyId , secretAccessKey string , useSSL bool ) ( * MediaClient , error ) {
2023-07-04 18:41:27 -04:00
if accessKeyId == "" {
return nil , errors . New ( "accessKeyId was found empty, but cannot be" )
}
if secretAccessKey == "" {
return nil , errors . New ( "secretAccessKey was found empty, but cannot be" )
}
2023-07-04 16:47:03 -04:00
var mediaClient MediaClient
minioClient , err := minio . New ( endpoint , & minio . Options {
Creds : credentials . NewStaticV4 ( accessKeyId , secretAccessKey , "" ) ,
Secure : useSSL ,
} )
if err != nil {
return & mediaClient , err
}
mediaClient . MinioClient = * minioClient
return & mediaClient , nil
}
func NewMediaClientFromViper ( ) ( * MediaClient , error ) {
var cfg config . Config
if err := viper . Unmarshal ( & cfg ) ; err != nil {
return nil , err
}
mediaClient , err := NewMediaClient ( cfg . Server . Documents . Endpoint , cfg . Server . Documents . AccessKeyId , cfg . Server . Documents . SecretAccessKey , cfg . Server . Documents . UseSSL )
if err != nil {
return mediaClient , err
}
return mediaClient , nil
}
type MediaClient struct {
MinioClient minio . Client
}
2023-07-04 20:33:27 -04:00
func ( m * MediaClient ) Seed ( ) ( [ ] string , error ) {
var cfg config . Config
if err := viper . Unmarshal ( & cfg ) ; err != nil {
return nil , err
}
var new_buckets [ ] string
2023-08-15 15:51:42 -04:00
for bucket := range cfg . Server . Documents . Buckets {
2023-07-04 20:33:27 -04:00
exists , err := m . MinioClient . BucketExists ( context . Background ( ) , bucket )
if err != nil {
return new_buckets , err
}
if exists {
continue
}
if err = m . MinioClient . MakeBucket ( context . Background ( ) , bucket , minio . MakeBucketOptions { } ) ; err != nil {
return new_buckets , err
}
new_buckets = append ( new_buckets , bucket )
}
return new_buckets , nil
2023-07-04 16:47:03 -04:00
}
2023-12-18 17:40:37 -05:00
2023-12-19 19:38:35 -05:00
func ( m * MediaClient ) UploadFormFiles ( bucketName string , fileHeaders [ ] * multipart . FileHeader ) ( statusCode int , result string ) {
ctx , cancel := context . WithCancel ( context . Background ( ) )
defer cancel ( )
ok , err := m . MinioClient . BucketExists ( ctx , bucketName )
if err != nil {
return http . StatusInternalServerError , fmt . Sprintf ( "Erreur lors de vérification d'existence de bucket '%s': %s" , bucketName , err )
}
if ! ok {
return http . StatusBadRequest , fmt . Sprintf ( "Bucket '%s' n'existe pas" , bucketName )
}
2023-12-18 17:40:37 -05:00
switch count := len ( fileHeaders ) ; count {
case 0 :
return http . StatusBadRequest , "Veuillez sélectionner au moins 1 document à téléverser"
case 1 :
result = "Téléversement de 1 fichier\n"
default :
result = fmt . Sprintf ( "Téléversement de %d fichiers\n" , count )
}
var allowedMediaTypes = [ ] string { "application/pdf" , "text/markdown" , "text/plain" }
var fileNames [ ] string
for _ , fileHeader := range fileHeaders {
fileNames = append ( fileNames , fileHeader . Filename )
}
2023-12-19 19:38:35 -05:00
var validFileHeaders [ ] * multipart . FileHeader
2023-12-18 17:40:37 -05:00
for i , fileHeader := range fileHeaders {
// Check for conflicting file names in upload
for j , fileName := range fileNames {
if fileName == fileHeader . Filename && i != j {
return http . StatusBadRequest , fmt . Sprintf ( "Doublon de nom de fichier '%s' trouvé, les noms de fichiers doivent être uniques" , fileName )
}
}
// Check media type
mediaType , _ , err := mime . ParseMediaType ( fileHeader . Header . Get ( "Content-Type" ) )
if err != nil {
return http . StatusBadRequest , fmt . Sprintf ( "Impossible de déterminer le type de fichier pour %d '%s'.\nPlus de détails: %s" , i , fileHeader . Filename , err . Error ( ) )
}
var isAllowedMediaType bool
for _ , allowedMediaType := range allowedMediaTypes {
if allowedMediaType == mediaType {
isAllowedMediaType = true
}
}
if ! isAllowedMediaType {
2023-12-19 19:38:35 -05:00
return http . StatusUnsupportedMediaType , fmt . Sprintf ( "Type de fichier interdit '%s' pour '%s'.\nTypes de fichiers permis: %s" , mediaType , fileHeader . Filename , allowedMediaTypes )
2023-12-18 17:40:37 -05:00
}
2023-12-19 19:38:35 -05:00
// Check for conflicting fileNames with existing files
objectInfo , err := m . MinioClient . StatObject ( ctx , bucketName , fileHeader . Filename , minio . StatObjectOptions { } )
if err == nil && objectInfo . Key == fileHeader . Filename {
return http . StatusConflict , fmt . Sprintf ( "Un document au nom '%s' de catégorie '%s' existe déjà et ne peut pas être inséré de cette façon." , fileHeader . Filename , bucketName )
}
switch msg := err . Error ( ) ; msg {
case "The specified key does not exist." :
default :
return http . StatusInternalServerError , fmt . Sprintf ( "Erreur inattendue lors de vérification de conflit de nom de fichier avec la base de données: %s" , err )
}
validFileHeaders = append ( validFileHeaders , fileHeader )
}
if len ( validFileHeaders ) == 0 {
return http . StatusOK , "Aucun fichier valide envoyé au serveur, rien à faire."
}
for i , fileHeader := range validFileHeaders {
mediaType , _ , err := mime . ParseMediaType ( fileHeader . Header . Get ( "Content-Type" ) )
if err != nil {
return http . StatusBadRequest , fmt . Sprintf ( "Impossible de déterminer le type de fichier pour %d '%s'.\nPlus de détails: %s" , i , fileHeader . Filename , err . Error ( ) )
}
// Get file content
fileContent , err := fileHeader . Open ( )
if err != nil {
return http . StatusBadRequest , fmt . Sprintf ( "Impossible de lire le contenu de '%s': %s" , fileHeader . Filename , err )
}
defer fileContent . Close ( )
// Upload file
info , err := m . MinioClient . PutObject ( ctx , bucketName , fileHeader . Filename , fileContent , fileHeader . Size , minio . PutObjectOptions {
ContentType : mediaType ,
} )
if err != nil {
return http . StatusInternalServerError , fmt . Sprintf ( "Impossible d'ajouter '%s' à la base de donnée: %s" , fileHeader . Filename , err )
}
2023-12-18 17:40:37 -05:00
2023-12-19 19:38:35 -05:00
result = fmt . Sprintf ( "%sDocument %d '%s' de type '%s' et de taille '%d' téléversé à '%s' avec succès\n" ,
result , i , info . Key , mediaType , info . Size , info . Bucket )
2023-12-18 17:40:37 -05:00
}
return http . StatusCreated , result
}