From f62d74634791f92e6d750703c5c84c5f0f951f52 Mon Sep 17 00:00:00 2001 From: Miguel Ramos Date: Thu, 11 Feb 2021 19:27:15 +0000 Subject: [PATCH] feat: upload resource simple --- api/api.go | 2 +- api/bucket.go | 78 ++++++++++++++++++++++++++++++++-- api/middleware.go | 10 ++++- config/minio.go | 2 +- database/00-gotrue-schema.sql | 13 ++++++ go.mod | 1 + go.sum | 2 + models/bucket.go | 19 +++++---- models/bucket_media.go | 38 +++++++++++++++++ models/media.go | 57 +++++++++++++++++++++++++ storage/dial.go | 1 + temp/me.jpeg | Bin 0 -> 38164 bytes utils/helpers.go | 6 +++ 13 files changed, 214 insertions(+), 15 deletions(-) create mode 100644 models/bucket_media.go create mode 100644 models/media.go create mode 100644 temp/me.jpeg diff --git a/api/api.go b/api/api.go index 44b6b1c..282ab22 100644 --- a/api/api.go +++ b/api/api.go @@ -42,7 +42,7 @@ func NewPrivateAPI(api *API, router fiber.Router) { bucketRouter := router.Group("/bucket") bucketRouter.Post("", api.CreateBucket) - bucketRouter.Post("/upload", api.PutObject) + bucketRouter.Post("/:bucket", api.PutObject) userRouter := router.Group("/user") userRouter.Post("", api.CreateUser) diff --git a/api/bucket.go b/api/bucket.go index 10fc4d9..7af955a 100644 --- a/api/bucket.go +++ b/api/bucket.go @@ -1,11 +1,17 @@ package api import ( + "encoding/json" "fmt" + "net/url" + "os" + "path" "strings" + "github.com/barasher/go-exiftool" "github.com/gobuffalo/pop/nulls" "github.com/gofiber/fiber/v2" + "github.com/gofrs/uuid" "github.com/gosimple/slug" "github.com/minio/minio-go/v7" "github.com/websublime/barrel/config" @@ -79,8 +85,74 @@ func (api *API) CreateBucket(ctx *fiber.Ctx) error { }) } +// PutObject upload to bucket func (api *API) PutObject(ctx *fiber.Ctx) error { - return ctx.JSON(fiber.Map{ - "data": "object", - }) + bucketName := ctx.Params("bucket") + medias := []*models.Media{} + //TODO: user + bucket, err := models.FindBucket(api.db, bucketName) + if err != nil { + return utils.NewException(utils.ErrorBucketMissing, fiber.StatusBadRequest, err.Error()) + } + + if et, err := exiftool.NewExiftool(); err == nil { + defer et.Close() + + if form, err := ctx.MultipartForm(); err == nil { + files := form.File["asset"] + + for _, file := range files { + ctx.SaveFile(file, fmt.Sprintf("./temp/%s", file.Filename)) + data := et.ExtractMetadata(fmt.Sprintf("./temp/%s", file.Filename)) + + meta, err := json.Marshal(data[0].Fields) + if err != nil { + return utils.NewException(utils.ErrorResourceMetaFailure, fiber.StatusBadRequest, err.Error()) + } + + metafile := new(config.MetaFile) + json.Unmarshal([]byte(meta), &metafile) + + bucketFile, err := api.store.FPutObject(ctx.Context(), bucketName, metafile.FileName, fmt.Sprintf("./temp/%s", metafile.FileName), minio.PutObjectOptions{ + ContentType: metafile.MIMEType, + UserMetadata: map[string]string{}, + }) + + if err != nil { + return utils.NewException(utils.ErrorResourceBucketFailure, fiber.StatusBadRequest, err.Error()) + } + + u, _ := url.Parse(api.config.BarrelBaseURL) + u.Path = path.Join(u.Path, bucketName, metafile.FileName) + bucketFileJSON, _ := json.Marshal(bucketFile) + metaFileJSON, _ := json.Marshal(metafile) + + media, _ := models.NewMedia(u.String(), nulls.NewUUID(uuid.Nil), nulls.NewString(string(bucketFileJSON)), nulls.NewString(string(metaFileJSON))) + bucketMedia, _ := models.NewBucketMedia(bucket.ID, media.ID) + + err = api.db.Transaction(func(tx *storage.Connection) error { + terr := tx.Create(media) + terr = tx.Create(bucketMedia) + + return terr + }) + if err != nil { + return utils.NewException(utils.ErrorResourceModelSave, fiber.StatusBadRequest, err.Error()) + } + + os.Remove(fmt.Sprintf("./temp/%s", file.Filename)) + + medias = append(medias, media) + } + + return ctx.JSON(fiber.Map{ + "data": medias, + }) + } else { + return utils.NewException(utils.ErrorResourceInvalidForm, fiber.StatusBadRequest, err.Error()) + } + } else { + return utils.NewException(utils.ErrorExifMissing, fiber.StatusBadRequest, err.Error()) + } + } diff --git a/api/middleware.go b/api/middleware.go index 98a5412..793c749 100644 --- a/api/middleware.go +++ b/api/middleware.go @@ -42,7 +42,7 @@ func (api *API) AuthorizedMiddleware(ctx *fiber.Ctx) error { } ctx.Locals("claims", claims) - ctx.Locals("token", auth) + ctx.Locals("token", token) } else { return utils.NewException(utils.ErrorOrgStatusForbidden, fiber.StatusForbidden, "Only authorized requests are permitted") } @@ -85,6 +85,7 @@ func (api *API) AdminMiddleware(ctx *fiber.Ctx) error { //CanAccessMiddleware check if user is register to access private endpoints func (api *API) CanAccessMiddleware(ctx *fiber.Ctx) error { isAdmin := ctx.Locals("admin").(bool) + token := ctx.Locals("token").(*jwt.Token) headerKey := ctx.Get("X-BARREL-KEY") if !isAdmin { @@ -93,6 +94,13 @@ func (api *API) CanAccessMiddleware(ctx *fiber.Ctx) error { return err } + if user.Status == "disabled" { + return utils.NewException(utils.ErrorOrgStatusForbidden, fiber.StatusForbidden, "User is disabled") + } + // TODO: we need to save user key/secret on database + client, _ := config.NewClient(api.config, headerKey, "20894b322d824da6a6ad32cd1be2e368", token.Raw) + api.store = client + ctx.Locals("user", user) } diff --git a/config/minio.go b/config/minio.go index 4f34d5d..6f86209 100644 --- a/config/minio.go +++ b/config/minio.go @@ -39,7 +39,7 @@ func OpenAdminClient(conf *EnvironmentConfig) (*madmin.AdminClient, error) { // NewClient create a new client connection func NewClient(conf *EnvironmentConfig, key string, secret string, token string) (*minio.Client, error) { minioClient, err := minio.New(conf.BarrelMinioURL, &minio.Options{ - Creds: credentials.NewStaticV4(key, secret, token), + Creds: credentials.NewStaticV4(key, secret, ""), Secure: false, }) diff --git a/database/00-gotrue-schema.sql b/database/00-gotrue-schema.sql index 4bbb2a4..781f213 100644 --- a/database/00-gotrue-schema.sql +++ b/database/00-gotrue-schema.sql @@ -84,6 +84,18 @@ CREATE TABLE auth.identities ( user_id uuid NOT NULL, CONSTRAINT identities_pkey PRIMARY KEY (id) ); +-- auth.templates definition +CREATE TABLE auth.templates +( + id uuid NOT NULL, + aud varchar(255), + type varchar(50), + subject text, + url text DEFAULT '/', + base_url varchar(255), + url_template text, + CONSTRAINT templates_pkey PRIMARY KEY (id) +); -- Gets the User ID from the request cookie create or replace function auth.uid() returns uuid as $$ select nullif(current_setting('request.jwt.claim.sub', true), '')::uuid; @@ -92,6 +104,7 @@ $$ language sql stable; create or replace function auth.role() returns text as $$ select nullif(current_setting('request.jwt.claim.role', true), '')::text; $$ language sql stable; + GRANT ALL PRIVILEGES ON SCHEMA auth TO postgres; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA auth TO postgres; GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA auth TO postgres; diff --git a/go.mod b/go.mod index 92d750d..78990ab 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/websublime/barrel go 1.15 require ( + github.com/barasher/go-exiftool v1.3.2 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/gobuffalo/pop v4.13.1+incompatible github.com/gobuffalo/pop/v5 v5.3.3 diff --git a/go.sum b/go.sum index 19192af..3f73549 100644 --- a/go.sum +++ b/go.sum @@ -72,6 +72,8 @@ github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQ github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.35.20/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/barasher/go-exiftool v1.3.2 h1:yWUIGOsM6PLbbHxe84ASTo/eyORMTyMH/5Qv1yBcC7s= +github.com/barasher/go-exiftool v1.3.2/go.mod h1:F9s/a3uHSM8YniVfwF+sbQUtP8Gmh9nyzigNF+8vsWo= github.com/bcicen/jstream v1.0.1 h1:BXY7Cu4rdmc0rhyTVyT3UkxAiX3bnLpKLas9btbH5ck= github.com/bcicen/jstream v1.0.1/go.mod h1:9ielPxqFry7Y4Tg3j4BfjPocfJ3TbsRtXOAYXYmRuAQ= github.com/beevik/ntp v0.3.0 h1:xzVrPrE4ziasFXgBVBZJDP0Wg/KpMwk2KHJ4Ba8GrDw= diff --git a/models/bucket.go b/models/bucket.go index 8cb2440..9385ecf 100644 --- a/models/bucket.go +++ b/models/bucket.go @@ -16,15 +16,16 @@ import ( // Bucket model type type Bucket struct { - ID uuid.UUID `json:"id" db:"id"` - Name string `json:"name" db:"name"` - Bucket nulls.String `json:"bucket,omitempty" db:"bucket"` - OrgID nulls.String `json:"orgId,omitempty" db:"org_id"` - IsPrivate bool `json:"isPrivate" db:"is_private"` - Policy string `json:"policy" db:"-"` - CreatedAt time.Time `json:"createdAt" db:"created_at"` - UpdatedAt time.Time `json:"updatedAt" db:"updated_at"` - DeletedAt nulls.Time `json:"deleteAt,omitempty" db:"deleted_at"` + ID uuid.UUID `json:"id" db:"id"` + Name string `json:"name" db:"name"` + Bucket nulls.String `json:"bucket,omitempty" db:"bucket"` + OrgID nulls.String `json:"orgId,omitempty" db:"org_id"` + IsPrivate bool `json:"isPrivate" db:"is_private"` + Policy string `json:"policy" db:"-"` + CreatedAt time.Time `json:"createdAt" db:"created_at"` + UpdatedAt time.Time `json:"updatedAt" db:"updated_at"` + DeletedAt nulls.Time `json:"deleteAt,omitempty" db:"deleted_at"` + BucketMedia []*BucketMedia `json:"medias,omitempty" many_to_many:"bucket_media" db:"-" fk_id:"bucket_id"` } // NewBucket creates new Bucket diff --git a/models/bucket_media.go b/models/bucket_media.go new file mode 100644 index 0000000..64b35ba --- /dev/null +++ b/models/bucket_media.go @@ -0,0 +1,38 @@ +package models + +import ( + "github.com/gobuffalo/uuid" + "github.com/pkg/errors" + "github.com/websublime/barrel/storage/namespace" +) + +type BucketMedia struct { + ID uuid.UUID `json:"id" db:"id" primary_id:"id"` + BucketID uuid.UUID `json:"bucketId" db:"bucket_id"` + MediaID uuid.UUID `json:"mediaId" db:"media_id"` +} + +func (BucketMedia) TableName() string { + tableName := "bucket_media" + + if namespace.GetNamespace() != "" { + return namespace.GetNamespace() + "." + tableName + } + + return tableName +} + +func NewBucketMedia(bucket uuid.UUID, media uuid.UUID) (*BucketMedia, error) { + uid, err := uuid.NewV4() + if err != nil { + return nil, errors.Wrap(err, "Error generating unique id") + } + + bucketMedia := &BucketMedia{ + ID: uid, + BucketID: bucket, + MediaID: media, + } + + return bucketMedia, nil +} diff --git a/models/media.go b/models/media.go new file mode 100644 index 0000000..e14c285 --- /dev/null +++ b/models/media.go @@ -0,0 +1,57 @@ +package models + +import ( + "time" + + "github.com/gobuffalo/pop/nulls" + "github.com/gobuffalo/uuid" + "github.com/gobuffalo/validate/v3" + "github.com/gobuffalo/validate/v3/validators" + "github.com/pkg/errors" + "github.com/websublime/barrel/storage/namespace" +) + +type Media struct { + ID uuid.UUID `json:"id" db:"id"` + URL string `json:"url" db:"url"` + Owner nulls.UUID `json:"ownerId" db:"owner"` + BucketFile nulls.String `json:"bucketFile" db:"bucket_file"` + Metafile nulls.String `json:"metadata" db:"meta_file"` + CreatedAt time.Time `json:"createdAt" db:"created_at"` + UpdatedAt time.Time `json:"updatedAt" db:"updated_at"` + DeletedAt nulls.Time `json:"deletedAt" db:"deleted_at"` + BucketMedia []*BucketMedia `json:"medias,omitempty" many_to_many:"bucket_media" db:"-" fk_id:"media_id" primary_id:"id"` +} + +func (Media) TableName() string { + tableName := "medias" + + if namespace.GetNamespace() != "" { + return namespace.GetNamespace() + "." + tableName + } + + return tableName +} + +func NewMedia(url string, owner nulls.UUID, bucketFile nulls.String, metadata nulls.String) (*Media, error) { + uid, err := uuid.NewV4() + if err != nil { + return nil, errors.Wrap(err, "Error generating unique id") + } + + media := &Media{ + ID: uid, + URL: url, + Owner: owner, + BucketFile: bucketFile, + Metafile: metadata, + } + + return media, nil +} + +func (m *Media) Validate() *validate.Errors { + return validate.Validate( + &validators.StringIsPresent{Field: m.URL, Name: "URL", Message: "Url is missign"}, + ) +} diff --git a/storage/dial.go b/storage/dial.go index 42aa1e9..2ebb2c6 100644 --- a/storage/dial.go +++ b/storage/dial.go @@ -39,6 +39,7 @@ func Dial(conf *config.EnvironmentConfig) (*Connection, error) { if logrus.StandardLogger().Level == logrus.DebugLevel { pop.Debug = true } + pop.Debug = true return &Connection{db}, nil } diff --git a/temp/me.jpeg b/temp/me.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..8a59fbe662cabff30fda1af9a86479fc308ea4e0 GIT binary patch literal 38164 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 literal 0 HcmV?d00001 diff --git a/utils/helpers.go b/utils/helpers.go index da36a6d..32a621c 100644 --- a/utils/helpers.go +++ b/utils/helpers.go @@ -5,6 +5,7 @@ const ( ErrorUserCreation = "EUSER_CREATEFORBIDDEN" ErrorUserBodyParse = "EUSER_BODYPARSE" ErrorBucketModel = "EBUCKET_MODEL" + ErrorBucketMissing = "EBUCKET_MISSING" ErrorBucketBodyParse = "EBUCKET_BODYPARSE" ErrorBucketExist = "EBUCKET_EXIST" ErrorBucketCreation = "EBUCKET_CREATE" @@ -23,6 +24,11 @@ const ( ErrorParseJson = "EJSON_PARSE" ErrorResourceForbidden = "ERESOURCE_FORBIDDEN" ErrorResourceInvalidBody = "ERESOURCE_BODYINVALID" + ErrorResourceInvalidForm = "ERESOURCE_FORMINVALID" + ErrorResourceMetaFailure = "ERESOURCE_METAFAILURE" + ErrorResourceBucketFailure = "ERESOURCE_BUCKETFAILURE" + ErrorResourceModelSave = "ERESOURCE_MODELSAVE" + ErrorExifMissing = "EEXIF_MISSING" ) // Contains checks if a string is present in a slice