-
Notifications
You must be signed in to change notification settings - Fork 16
[DAPS-1515] Integrate repository type system into core endpoints #1543
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
base: feat-DAPS-1513-rust-js-design
Are you sure you want to change the base?
Changes from all commits
1b8a7fc
4d37418
5caa3bf
d117b5a
66bdb31
90b0a2a
50be6a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,20 @@ const joi = require("joi"); | |
const g_db = require("@arangodb").db; | ||
const g_lib = require("./support"); | ||
const g_tasks = require("./tasks"); | ||
const { validateGlobusConfig, validatePartialGlobusConfig } = require("./repository/validation"); | ||
const { RepositoryOps } = require("./repository/operations"); | ||
|
||
// Helper function to prepare repository data for saving | ||
const prepareRepoData = (obj) => { | ||
// Ensure paths end with / for saving | ||
if (obj.path && !obj.path.endsWith("/")) { | ||
obj.path += "/"; | ||
} | ||
if (obj.exp_path && !obj.exp_path.endsWith("/")) { | ||
obj.exp_path += "/"; | ||
} | ||
return obj; | ||
}; | ||
|
||
module.exports = router; | ||
|
||
|
@@ -121,28 +135,31 @@ router | |
g_lib.procInputParam(req.body, "summary", false, obj); | ||
g_lib.procInputParam(req.body, "domain", false, obj); | ||
|
||
if (!obj.path.startsWith("/")) | ||
throw [ | ||
g_lib.ERR_INVALID_PARAM, | ||
"Repository path must be an absolute path file system path.", | ||
]; | ||
|
||
if (!obj.path.endsWith("/")) obj.path += "/"; | ||
|
||
var idx = obj.path.lastIndexOf("/", obj.path.length - 2); | ||
if (obj.path.substr(idx + 1, obj.path.length - idx - 2) != obj._key) | ||
throw [ | ||
g_lib.ERR_INVALID_PARAM, | ||
"Last part of repository path must be repository ID suffix (" + | ||
obj._key + | ||
")", | ||
]; | ||
Comment on lines
-133
to
-139
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is contained in the validation.js file, in the validateRepositoryPath function. |
||
|
||
if (req.body.exp_path) { | ||
obj.exp_path = req.body.exp_path; | ||
if (!obj.exp_path.endsWith("/")) obj.path += "/"; | ||
} | ||
|
||
// Validate the configuration | ||
const validationResult = validateGlobusConfig({ | ||
id: obj._key, | ||
title: obj.title, | ||
capacity: obj.capacity, | ||
admins: req.body.admins, | ||
pub_key: obj.pub_key, | ||
address: obj.address, | ||
endpoint: obj.endpoint, | ||
domain: obj.domain, | ||
path: obj.path, | ||
exp_path: obj.exp_path, | ||
}); | ||
|
||
if (!validationResult.ok) { | ||
throw [validationResult.error.code, validationResult.error.message]; | ||
} | ||
|
||
// Prepare repository data for saving | ||
prepareRepoData(obj); | ||
|
||
var repo = g_db.repo.save(obj, { | ||
returnNew: true, | ||
}); | ||
|
@@ -211,40 +228,41 @@ router | |
g_lib.procInputParam(req.body, "summary", true, obj); | ||
g_lib.procInputParam(req.body, "domain", true, obj); | ||
|
||
if (req.body.path) { | ||
if (!req.body.path.startsWith("/")) | ||
throw [ | ||
g_lib.ERR_INVALID_PARAM, | ||
"Repository path must be an absolute path file system path.", | ||
]; | ||
|
||
obj.path = req.body.path; | ||
if (!obj.path.endsWith("/")) obj.path += "/"; | ||
|
||
// Last part of storage path MUST end with the repo ID | ||
var idx = obj.path.lastIndexOf("/", obj.path.length - 2); | ||
var key = req.body.id.substr(5); | ||
if (obj.path.substr(idx + 1, obj.path.length - idx - 2) != key) | ||
throw [ | ||
g_lib.ERR_INVALID_PARAM, | ||
"Last part of repository path must be repository ID suffix (" + | ||
key + | ||
")", | ||
]; | ||
} | ||
if (req.body.path) obj.path = req.body.path; | ||
if (req.body.exp_path) obj.exp_path = req.body.exp_path; | ||
if (req.body.capacity) obj.capacity = req.body.capacity; | ||
if (req.body.pub_key) obj.pub_key = req.body.pub_key; | ||
if (req.body.address) obj.address = req.body.address; | ||
if (req.body.endpoint) obj.endpoint = req.body.endpoint; | ||
|
||
if (req.body.exp_path) { | ||
obj.exp_path = req.body.exp_path; | ||
if (!obj.exp_path.endsWith("/")) obj.exp_path += "/"; | ||
} | ||
// Extract repo key from ID for validation | ||
const key = req.body.id.substr(5); | ||
|
||
if (req.body.capacity) obj.capacity = req.body.capacity; | ||
// Validate the partial configuration | ||
const updateConfig = { | ||
title: req.body.title, | ||
domain: req.body.domain, | ||
path: req.body.path, | ||
exp_path: req.body.exp_path, | ||
capacity: req.body.capacity, | ||
pub_key: req.body.pub_key, | ||
address: req.body.address, | ||
endpoint: req.body.endpoint, | ||
admins: req.body.admins, | ||
}; | ||
|
||
if (req.body.pub_key) obj.pub_key = req.body.pub_key; | ||
// Remove undefined fields | ||
Object.keys(updateConfig).forEach( | ||
(k) => updateConfig[k] === undefined && delete updateConfig[k], | ||
); | ||
|
||
if (req.body.address) obj.address = req.body.address; | ||
const validationResult = validatePartialGlobusConfig(updateConfig, key); | ||
if (!validationResult.ok) { | ||
throw [validationResult.error.code, validationResult.error.message]; | ||
} | ||
|
||
if (req.body.endpoint) obj.endpoint = req.body.endpoint; | ||
// Prepare repository data for saving | ||
prepareRepoData(obj); | ||
|
||
var repo = g_db._update(req.body.id, obj, { | ||
returnNew: true, | ||
|
@@ -672,15 +690,37 @@ router | |
subject_id = req.queryParams.subject; | ||
else subject_id = g_lib.getUserFromClientID(req.queryParams.subject)._id; | ||
|
||
var result = g_tasks.taskInitAllocCreate( | ||
client, | ||
req.queryParams.repo, | ||
subject_id, | ||
req.queryParams.data_limit, | ||
req.queryParams.rec_limit, | ||
// Find the repository using the new type system | ||
const findResult = RepositoryOps.find(req.queryParams.repo); | ||
if (!findResult.ok) { | ||
throw [findResult.error.code, findResult.error.message]; | ||
} | ||
|
||
const repository = findResult.value; | ||
|
||
// Check permissions | ||
const permResult = RepositoryOps.checkPermission( | ||
repository, | ||
client._id, | ||
"admin", | ||
); | ||
if (!permResult.ok || !permResult.value) { | ||
throw g_lib.ERR_PERM_DENIED; | ||
} | ||
|
||
res.send(result); | ||
// Create allocation using the new system | ||
const allocResult = RepositoryOps.createAllocation(repository, { | ||
subject: subject_id, | ||
size: req.queryParams.data_limit, | ||
rec_limit: req.queryParams.rec_limit, | ||
}); | ||
|
||
if (!allocResult.ok) { | ||
throw [allocResult.error.code, allocResult.error.message]; | ||
} | ||
|
||
// Return the new response format | ||
res.send(allocResult.value); | ||
}, | ||
}); | ||
} catch (e) { | ||
|
@@ -702,7 +742,7 @@ router | |
) | ||
.summary("Create user/project repo allocation") | ||
.description( | ||
"Create user repo/project allocation. Only repo admin can set allocations. Returns a task document.", | ||
"Create user repo/project allocation. Only repo admin can set allocations. Returns either a task (for Globus repos) or direct result (for metadata-only repos).", | ||
); | ||
|
||
router | ||
|
@@ -722,13 +762,34 @@ router | |
subject_id = req.queryParams.subject; | ||
else subject_id = g_lib.getUserFromClientID(req.queryParams.subject)._id; | ||
|
||
var result = g_tasks.taskInitAllocDelete( | ||
client, | ||
req.queryParams.repo, | ||
subject_id, | ||
); | ||
// Find the repository using the new type system | ||
var findResult = RepositoryOps.find(req.queryParams.repo); | ||
if (!findResult.ok) { | ||
throw [findResult.error.code, findResult.error.message]; | ||
} | ||
|
||
var repository = findResult.value; | ||
|
||
// Check permissions | ||
var permResult = RepositoryOps.checkPermission(repository, client._id, "admin"); | ||
if (!permResult.ok || !permResult.value) { | ||
throw g_lib.ERR_PERM_DENIED; | ||
} | ||
|
||
// Check if subject exists | ||
if (!g_db._exists(subject_id)) { | ||
throw [g_lib.ERR_NOT_FOUND, "Subject not found: " + subject_id]; | ||
Comment on lines
+775
to
+781
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be clearer if we include in the exeception, that the allocation delete request failed, for audit reasons, in cases around authorization it is really useful to know who attempted to do what. |
||
} | ||
|
||
// Delete allocation using the new system | ||
var deleteResult = RepositoryOps.deleteAllocation(repository, subject_id); | ||
AronPerez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if (!deleteResult.ok) { | ||
throw [deleteResult.error.code, deleteResult.error.message]; | ||
} | ||
|
||
res.send(result); | ||
// Return the new response format | ||
res.send(deleteResult.value); | ||
}, | ||
}); | ||
} catch (e) { | ||
|
@@ -740,7 +801,7 @@ router | |
.queryParam("repo", joi.string().required(), "Repo ID") | ||
.summary("Delete user/project repo allocation") | ||
.description( | ||
"Delete user repo/project allocation. Only repo admin can set allocations. Returns a task document.", | ||
"Delete user repo/project allocation. Only repo admin can set allocations. Returns either a task (for Globus repos) or direct result (for metadata-only repos).", | ||
); | ||
|
||
router | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are making sure that the .path ends with "/", in the original code, it is also checking to make sure that it begins with "/". Is that check being done somewhere else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see it is in the validation.js file.