diff --git a/cmd/server/pactasrv/BUILD.bazel b/cmd/server/pactasrv/BUILD.bazel index d2e8c1e..bd1a4eb 100644 --- a/cmd/server/pactasrv/BUILD.bazel +++ b/cmd/server/pactasrv/BUILD.bazel @@ -9,6 +9,7 @@ go_library( "pacta_version.go", "pactasrv.go", "portfolio.go", + "upload.go", "user.go", ], importpath = "github.com/RMI/pacta/cmd/server/pactasrv", diff --git a/cmd/server/pactasrv/pactasrv.go b/cmd/server/pactasrv/pactasrv.go index 4e0a09b..937ac96 100644 --- a/cmd/server/pactasrv/pactasrv.go +++ b/cmd/server/pactasrv/pactasrv.go @@ -67,6 +67,12 @@ type DB interface { CreatePortfolioInitiativeMembership(tx db.Tx, pim *pacta.PortfolioInitiativeMembership) error DeletePortfolioInitiativeMembership(tx db.Tx, pid pacta.PortfolioID, iid pacta.InitiativeID) error + IncompleteUpload(tx db.Tx, id pacta.IncompleteUploadID) (*pacta.IncompleteUpload, error) + IncompleteUploads(tx db.Tx, ids []pacta.IncompleteUploadID) (map[pacta.IncompleteUploadID]*pacta.IncompleteUpload, error) + CreateIncompleteUpload(tx db.Tx, i *pacta.IncompleteUpload) (pacta.IncompleteUploadID, error) + UpdateIncompleteUpload(tx db.Tx, id pacta.IncompleteUploadID, mutations ...db.UpdateIncompleteUploadFn) error + DeleteIncompleteUpload(tx db.Tx, id pacta.IncompleteUploadID) (pacta.BlobURI, error) + GetOrCreateUserByAuthn(tx db.Tx, mech pacta.AuthnMechanism, authnID, email, canonicalEmail string) (*pacta.User, error) User(tx db.Tx, id pacta.UserID) (*pacta.User, error) Users(tx db.Tx, ids []pacta.UserID) (map[pacta.UserID]*pacta.User, error) diff --git a/cmd/server/pactasrv/upload.go b/cmd/server/pactasrv/upload.go new file mode 100644 index 0000000..a9c6498 --- /dev/null +++ b/cmd/server/pactasrv/upload.go @@ -0,0 +1,20 @@ +package pactasrv + +import ( + "context" + "fmt" + + api "github.com/RMI/pacta/openapi/pacta" +) + +// Starts the process of uploading one or more portfolio files +// (POST /portfolio-upload) +func (s *Server) StartPortfolioUpload(ctx context.Context, request api.StartPortfolioUploadRequestObject) (api.StartPortfolioUploadResponseObject, error) { + return nil, fmt.Errorf("not implemented") +} + +// Called after uploads of portfolios to cloud storage are complete. +// (POST /portfolio-upload:complete) +func (s *Server) CompletePortfolioUpload(ctx context.Context, request api.CompletePortfolioUploadRequestObject) (api.CompletePortfolioUploadResponseObject, error) { + return nil, fmt.Errorf("not implemented") +} diff --git a/openapi/pacta.yaml b/openapi/pacta.yaml index ae4c0c8..0ba82be 100644 --- a/openapi/pacta.yaml +++ b/openapi/pacta.yaml @@ -464,9 +464,47 @@ paths: application/json: schema: $ref: '#/components/schemas/NewPortfolioAsset' + /portfolio-upload: + post: + summary: Starts the process of uploading one or more portfolio files + description: Creates one or more new incomplete portfolio uploads, and creates upload URLs for the user to put their blobs into. + operationId: startPortfolioUpload + requestBody: + description: A request describing the portfolios that the user wants to upload + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/StartPortfolioUploadReq' + responses: + '200': + description: The assets can now be uploaded via the given signed URLs. + content: + application/json: + schema: + $ref: '#/components/schemas/StartPortfolioUploadResp' + /portfolio-upload:complete: + post: + summary: Called after uploads of portfolios to cloud storage are complete. + description: Signals that the upload of the portfolios are complete, and that the server should start parsing them. + operationId: completePortfolioUpload + requestBody: + description: A request describing the incomplete uploads that the user wants to begin processing + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CompletePortfolioUploadReq' + responses: + '200': + description: The process to initiate the parsing of the uploads has been initiated. + content: + application/json: + schema: + $ref: '#/components/schemas/CompletePortfolioUploadResp' /test:parsePortfolio: post: - summary: Test endpoint, triggers a task to process the portfolio + summary: Test endpoint, triggers a task to parse the portfolio description: | Starts processing raw uploaded files operationId: parsePortfolio @@ -838,6 +876,74 @@ components: asset_id: type: string description: A unique identifier for the uploaded asset + StartPortfolioUploadReq: + type: object + required: + - items + properties: + items: + type: array + items: + $ref: '#/components/schemas/StartPortfolioUploadReqItem' + StartPortfolioUploadReqItem: + type: object + required: + - file_name + properties: + file_name: + type: string + description: The name of the file, including its extension. + StartPortfolioUploadResp: + type: object + required: + - items + properties: + items: + type: array + items: + $ref: '#/components/schemas/StartPortfolioUploadRespItem' + StartPortfolioUploadRespItem: + type: object + required: + - file_name + - upload_url + - incomplete_upload_id + properties: + file_name: + type: string + description: The name of the file, including its extension, used as a round-trip id. + upload_url: + type: string + description: The signed URL where the file should be uploaded to, using PUT semantics. + incomplete_upload_id: + type: string + description: A unique identifier for the uploaded asset + CompletePortfolioUploadReq: + type: object + required: + - items + properties: + items: + type: array + items: + $ref: '#/components/schemas/CompletePortfolioUploadReqItem' + description: The incomplete uploads that have been successfully uploaded to storage and are ready for parsing. + CompletePortfolioUploadReqItem: + type: object + required: + - incomplete_upload_id + properties: + incomplete_upload_id: + type: string + description: The unique identifier for the uploaded asset + CompletePortfolioUploadResp: + type: object + required: + - analysis_id + properties: + analysis_id: + type: string + description: The analysis id to track for the parsing task. ParsePortfolioReq: type: object required: