Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: object upload #121

Merged
merged 25 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
258bf0a
update ent schemas
matoszz Oct 3, 2024
c36430b
remove query and commit updated schema
matoszz Oct 3, 2024
0fbbbd6
remove file history
matoszz Oct 3, 2024
9407a27
task pr output
matoszz Oct 3, 2024
300d169
functional handler
matoszz Oct 7, 2024
184eca1
wip: updates to use middleware + gqlgen upload files for file objects
golanglemonade Oct 13, 2024
7c1f7dd
switch to mockery
golanglemonade Oct 13, 2024
8b09fc6
switch to config
golanglemonade Oct 13, 2024
c05fe43
squash db, hooks for user avatar example
golanglemonade Oct 13, 2024
224c18e
fix upload with seeker reset, update interfaces to stores
golanglemonade Oct 13, 2024
425bb69
add avatar file as fk to files table
golanglemonade Oct 13, 2024
42bff32
move most middleware to pkg, not unique to core repo except the datab…
golanglemonade Oct 14, 2024
10c7e1f
generate, upload
golanglemonade Oct 14, 2024
ce1adb6
validate mime type, fixes for gqlgenc client
golanglemonade Oct 15, 2024
01b2f66
comment, tests, run:generate
golanglemonade Oct 15, 2024
e6a2c51
exclude mocks from sonar
golanglemonade Oct 15, 2024
8c19cc1
sonar cleanup
golanglemonade Oct 15, 2024
8de4e21
comment move
golanglemonade Oct 15, 2024
fbbe9ff
be smarter
golanglemonade Oct 15, 2024
647854b
or dont
golanglemonade Oct 15, 2024
bd513bd
remove fork reference for gqlgenc, bump to go 1.23.2
golanglemonade Oct 15, 2024
fd3cae1
fix bad testify import
golanglemonade Oct 15, 2024
642f326
fix bug with graphql arguments, PR feedback
golanglemonade Oct 15, 2024
386367a
remove unused bind funcs
golanglemonade Oct 15, 2024
6410f2b
fix flakey test
golanglemonade Oct 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ issues:
- docker/*
- internal/ent/generated/*
- jsonschema/templates/*
- pkg/objects/mocks/*
exclude-files:
- internal/graphapi/gen_server.go
- internal/graphapi/
Expand Down
8 changes: 4 additions & 4 deletions cmd/cli/Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ tasks:
sh: ls -d ../../query/* | cut -f1 |grep history | sed -e "s/query\///" |sed -e "s/.graphql//" | sed -e "s/history/History/" | sed -e "s/..\/..\///"
cmds:
- for: {var: SCHEMAS, as: SCHEMA}
cmd: go run gencmd/generate/main.go generate --name={{ .SCHEMA }} --read-only
cmd: go run ../../pkg/gencmd/generate/main.go generate --name={{ .SCHEMA }} --read-only

generate:all:history:force:
desc: regenerates the cli cmd for all history commands from the query/ directory, this will overwrite any changes made to the generated files
Expand All @@ -17,19 +17,19 @@ tasks:
sh: ls -d ../../query/* | cut -f1 |grep history | sed -e "s/query\///" |sed -e "s/.graphql//" | sed -e "s/history/History/" | sed -e "s/..\/..\///"
cmds:
- for: {var: SCHEMAS, as: SCHEMA}
cmd: go run gencmd/generate/main.go generate --name={{ .SCHEMA }} --read-only --force
cmd: go run ../../pkg/gencmd/generate/main.go generate --name={{ .SCHEMA }} --read-only --force

generate:
desc: generates a new cli cmd
interactive: true
cmds:
- go run gencmd/generate/main.go generate
- go run ../../pkg/gencmd/generate/main.go generate

generate:ro:
desc: generates a new cli cmd with only the read cmds
interactive: true
cmds:
- go run gencmd/generate/main.go generate --read-only
- go run ../../pkg/gencmd/generate/main.go generate --read-only

org:create:
desc: creates an organization against a running local instance of the server - see the CLI help commands for other variables
Expand Down
2 changes: 2 additions & 0 deletions cmd/cli/cmd/file/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package file is our cobra cli for file endpoints
package file
49 changes: 49 additions & 0 deletions cmd/cli/cmd/file/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package file

import (
"context"

"github.com/spf13/cobra"

"github.com/theopenlane/core/cmd/cli/cmd"
)

var getCmd = &cobra.Command{
Use: "get",
Short: "get an existing file",
Run: func(cmd *cobra.Command, args []string) {
err := get(cmd.Context())
cobra.CheckErr(err)
},
}

func init() {
command.AddCommand(getCmd)

getCmd.Flags().StringP("id", "i", "", "the ID of the file")
}

// get an existing file in the platform
func get(ctx context.Context) error {
// setup http client
client, err := cmd.SetupClientWithAuth(ctx)
cobra.CheckErr(err)
defer cmd.StoreSessionCookies(client)

// filter options
id := cmd.Config.String("id")

// if an file ID is provided, filter on that file, otherwise get all
if id != "" {
o, err := client.GetFileByID(ctx, id)
cobra.CheckErr(err)

return consoleOutput(o)
}

// get all will be filtered for the authorized organization(s)
o, err := client.GetAllFiles(ctx)
cobra.CheckErr(err)

return consoleOutput(o)
}
106 changes: 106 additions & 0 deletions cmd/cli/cmd/file/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package file

import (
"encoding/json"
"strings"

"github.com/spf13/cobra"

"github.com/theopenlane/utils/cli/tables"

"github.com/theopenlane/core/cmd/cli/cmd"
"github.com/theopenlane/core/pkg/openlaneclient"
)

// command represents the base file command when called without any subcommands
var command = &cobra.Command{
Use: "file",
Short: "the subcommands for working with files",
}

func init() {
cmd.RootCmd.AddCommand(command)
}

// consoleOutput prints the output in the console
func consoleOutput(e any) error {
// check if the output format is JSON and print the files in JSON format
if strings.EqualFold(cmd.OutputFormat, cmd.JSONOutput) {
return jsonOutput(e)
}

// check the type of the files and print them in a table format
switch v := e.(type) {
case *openlaneclient.GetAllFiles:
var nodes []*openlaneclient.GetAllFiles_Files_Edges_Node

for _, i := range v.Files.Edges {
nodes = append(nodes, i.Node)
}

e = nodes
case *openlaneclient.GetFiles:
var nodes []*openlaneclient.GetFiles_Files_Edges_Node

for _, i := range v.Files.Edges {
nodes = append(nodes, i.Node)
}

e = nodes
case *openlaneclient.GetFileByID:
e = v.File
case *openlaneclient.CreateFile:
e = v.CreateFile.File
case *openlaneclient.UpdateFile:
e = v.UpdateFile.File
case *openlaneclient.DeleteFile:
deletedTableOutput(v)
return nil
}

s, err := json.Marshal(e)
cobra.CheckErr(err)

var list []openlaneclient.File

err = json.Unmarshal(s, &list)
if err != nil {
var in openlaneclient.File
err = json.Unmarshal(s, &in)
cobra.CheckErr(err)

list = append(list, in)
}

tableOutput(list)

return nil
}

// jsonOutput prints the output in a JSON format
func jsonOutput(out any) error {
s, err := json.Marshal(out)
cobra.CheckErr(err)

return cmd.JSONPrint(s)
}

// tableOutput prints the output in a table format
func tableOutput(out []openlaneclient.File) {
// create a table writer
writer := tables.NewTableWriter(command.OutOrStdout(), "ID", "URI", "ProvidedFileName", "CategoryType", "DetectedMimeType", "FileExtension", "StoragePath")
for _, i := range out {
writer.AddRow(i.ID, *i.URI, i.ProvidedFileName, *i.Md5Hash, *i.DetectedMimeType, i.ProvidedFileExtension, *i.StoragePath)
}

writer.Render()
}

// deleteTableOutput prints the deleted id in a table format
func deletedTableOutput(e *openlaneclient.DeleteFile) {
writer := tables.NewTableWriter(command.OutOrStdout(), "DeletedID")

writer.AddRow(e.DeleteFile.DeletedID)

writer.Render()
}
2 changes: 1 addition & 1 deletion cmd/cli/cmd/filehistory/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/theopenlane/core/pkg/openlaneclient"
)

// cmd represents the base fileHistory command when called without any subcommands
// command represents the base fileHistory command when called without any subcommands
var command = &cobra.Command{
Use: "file-history",
Short: "the subcommands for working with fileHistories",
Expand Down
32 changes: 25 additions & 7 deletions cmd/cli/cmd/user/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package user
import (
"context"

"github.com/99designs/gqlgen/graphql"
"github.com/spf13/cobra"

"github.com/theopenlane/core/cmd/cli/cmd"
"github.com/theopenlane/core/pkg/objects"
"github.com/theopenlane/core/pkg/openlaneclient"
)

Expand All @@ -26,25 +28,26 @@ func init() {
createCmd.Flags().StringP("first-name", "f", "", "first name of the user")
createCmd.Flags().StringP("last-name", "l", "", "last name of the user")
createCmd.Flags().StringP("display-name", "d", "", "first name of the user")
createCmd.Flags().StringP("avatar-file", "a", "", "local of avatar file to upload")
}

// createValidation validates the required fields for the command
func createValidation() (input openlaneclient.CreateUserInput, err error) {
func createValidation() (input openlaneclient.CreateUserInput, avatarFile *graphql.Upload, err error) {
input.Email = cmd.Config.String("email")
if input.Email == "" {
return input, cmd.NewRequiredFieldMissingError("email")
return input, nil, cmd.NewRequiredFieldMissingError("email")
}

firstName := cmd.Config.String("first-name")
if firstName == "" {
return input, cmd.NewRequiredFieldMissingError("first name")
return input, nil, cmd.NewRequiredFieldMissingError("first name")
}

input.FirstName = &firstName

lastName := cmd.Config.String("last-name")
if lastName == "" {
return input, cmd.NewRequiredFieldMissingError("last name")
return input, nil, cmd.NewRequiredFieldMissingError("last name")
}

input.LastName = &lastName
Expand All @@ -59,7 +62,22 @@ func createValidation() (input openlaneclient.CreateUserInput, err error) {
input.Password = &password
}

return input, nil
avatarFileLoc := cmd.Config.String("avatar-file")
if avatarFileLoc != "" {
file, err := objects.NewUploadFile(avatarFileLoc)
if err != nil {
return input, nil, err
}

avatarFile = &graphql.Upload{
File: file.File,
Filename: file.Filename,
Size: file.Size,
ContentType: file.ContentType,
}
}

return input, avatarFile, nil
}

// create a new user
Expand All @@ -69,10 +87,10 @@ func create(ctx context.Context) error {
cobra.CheckErr(err)
defer cmd.StoreSessionCookies(client)

input, err := createValidation()
input, avatarFile, err := createValidation()
cobra.CheckErr(err)

o, err := client.CreateUser(ctx, input)
o, err := client.CreateUser(ctx, input, avatarFile)
cobra.CheckErr(err)

return consoleOutput(o)
Expand Down
1 change: 0 additions & 1 deletion cmd/cli/cmd/user/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ func jsonOutput(out any) error {
func tableOutput(out []openlaneclient.User) {
writer := tables.NewTableWriter(command.OutOrStdout(), "ID", "Email", "FirstName", "LastName", "DisplayName", "AuthProvider")
for _, i := range out {
// this doesn't visually show you the json in the table but leaving it in for now
writer.AddRow(i.ID, i.Email, *i.FirstName, *i.LastName, i.DisplayName, i.AuthProvider)
}

Expand Down
28 changes: 23 additions & 5 deletions cmd/cli/cmd/user/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package user
import (
"context"

"github.com/99designs/gqlgen/graphql"
"github.com/spf13/cobra"

"github.com/theopenlane/core/cmd/cli/cmd"
"github.com/theopenlane/core/pkg/objects"
"github.com/theopenlane/core/pkg/openlaneclient"
)

Expand All @@ -26,13 +28,14 @@ func init() {
updateCmd.Flags().StringP("last-name", "l", "", "last name of the user")
updateCmd.Flags().StringP("display-name", "d", "", "display name of the user")
updateCmd.Flags().StringP("email", "e", "", "email of the user")
updateCmd.Flags().StringP("avatar-file", "a", "", "local of avatar file to upload")
}

// updateValidation validates the input flags provided by the user
func updateValidation() (id string, input openlaneclient.UpdateUserInput, err error) {
func updateValidation() (id string, input openlaneclient.UpdateUserInput, avatarFile *graphql.Upload, err error) {
id = cmd.Config.String("id")
if id == "" {
return id, input, cmd.NewRequiredFieldMissingError("user id")
return id, input, nil, cmd.NewRequiredFieldMissingError("user id")
}

firstName := cmd.Config.String("first-name")
Expand All @@ -55,8 +58,23 @@ func updateValidation() (id string, input openlaneclient.UpdateUserInput, err er
input.Email = &email
}

avatarFileLoc := cmd.Config.String("avatar-file")
if avatarFileLoc != "" {
file, err := objects.NewUploadFile(avatarFileLoc)
if err != nil {
return id, input, nil, err
}

avatarFile = &graphql.Upload{
File: file.File,
Filename: file.Filename,
Size: file.Size,
ContentType: file.ContentType,
}
}

// TODO: allow updates to user settings
return id, input, nil
return id, input, avatarFile, nil
}

// update an existing user
Expand All @@ -66,10 +84,10 @@ func update(ctx context.Context) error {
cobra.CheckErr(err)
defer cmd.StoreSessionCookies(client)

id, input, err := updateValidation()
id, input, avatarFile, err := updateValidation()
cobra.CheckErr(err)

o, err := client.UpdateUser(ctx, id, input)
o, err := client.UpdateUser(ctx, id, input, avatarFile)
cobra.CheckErr(err)

return consoleOutput(o)
Expand Down
1 change: 1 addition & 0 deletions cmd/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
_ "github.com/theopenlane/core/cmd/cli/cmd/entitytype"
_ "github.com/theopenlane/core/cmd/cli/cmd/events"
_ "github.com/theopenlane/core/cmd/cli/cmd/features"
_ "github.com/theopenlane/core/cmd/cli/cmd/file"
_ "github.com/theopenlane/core/cmd/cli/cmd/group"
_ "github.com/theopenlane/core/cmd/cli/cmd/groupmembers"
_ "github.com/theopenlane/core/cmd/cli/cmd/groupsetting"
Expand Down
1 change: 1 addition & 0 deletions cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func serve(ctx context.Context) error {
serveropts.WithSecureMW(),
serveropts.WithCacheHeaders(),
serveropts.WithCORS(),
serveropts.WithObjectStorage(),
)

so := serveropts.NewServerOptions(serverOpts, k.String("config"))
Expand Down
8 changes: 8 additions & 0 deletions config/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,11 @@ CORE_RATELIMIT_ENABLED="false"
CORE_RATELIMIT_LIMIT="10"
CORE_RATELIMIT_BURST="30"
CORE_RATELIMIT_EXPIRES="10m"
CORE_OBJECTSTORAGE_ENABLED="true"
CORE_OBJECTSTORAGE_PROVIDER=""
CORE_OBJECTSTORAGE_ACCESSKEY=""
CORE_OBJECTSTORAGE_REGION=""
CORE_OBJECTSTORAGE_SECRETKEY=""
CORE_OBJECTSTORAGE_CREDENTIALSJSON=""
CORE_OBJECTSTORAGE_DEFAULTBUCKET=""
CORE_OBJECTSTORAGE_KEYS="[uploadFile]"
Loading