@@ -29,25 +29,12 @@ func (ph *PublicHandler) UploadCatalogFile(ctx context.Context, req *artifactpb.
2929 err := fmt .Errorf ("failed to get user id from header: %v. err: %w" , err , customerror .ErrUnauthenticated )
3030 return nil , err
3131 }
32- err = checkUploadKnowledgeBaseFileRequest (req )
32+
33+ hasObject , err := checkUploadKnowledgeBaseFileRequest (req )
3334 if err != nil {
3435 return nil , err
3536 }
36- // check file name length based on character count
37- if len (req .File .Name ) > 255 {
38- return nil , fmt .Errorf ("file name is too long. max length is 255. name: %s err: %w" ,
39- req .File .Name , customerror .ErrInvalidArgument )
40- }
41- // determine the file type by its extension
42- req .File .Type = DetermineFileType (req .File .Name )
43- if req .File .Type == artifactpb .FileType_FILE_TYPE_UNSPECIFIED {
44- return nil , fmt .Errorf ("file extension is not supported. name: %s err: %w" ,
45- req .File .Name , customerror .ErrInvalidArgument )
46- }
4737
48- if strings .Contains (req .File .Name , "/" ) {
49- return nil , fmt .Errorf ("file name cannot contain '/'. err: %w" , customerror .ErrInvalidArgument )
50- }
5138 ns , err := ph .service .GetNamespaceByNsID (ctx , req .GetNamespaceId ())
5239 if err != nil {
5340 log .Error (
@@ -89,9 +76,26 @@ func (ph *PublicHandler) UploadCatalogFile(ctx context.Context, req *artifactpb.
8976 log .Error ("failed to get namespace tier" , zap .Error (err ))
9077 return nil , fmt .Errorf ("failed to get namespace tier. err: %w" , err )
9178 }
79+
9280 // upload file to minio and database
9381 var res * repository.KnowledgeBaseFile
94- {
82+ if ! hasObject {
83+ // check file name length based on character count
84+ if len (req .File .Name ) > 255 {
85+ return nil , fmt .Errorf ("file name is too long. max length is 255. name: %s err: %w" ,
86+ req .File .Name , customerror .ErrInvalidArgument )
87+ }
88+ // determine the file type by its extension
89+ req .File .Type = DetermineFileType (req .File .Name )
90+ if req .File .Type == artifactpb .FileType_FILE_TYPE_UNSPECIFIED {
91+ return nil , fmt .Errorf ("file extension is not supported. name: %s err: %w" ,
92+ req .File .Name , customerror .ErrInvalidArgument )
93+ }
94+
95+ if strings .Contains (req .File .Name , "/" ) {
96+ return nil , fmt .Errorf ("file name cannot contain '/'. err: %w" , customerror .ErrInvalidArgument )
97+ }
98+
9599 creatorUID , err := uuid .FromString (authUID )
96100 if err != nil {
97101 log .Error ("failed to parse creator uid" , zap .Error (err ))
@@ -152,8 +156,64 @@ func (ph *PublicHandler) UploadCatalogFile(ctx context.Context, req *artifactpb.
152156 log .Error ("failed to increase catalog usage" , zap .Error (err ))
153157 return nil , err
154158 }
155- }
159+ } else {
160+ object , err := ph .service .Repository .GetObjectByUID (ctx , uuid .FromStringOrNil (req .GetFile ().GetObjectUid ()))
161+ if err != nil {
162+ log .Error ("failed to get catalog object with provided UID" , zap .Error (err ))
163+ return nil , err
164+ }
156165
166+ if ! object .IsUploaded {
167+ log .Error ("file has not been uploaded yet" )
168+ return nil , fmt .Errorf ("file has not been uploaded yet" )
169+ }
170+
171+ // check if file size is more than 150MB
172+ if object .Size > int64 (tier .GetMaxUploadFileSize ()) {
173+ return nil , fmt .Errorf (
174+ "file size is more than %v. err: %w" ,
175+ tier .GetMaxUploadFileSize (),
176+ customerror .ErrInvalidArgument )
177+ }
178+
179+ // check if total usage in namespace
180+ quota , humanReadable := tier .GetFileStorageTotalQuota ()
181+ if totalUsageInNamespace + object .Size > int64 (quota ) {
182+ return nil , fmt .Errorf (
183+ "file storage total quota exceeded. max: %v. tier:%v, err: %w" ,
184+ humanReadable , tier .String (), customerror .ErrInvalidArgument )
185+ }
186+
187+ req .File .Type = DetermineFileType (object .Name )
188+
189+ kbFile := repository.KnowledgeBaseFile {
190+ Name : object .Name ,
191+ Type : req .File .Type .String (),
192+ Owner : ns .NsUID ,
193+ CreatorUID : object .CreatorUID ,
194+ KnowledgeBaseUID : kb .UID ,
195+ Destination : object .Destination ,
196+ ProcessStatus : artifactpb .FileProcessStatus_name [int32 (artifactpb .FileProcessStatus_FILE_PROCESS_STATUS_NOTSTARTED )],
197+ Size : object .Size ,
198+ ExternalMetadataUnmarshal : req .File .ExternalMetadata ,
199+ }
200+
201+ // create catalog file in database
202+ res , err = ph .service .Repository .CreateKnowledgeBaseFile (ctx , kbFile , nil )
203+
204+ if err != nil {
205+ log .Error ("failed to create catalog file" , zap .Error (err ))
206+ return nil , err
207+ }
208+
209+ // increase catalog usage. need to increase after the file is created.
210+ // Note: in the future, we need to increase the usage in transaction with creating the file.
211+ err = ph .service .Repository .IncreaseKnowledgeBaseUsage (ctx , nil , kb .UID .String (), int (object .Size ))
212+ if err != nil {
213+ log .Error ("failed to increase catalog usage" , zap .Error (err ))
214+ return nil , err
215+ }
216+ }
157217 return & artifactpb.UploadCatalogFileResponse {
158218 File : & artifactpb.File {
159219 FileUid : res .UID .String (),
@@ -169,6 +229,7 @@ func (ph *PublicHandler) UploadCatalogFile(ctx context.Context, req *artifactpb.
169229 TotalChunks : 0 ,
170230 TotalTokens : 0 ,
171231 ExternalMetadata : res .ExternalMetadataUnmarshal ,
232+ ObjectUid : req .File .ObjectUid ,
172233 },
173234 }, nil
174235}
@@ -204,20 +265,23 @@ func getFileSize(base64String string) (int64, string) {
204265 return int64 (decodedSize ), fmt .Sprintf ("%.1f %cB" , size , "KMGTPE" [exp ])
205266}
206267
207- func checkUploadKnowledgeBaseFileRequest (req * artifactpb.UploadCatalogFileRequest ) error {
268+ // Check if objectUID is provided, and all other required fields if not
269+ func checkUploadKnowledgeBaseFileRequest (req * artifactpb.UploadCatalogFileRequest ) (bool , error ) {
208270 if req .GetNamespaceId () == "" {
209- return fmt .Errorf ("owner uid is required. err: %w" , ErrCheckRequiredFields )
271+ return false , fmt .Errorf ("owner uid is required. err: %w" , ErrCheckRequiredFields )
210272 } else if req .CatalogId == "" {
211- return fmt .Errorf ("catalog uid is required. err: %w" , ErrCheckRequiredFields )
273+ return false , fmt .Errorf ("catalog uid is required. err: %w" , ErrCheckRequiredFields )
212274 } else if req .File == nil {
213- return fmt .Errorf ("file is required. err: %w" , ErrCheckRequiredFields )
275+ return false , fmt .Errorf ("file is required. err: %w" , ErrCheckRequiredFields )
276+ } else if req .File .GetObjectUid () != "" {
277+ return true , nil
214278 } else if req .File .Name == "" {
215- return fmt .Errorf ("file name is required. err: %w" , ErrCheckRequiredFields )
279+ return false , fmt .Errorf ("file name is required. err: %w" , ErrCheckRequiredFields )
216280 } else if req .File .Content == "" {
217- return fmt .Errorf ("file content is required. err: %w" , ErrCheckRequiredFields )
281+ return false , fmt .Errorf ("file content is required. err: %w" , ErrCheckRequiredFields )
218282 }
219283
220- return nil
284+ return false , nil
221285}
222286
223287// MoveFileToCatalog moves a file from one catalog to another within the same namespace.
@@ -394,6 +458,9 @@ func (ph *PublicHandler) ListCatalogFiles(ctx context.Context, req *artifactpb.L
394458 totalSize = size
395459 nextPageToken = nextToken
396460 for _ , kbFile := range kbFiles {
461+
462+ objectUID := uuid .FromStringOrNil (strings .TrimPrefix (strings .Split (kbFile .Destination , "/" )[1 ], "obj-" ))
463+
397464 files = append (files , & artifactpb.File {
398465 FileUid : kbFile .UID .String (),
399466 OwnerUid : kbFile .Owner .String (),
@@ -408,6 +475,7 @@ func (ph *PublicHandler) ListCatalogFiles(ctx context.Context, req *artifactpb.L
408475 ExternalMetadata : kbFile .ExternalMetadataUnmarshal ,
409476 TotalChunks : int32 (totalChunks [kbFile .UID ]),
410477 TotalTokens : int32 (totalTokens [kbFile .UID ]),
478+ ObjectUid : objectUID .String (),
411479 })
412480 }
413481 }
@@ -614,6 +682,9 @@ func (ph *PublicHandler) ProcessCatalogFiles(ctx context.Context, req *artifactp
614682 // populate the files into response
615683 var resFiles []* artifactpb.File
616684 for _ , file := range files {
685+
686+ objectUID := uuid .FromStringOrNil (strings .TrimPrefix (strings .Split (file .Destination , "/" )[1 ], "obj-" ))
687+
617688 resFiles = append (resFiles , & artifactpb.File {
618689 FileUid : file .UID .String (),
619690 OwnerUid : file .Owner .String (),
@@ -624,6 +695,7 @@ func (ph *PublicHandler) ProcessCatalogFiles(ctx context.Context, req *artifactp
624695 CreateTime : timestamppb .New (* file .CreateTime ),
625696 UpdateTime : timestamppb .New (* file .UpdateTime ),
626697 ProcessStatus : artifactpb .FileProcessStatus (artifactpb .FileProcessStatus_value [file .ProcessStatus ]),
698+ ObjectUid : objectUID .String (),
627699 })
628700 }
629701 return & artifactpb.ProcessCatalogFilesResponse {
0 commit comments