package repository import ( "context" "errors" "fmt" "mime/multipart" "strings" "time" "github.com/minio/minio-go/v7" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.uber.org/zap" "penahub.gitlab.yandexcloud.net/backend/verification/internal/models" ) type VerificationRepository struct { logger *zap.Logger mongo *mongo.Collection s3 *minio.Client } const ( VerificationEndpointURL = "https://hub.pena.digital" VerificationBucket = "verification1" VerificationCollection = "verification" ) func NewVerificationRepository(logger *zap.Logger, mongoDb *mongo.Database, s3 *minio.Client) *VerificationRepository { // Получаем список названий коллекций collections, err := mongoDb.ListCollectionNames(context.Background(), bson.M{}) if err != nil { fmt.Println(err) } fmt.Println(collections) return &VerificationRepository{ logger: logger, mongo: mongoDb.Collection(VerificationCollection), s3: s3, } } func (r *VerificationRepository) Init(ctx context.Context) error { //ok, err := r.s3.BucketExists(ctx, VerificationBucket) //if r.err(err) { // return err //} // //if !ok { // err = r.s3.MakeBucket(ctx, VerificationBucket, minio.MakeBucketOptions{ObjectLocking: false}) // if r.err(err) { // return err // } // // policyConsoleStatement := policy.Statement{ // Actions: set.CreateStringSet("*"), // Conditions: policy.ConditionMap{ // "StringLike": policy.ConditionKeyMap{ // "aws:referer": set.CreateStringSet(fmt.Sprintf("https://console.cloud.yandex.*/folders/*/storage/buckets/%s*", VerificationBucket)), // }, // }, // Effect: "Allow", // Principal: policy.User{AWS: set.CreateStringSet("*")}, // Resources: set.CreateStringSet(fmt.Sprintf("arn:aws:s3:::%s/*", VerificationBucket), // fmt.Sprintf("arn:aws:s3:::%s", VerificationBucket)), // Sid: "console-statement", // } // // policyServiceAccount := policy.Statement{ // Actions: set.CreateStringSet("*"), // Conditions: nil, // Effect: "Allow", // Principal: policy.User{CanonicalUser: set.CreateStringSet("ajelmc4tjbct675tjdh9")}, // Resources: set.CreateStringSet(fmt.Sprintf("arn:aws:s3:::%s/*", VerificationBucket), // fmt.Sprintf("arn:aws:s3:::%s", VerificationBucket)), // Sid: "service-account-statement", // } // // policySharingBucket := policy.Statement{ // Actions: set.CreateStringSet("s3:GetObject"), // Conditions: nil, // Effect: "Allow", // Principal: policy.User{AWS: set.CreateStringSet("*")}, // Resources: set.CreateStringSet(fmt.Sprintf("arn:aws:s3:::%s/*", VerificationBucket), // fmt.Sprintf("arn:aws:s3:::%s", VerificationBucket)), // Sid: "sharing-bucket", // } // // p := policy.BucketAccessPolicy{Version: "2012-10-17", Statements: []policy.Statement{ // policyConsoleStatement, // policyServiceAccount, // policySharingBucket, // }} // // outPolicy, err := json.Marshal(&p) // if r.err(err) { // return err // } // // err = r.s3.SetBucketPolicy(ctx, VerificationBucket, string(outPolicy)) // if r.err(err) { // return err // } //} return nil } func (r *VerificationRepository) Insert( ctx context.Context, userID string, record *models.Verification, innFH, ruleFH, egruleFH, certFH *multipart.FileHeader) (*models.Verification, error) { now := time.Now() record.ID = primitive.NewObjectIDFromTimestamp(now).Hex() record.UpdatedAt = now // Put inn file inn, err := innFH.Open() if r.err(err) { return nil, err } _, err = r.s3.PutObject(ctx, VerificationBucket, fmt.Sprintf("%s/%s", userID, innFH.Filename), inn, innFH.Size, minio.PutObjectOptions{}) if r.err(err) { return nil, err } rule, err := ruleFH.Open() if r.err(err) { return nil, err } // Put rule file _, err = r.s3.PutObject(ctx, VerificationBucket, fmt.Sprintf("%s/%s", userID, ruleFH.Filename), rule, ruleFH.Size, minio.PutObjectOptions{}) if r.err(err) { return nil, err } // Put egrule file egrule, err := egruleFH.Open() if r.err(err) { return nil, err } _, err = r.s3.PutObject(ctx, VerificationBucket, fmt.Sprintf("%s/%s", userID, egruleFH.Filename), egrule, egruleFH.Size, minio.PutObjectOptions{}) if r.err(err) { return nil, err } // Put certificate file if certFH != nil { cert, err := certFH.Open() if r.err(err) { return nil, err } _, err = r.s3.PutObject(ctx, VerificationBucket, fmt.Sprintf("%s/%s", userID, certFH.Filename), cert, certFH.Size, minio.PutObjectOptions{}) if r.err(err) { return nil, err } record.Files = []models.VerificationFile{ { Name: "certificate", Url: fmt.Sprintf("%s/%s/%s/%s", VerificationEndpointURL, VerificationBucket, userID, certFH.Filename), }, } } // Insert to MongoDB record.Files = append(record.Files, []models.VerificationFile{ { Name: "inn", Url: fmt.Sprintf("%s/%s/%s/%s", VerificationEndpointURL, VerificationBucket, userID, innFH.Filename), }, { Name: "rule", Url: fmt.Sprintf("%s/%s/%s/%s", VerificationEndpointURL, VerificationBucket, userID, ruleFH.Filename), }, { Name: "egrule", Url: fmt.Sprintf("%s/%s/%s/%s", VerificationEndpointURL, VerificationBucket, userID, egruleFH.Filename), }, }...) result, err := r.mongo.InsertOne(ctx, record) if r.err(err) { return nil, err } record.ID = result.InsertedID.(string) return record, nil } func (r *VerificationRepository) GetByUserID(ctx context.Context, userID string) (*models.Verification, error) { if userID == "" { err := errors.New("userID cannot be empty") r.logger.Error("VerificationRepositoryError", zap.Error(err)) return nil, err } filter := bson.M{ "user_id": userID, } opts := options.FindOne().SetSort(bson.D{{Key: "updated_at", Value: -1}}) var result models.Verification err := r.mongo.FindOne(ctx, filter, opts).Decode(&result) if err != nil { if err == mongo.ErrNoDocuments { return nil, nil } r.logger.Error("VerificationRepositoryError", zap.Error(err)) return nil, err } return &result, nil } func (r *VerificationRepository) Get(ctx context.Context, id string) (*models.Verification, error) { if id == "" { err := errors.New("_id cannot be empty") r.logger.Error("VerificationRepositoryError", zap.Error(err)) return nil, err } filter := bson.M{ "_id": id, } var result models.Verification err := r.mongo.FindOne(ctx, filter).Decode(&result) if err != nil { if err == mongo.ErrNoDocuments { return nil, nil } r.logger.Error("VerificationRepositoryError", zap.Error(err)) return nil, err } return &result, nil } func (r *VerificationRepository) Update(ctx context.Context, record *models.Verification) (*models.Verification, error) { record.UpdatedAt = time.Now() test := models.Test{ UserID: record.UserID, Accepted: record.Accepted, Status: record.Status, UpdatedAt: record.UpdatedAt, Comment: record.Comment, Files: record.Files, TaxNumber: record.TaxNumber, } id, _ := primitive.ObjectIDFromHex(record.ID) var result models.Verification err := r.mongo.FindOneAndUpdate(ctx, bson.M{"_id": id}, bson.M{"$set": test}, options.FindOneAndUpdate().SetReturnDocument(options.After)).Decode(&result) if r.err(err) { fmt.Println(err) return nil, err } fmt.Println(result) return &result, nil } func (r *VerificationRepository) UpdateFile(ctx context.Context, userID, fileName string, fileHeader *multipart.FileHeader) (*models.Verification, error) { var err error // put file fileReader, err := fileHeader.Open() if r.err(err) { return nil, err } _, err = r.s3.PutObject(ctx, VerificationBucket, fmt.Sprintf("%s/%s", userID, fileHeader.Filename), fileReader, fileHeader.Size, minio.PutObjectOptions{}) if r.err(err) { return nil, err } fileURL := fmt.Sprintf("%s/%s/%s/%s", VerificationEndpointURL, VerificationBucket, userID, fileHeader.Filename) // remove old file verification, err := r.GetByUserID(ctx, userID) if r.err(err) { return nil, err } found := false for iterator, file := range verification.Files { if file.Name != fileName { continue } objectName := strings.ReplaceAll(file.Url, fmt.Sprintf("%v/%v/", VerificationEndpointURL, VerificationBucket), "") if err = r.s3.RemoveObject(ctx, VerificationBucket, objectName, minio.RemoveObjectOptions{}); r.err(err) { return nil, err } verification.Files[iterator] = models.VerificationFile{Name: file.Name, Url: fileURL} found = true } if !found { verification.Files = append(verification.Files, models.VerificationFile{Name: fileName, Url: fileURL}) } // update in mongodb result, err := r.Update(ctx, &models.Verification{ID: verification.ID, Files: verification.Files}) if r.err(err) { return nil, err } return result, nil } func (r *VerificationRepository) err(err error) bool { if err != nil { r.logger.Error("VerificationRepositoryError", zap.Error(err)) return true } return false }