@@ -4,6 +4,10 @@ const { Result } = require("./types");
44const { RepositoryOps } = require ( "./operations" ) ;
55const g_lib = require ( "../support" ) ;
66
7+ // Define error code constant if not available from g_lib
8+ const ERR_INVALID_PARAM = g_lib . ERR_INVALID_PARAM !== undefined ? g_lib . ERR_INVALID_PARAM : 2 ;
9+ const ERR_INVALID_OPERATION = g_lib . ERR_INVALID_OPERATION !== undefined ? g_lib . ERR_INVALID_OPERATION : 400 ;
10+
711/**
812 * Standalone validation functions following Rust patterns
913 * Pure functions that return Result types for error handling
@@ -20,7 +24,7 @@ const g_lib = require("../support");
2024const validateNonEmptyString = ( value , fieldName ) => {
2125 if ( ! value || typeof value !== "string" || value . trim ( ) === "" ) {
2226 return Result . err ( {
23- code : g_lib . ERR_INVALID_PARAM ,
27+ code : ERR_INVALID_PARAM ,
2428 message : `${ fieldName } is required and must be a non-empty string` ,
2529 } ) ;
2630 }
@@ -46,15 +50,17 @@ const validateCommonFields = (config) => {
4650 errors . push ( "Repository capacity must be a positive number" ) ;
4751 }
4852
49- if ( ! Array . isArray ( config . admins ) || config . admins . length === 0 ) {
53+ // Check for both 'admin' and 'admins' fields for backward compatibility
54+ const adminField = config . admins || config . admin ;
55+ if ( ! Array . isArray ( adminField ) || adminField . length === 0 ) {
5056 errors . push ( "Repository must have at least one admin" ) ;
5157 }
5258
5359 if ( errors . length > 0 ) {
5460 // See: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#propagating-errors
5561 // Early return with error - similar to Rust's ? operator
5662 return Result . err ( {
57- code : g_lib . ERR_INVALID_PARAM ,
63+ code : ERR_INVALID_PARAM ,
5864 message : errors . join ( "; " ) ,
5965 } ) ;
6066 }
@@ -66,22 +72,22 @@ const validateCommonFields = (config) => {
6672const validatePOSIXPath = ( path , fieldName ) => {
6773 if ( ! path || typeof path !== "string" ) {
6874 return Result . err ( {
69- code : g_lib . ERR_INVALID_PARAM ,
75+ code : ERR_INVALID_PARAM ,
7076 message : `${ fieldName } must be a non-empty string` ,
7177 } ) ;
7278 }
7379
7480 if ( ! path . startsWith ( "/" ) ) {
7581 return Result . err ( {
76- code : g_lib . ERR_INVALID_PARAM ,
82+ code : ERR_INVALID_PARAM ,
7783 message : `${ fieldName } must be an absolute path (start with '/')` ,
7884 } ) ;
7985 }
8086
8187 // Check for invalid characters in path
8288 if ( path . includes ( ".." ) || path . includes ( "//" ) ) {
8389 return Result . err ( {
84- code : g_lib . ERR_INVALID_PARAM ,
90+ code : ERR_INVALID_PARAM ,
8591 message : `${ fieldName } contains invalid path sequences` ,
8692 } ) ;
8793 }
@@ -105,7 +111,7 @@ const validateRepositoryPath = (path, repoId) => {
105111
106112 if ( lastComponent !== repoId ) {
107113 return Result . err ( {
108- code : g_lib . ERR_INVALID_PARAM ,
114+ code : ERR_INVALID_PARAM ,
109115 message : `Repository path must end with repository ID (${ repoId } )` ,
110116 } ) ;
111117 }
@@ -115,7 +121,13 @@ const validateRepositoryPath = (path, repoId) => {
115121
116122// Validate Globus-specific configuration
117123const validateGlobusConfig = ( config ) => {
118- const commonResult = validateCommonFields ( config ) ;
124+ // Normalize admin/admins field for backward compatibility
125+ const normalizedConfig = { ...config } ;
126+ if ( config . admin && ! config . admins ) {
127+ normalizedConfig . admins = config . admin ;
128+ }
129+
130+ const commonResult = validateCommonFields ( normalizedConfig ) ;
119131 if ( ! commonResult . ok ) {
120132 return commonResult ;
121133 }
@@ -140,7 +152,7 @@ const validateGlobusConfig = (config) => {
140152
141153 if ( errors . length > 0 ) {
142154 return Result . err ( {
143- code : g_lib . ERR_INVALID_PARAM ,
155+ code : ERR_INVALID_PARAM ,
144156 message : errors . join ( "; " ) ,
145157 } ) ;
146158 }
@@ -164,7 +176,13 @@ const validateGlobusConfig = (config) => {
164176
165177// Validate metadata-only repository configuration
166178const validateMetadataConfig = ( config ) => {
167- const commonResult = validateCommonFields ( config ) ;
179+ // Normalize admin/admins field for backward compatibility
180+ const normalizedConfig = { ...config } ;
181+ if ( config . admin && ! config . admins ) {
182+ normalizedConfig . admins = config . admin ;
183+ }
184+
185+ const commonResult = validateCommonFields ( normalizedConfig ) ;
168186 if ( ! commonResult . ok ) {
169187 return commonResult ;
170188 }
@@ -176,7 +194,7 @@ const validateMetadataConfig = (config) => {
176194
177195 if ( presentInvalidFields . length > 0 ) {
178196 return Result . err ( {
179- code : g_lib . ERR_INVALID_PARAM ,
197+ code : ERR_INVALID_PARAM ,
180198 message : `Metadata-only repositories should not have: ${ presentInvalidFields . join ( ", " ) } ` ,
181199 } ) ;
182200 }
@@ -203,7 +221,7 @@ const validateAllocationParams = (params) => {
203221
204222 if ( errors . length > 0 ) {
205223 return Result . err ( {
206- code : g_lib . ERR_INVALID_PARAM ,
224+ code : ERR_INVALID_PARAM ,
207225 message : errors . join ( "; " ) ,
208226 } ) ;
209227 }
@@ -222,7 +240,7 @@ const validateRepositorySupportsDataOperations = (repoId, dataId, errorMessage)
222240 const defaultMessage =
223241 errorMessage || `Data operations not supported for ${ repository . type } repository` ;
224242 throw [
225- g_lib . ERR_INVALID_OPERATION ,
243+ ERR_INVALID_OPERATION ,
226244 defaultMessage ,
227245 {
228246 repo_type : repository . type ,
@@ -234,12 +252,90 @@ const validateRepositorySupportsDataOperations = (repoId, dataId, errorMessage)
234252 }
235253} ;
236254
255+ // Validate partial Globus configuration (for updates)
256+ const validatePartialGlobusConfig = ( config , repoId ) => {
257+ // For partial updates, we don't require all fields
258+ // Only validate the fields that are provided
259+ const errors = [ ] ;
260+
261+ // Normalize admin/admins field for backward compatibility
262+ const normalizedConfig = { ...config } ;
263+ if ( config . admin && ! config . admins ) {
264+ normalizedConfig . admins = config . admin ;
265+ }
266+
267+ // Validate provided fields
268+ if ( normalizedConfig . title !== undefined ) {
269+ const titleValidation = validateNonEmptyString ( normalizedConfig . title , "Repository title" ) ;
270+ if ( ! titleValidation . ok ) {
271+ errors . push ( titleValidation . error . message ) ;
272+ }
273+ }
274+
275+ if ( normalizedConfig . capacity !== undefined ) {
276+ if ( typeof normalizedConfig . capacity !== "number" || normalizedConfig . capacity <= 0 ) {
277+ errors . push ( "Repository capacity must be a positive number" ) ;
278+ }
279+ }
280+
281+ if ( normalizedConfig . admins !== undefined ) {
282+ if ( ! Array . isArray ( normalizedConfig . admins ) || normalizedConfig . admins . length === 0 ) {
283+ errors . push ( "Repository must have at least one admin" ) ;
284+ }
285+ }
286+
287+ if ( normalizedConfig . pub_key !== undefined ) {
288+ const pubKeyValidation = validateNonEmptyString ( normalizedConfig . pub_key , "Public key" ) ;
289+ if ( ! pubKeyValidation . ok ) {
290+ errors . push ( pubKeyValidation . error . message ) ;
291+ }
292+ }
293+
294+ if ( normalizedConfig . address !== undefined ) {
295+ const addressValidation = validateNonEmptyString ( normalizedConfig . address , "Address" ) ;
296+ if ( ! addressValidation . ok ) {
297+ errors . push ( addressValidation . error . message ) ;
298+ }
299+ }
300+
301+ if ( normalizedConfig . endpoint !== undefined ) {
302+ const endpointValidation = validateNonEmptyString ( normalizedConfig . endpoint , "Endpoint" ) ;
303+ if ( ! endpointValidation . ok ) {
304+ errors . push ( endpointValidation . error . message ) ;
305+ }
306+ }
307+
308+ if ( normalizedConfig . path !== undefined && repoId ) {
309+ const pathResult = validateRepositoryPath ( normalizedConfig . path , repoId ) ;
310+ if ( ! pathResult . ok ) {
311+ return pathResult ;
312+ }
313+ }
314+
315+ if ( normalizedConfig . exp_path !== undefined ) {
316+ const expPathResult = validatePOSIXPath ( normalizedConfig . exp_path , "Export path" ) ;
317+ if ( ! expPathResult . ok ) {
318+ return expPathResult ;
319+ }
320+ }
321+
322+ if ( errors . length > 0 ) {
323+ return Result . err ( {
324+ code : ERR_INVALID_PARAM ,
325+ message : errors . join ( "; " ) ,
326+ } ) ;
327+ }
328+
329+ return Result . ok ( true ) ;
330+ } ;
331+
237332module . exports = {
238333 validateNonEmptyString,
239334 validateCommonFields,
240335 validatePOSIXPath,
241336 validateRepositoryPath,
242337 validateGlobusConfig,
338+ validatePartialGlobusConfig,
243339 validateMetadataConfig,
244340 validateAllocationParams,
245341 validateRepositorySupportsDataOperations,
0 commit comments