diff --git a/api-docs/openapi.json b/api-docs/openapi.json
index 6a5872063..83e6177e0 100644
--- a/api-docs/openapi.json
+++ b/api-docs/openapi.json
@@ -2605,7 +2605,7 @@
"Registry Organization"
],
"summary": "Updates information about the organization specified by short name (accessible Temporarily to Secretariat only)",
- "description": "
Access Control
User must belong to an organization with the Secretariat role temporarily.
In the future, only the organization's admin will be able to request changes to its information.
With Joint Approval required for the following fields:
Expected Behavior
This endpoint expects a full organization object in the request body. Secretariat: Updates any organization's information
Organization Admin: Requests changes to its organization's information
- short_name
- long_name
- authority
- aliases
- oversees
- top_level_root
- charter_or_scope
- product_list
- disclosure_policy
- contact_info.poc
- contact_info.poc_email
- contact_info.poc_phone
- contact_info.org_email
- partner_role_type
- partner_country
- advisory_locations
- industry
- tl_root_start_date
- is_cna_discussion_list
",
+ "description": " Access Control
User must belong to an organization with the Secretariat role temporarily.
In the future, only the organization's admin will be able to request changes to its information.
With Joint Approval required for the following fields:
Expected Behavior
This endpoint expects a full organization object in the request body. Secretariat: Updates any organization's information
Organization Admin: Requests changes to its organization's information
- short_name
- long_name
- authority
- aliases
- oversees
- top_level_root
- charter_or_scope
- product_list
- disclosure_policy
- contact_info.websites
- contact_info.emails
- contact_info.phone
- partner_role_type
- partner_country
- advisory_locations
- industry
- tl_root_start_date
- is_cna_discussion_list
",
"operationId": "orgUpdateSingle",
"parameters": [
{
diff --git a/datadump/pre-population/glossary.json b/datadump/pre-population/glossary.json
index ac9ccc4e7..10ee659ce 100644
--- a/datadump/pre-population/glossary.json
+++ b/datadump/pre-population/glossary.json
@@ -1,7 +1,83 @@
[
- {
- "services_short_name": "long_name",
- "label": "Long Name",
- "def": "The full, official name of an organization participating in the CVE program."
- }
-]
+ {
+ "services_short_name": "long_name",
+ "label": "Long Name",
+ "def": "Partner long name displayed on the Partners list on website"
+ },
+ {
+ "services_short_name": "partner_number",
+ "label": "Partner Number",
+ "def": "Unique Identifier that provides insight into when the partner joined the program (used for reporting and website updates)"
+ },
+ {
+ "services_short_name": "short_name",
+ "label": "Short Name",
+ "def": "Partner short name, computer readable name, used for API requests and posted with the CVE record."
+ },
+ {
+ "services_short_name": "status",
+ "label": "Status",
+ "def": "Partner status"
+ },
+ {
+ "services_short_name": "authority",
+ "label": "Authority",
+ "def": "Provides the type of partner."
+ },
+ {
+ "services_short_name": "website_update_date",
+ "label": "CVE Website Update Date",
+ "def": "Date Partner information was last updated on the website."
+ },
+ {
+ "services_short_name": "cve_website_update_needed",
+ "label": "CVE Website Update Needed",
+ "def": "Tracks if partner information updates are completed or pending."
+ },
+ {
+ "services_short_name": "top_level_root",
+ "label": "Top Level Root",
+ "def": "Provides the CNA Top Level Root."
+ },
+ {
+ "services_short_name": "reports_to",
+ "label": "Reports To",
+ "def": "Provides who the partner reports to."
+ },
+ {
+ "services_short_name": "partner_country",
+ "label": "Partner Country",
+ "def": "Partner country that is self identified."
+ },
+ {
+ "services_short_name": "partner_active_date",
+ "label": "Partner Active Date",
+ "def": "Date the partner joined the program."
+ },
+ {
+ "services_short_name": "partner_inactive_date",
+ "label": "Partner Inactive Date",
+ "def": "Date the partner was removed from the program."
+ },
+ {
+ "services_short_name": "charter_or_scope",
+ "label": "Charter or Scope",
+ "def": "Partner charter or scope."
+ },
+ {
+ "services_short_name": "disclosure_policy",
+ "label": "Disclosure Policy",
+ "def": "Partner disclosure policy."
+ },
+ {
+ "services_short_name": "advisory_location",
+ "label": "Advisory Location",
+ "def": "Partner vulnerability advisory locations."
+ },
+ {
+ "services_short_name": "vulnerability_advisory_location_for_web_scraping",
+ "label": "Vulnerability Advisory Locations for Web Scraping.",
+ "def": "Partner vulnerability advisory location for web scraping."
+ }
+ ]
+
diff --git a/schemas/registry-org/BaseOrg.json b/schemas/registry-org/BaseOrg.json
index d47c19729..f1e8ef02f 100644
--- a/schemas/registry-org/BaseOrg.json
+++ b/schemas/registry-org/BaseOrg.json
@@ -140,19 +140,24 @@
"contact_info": {
"type": "object",
"properties": {
- "phone": {
- "type": "string"
- },
- "poc": {
- "type": "string"
+ "websites": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uri"
+ },
+ "uniqueItems": true
},
- "poc_email": {
- "type": "string",
- "format": "email"
+ "emails": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "email"
+ },
+ "uniqueItems": true
},
- "website": {
- "type": "string",
- "format": "uri"
+ "phone": {
+ "type": "string"
}
},
"additionalProperties": false
diff --git a/schemas/registry-org/CNAOrg.json b/schemas/registry-org/CNAOrg.json
index 0b86c1a9a..bdcfedc85 100644
--- a/schemas/registry-org/CNAOrg.json
+++ b/schemas/registry-org/CNAOrg.json
@@ -45,16 +45,23 @@
"contact_info": {
"type": "object",
"properties": {
- "phone": {
- "type": "string"
- },
- "poc": {
- "type": "string"
+ "websites": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uri"
+ },
+ "uniqueItems": true
},
- "poc_email": {
- "type": "string"
+ "emails": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "email"
+ },
+ "uniqueItems": true
},
- "website": {
+ "phone": {
"type": "string"
}
},
@@ -136,4 +143,4 @@
"short_name",
"hard_quota"
]
-}
\ No newline at end of file
+}
diff --git a/schemas/registry-org/RootOrg.json b/schemas/registry-org/RootOrg.json
index d4c090444..aef1f5494 100644
--- a/schemas/registry-org/RootOrg.json
+++ b/schemas/registry-org/RootOrg.json
@@ -6,16 +6,24 @@
"description": "Schema for a CVE Root Organization",
"additionalProperties": false,
"properties": {
- "UUID": { "$ref": "/BaseOrg#/definitions/uuidType" },
- "short_name": { "$ref": "/BaseOrg#/definitions/shortName" },
- "long_name": { "$ref": "/BaseOrg#/definitions/longName" },
+ "UUID": {
+ "$ref": "/BaseOrg#/definitions/uuidType"
+ },
+ "short_name": {
+ "$ref": "/BaseOrg#/definitions/shortName"
+ },
+ "long_name": {
+ "$ref": "/BaseOrg#/definitions/longName"
+ },
"new_short_name": {
"description": "Used to rename an organization's short name during an update.",
"type": "string",
"minLength": 2,
"maxLength": 32
},
- "aliases": { "$ref": "/BaseOrg#/properties/aliases" },
+ "aliases": {
+ "$ref": "/BaseOrg#/properties/aliases"
+ },
"private_contacts": {
"type": "array",
"items": {
@@ -37,11 +45,25 @@
"contact_info": {
"type": "object",
"properties": {
- "poc": { "type": "string" },
- "poc_email": { "type": "string" },
- "poc_phone": { "type": "string" },
- "org_email": { "type": "string" },
- "website": { "type": "string" }
+ "websites": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uri"
+ },
+ "uniqueItems": true
+ },
+ "emails": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "email"
+ },
+ "uniqueItems": true
+ },
+ "phone": {
+ "type": "string"
+ }
},
"additionalProperties": false
},
@@ -68,10 +90,20 @@
"partner_country": {
"type": "string"
},
- "advisory_locations": { "$ref": "/BaseOrg#/properties/advisory_locations" },
- "program_data": { "$ref": "/BaseOrg#/properties/program_data" },
- "industry": { "$ref": "/BaseOrg#/properties/industry" },
- "top_level_root": { "$ref": "/BaseOrg#/properties/top_level_root" }
+ "advisory_locations": {
+ "$ref": "/BaseOrg#/properties/advisory_locations"
+ },
+ "program_data": {
+ "$ref": "/BaseOrg#/properties/program_data"
+ },
+ "industry": {
+ "$ref": "/BaseOrg#/properties/industry"
+ },
+ "top_level_root": {
+ "$ref": "/BaseOrg#/properties/top_level_root"
+ }
},
- "required": ["short_name"]
+ "required": [
+ "short_name"
+ ]
}
diff --git a/schemas/registry-org/create-registry-org-request.json b/schemas/registry-org/create-registry-org-request.json
index 718778634..cfa8b9f09 100644
--- a/schemas/registry-org/create-registry-org-request.json
+++ b/schemas/registry-org/create-registry-org-request.json
@@ -85,26 +85,27 @@
"contact_info": {
"type": "object",
"properties": {
- "phone": {
- "type": "string"
- },
- "poc": {
- "type": "string"
+ "websites": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uri"
+ },
+ "uniqueItems": true
},
- "poc_email": {
- "type": "string",
- "format": "email"
+ "emails": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "email"
+ },
+ "uniqueItems": true
},
- "website": {
- "type": "string",
- "format": "uri"
+ "phone": {
+ "type": "string"
}
},
- "required": [
- "poc",
- "poc_email",
- "admins"
- ]
+ "additionalProperties": false
},
"advisory_locations": {
"type": "array",
@@ -190,4 +191,4 @@
"authority",
"long_name"
]
-}
\ No newline at end of file
+}
diff --git a/schemas/registry-org/create-registry-org-response.json b/schemas/registry-org/create-registry-org-response.json
index 9c8cb073e..a8ef091f1 100644
--- a/schemas/registry-org/create-registry-org-response.json
+++ b/schemas/registry-org/create-registry-org-response.json
@@ -126,26 +126,27 @@
"contact_info": {
"type": "object",
"properties": {
- "phone": {
- "type": "string"
- },
- "poc": {
- "type": "string"
+ "websites": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uri"
+ },
+ "uniqueItems": true
},
- "poc_email": {
- "type": "string",
- "format": "email"
+ "emails": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "email"
+ },
+ "uniqueItems": true
},
- "website": {
- "type": "string",
- "format": "uri"
+ "phone": {
+ "type": "string"
}
},
- "required": [
- "poc",
- "poc_email",
- "admins"
- ]
+ "additionalProperties": false
},
"advisory_locations": {
"type": "array",
@@ -184,4 +185,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/schemas/registry-org/get-registry-org-response.json b/schemas/registry-org/get-registry-org-response.json
index 121ec7899..a847dc290 100644
--- a/schemas/registry-org/get-registry-org-response.json
+++ b/schemas/registry-org/get-registry-org-response.json
@@ -91,25 +91,27 @@
"contact_info": {
"type": "object",
"properties": {
- "phone": {
- "type": "string"
- },
- "poc": {
- "type": "string"
+ "websites": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uri"
+ },
+ "uniqueItems": true
},
- "poc_email": {
- "type": "string",
- "format": "email"
+ "emails": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "email"
+ },
+ "uniqueItems": true
},
- "website": {
- "type": "string",
- "format": "uri"
+ "phone": {
+ "type": "string"
}
},
- "required": [
- "poc",
- "poc_email"
- ]
+ "additionalProperties": false
},
"partner_role_type": {
"$ref": "/BaseOrg#/definitions/partnerRoleType"
@@ -224,4 +226,4 @@
"description": "List of conversation messages associated with the organization"
}
}
-}
\ No newline at end of file
+}
diff --git a/schemas/registry-org/list-registry-orgs-response.json b/schemas/registry-org/list-registry-orgs-response.json
index fa6d832de..78b9f215c 100644
--- a/schemas/registry-org/list-registry-orgs-response.json
+++ b/schemas/registry-org/list-registry-orgs-response.json
@@ -120,25 +120,27 @@
"contact_info": {
"type": "object",
"properties": {
- "phone": {
- "type": "string"
- },
- "poc": {
- "type": "string"
+ "websites": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uri"
+ },
+ "uniqueItems": true
},
- "poc_email": {
- "type": "string",
- "format": "email"
+ "emails": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "email"
+ },
+ "uniqueItems": true
},
- "website": {
- "type": "string",
- "format": "uri"
+ "phone": {
+ "type": "string"
}
},
- "required": [
- "poc",
- "poc_email"
- ]
+ "additionalProperties": false
},
"partner_role_type": {
"$ref": "/BaseOrg#/definitions/partnerRoleType"
@@ -256,4 +258,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/schemas/registry-org/update-registry-org-request.json b/schemas/registry-org/update-registry-org-request.json
index 456be9213..f171addee 100644
--- a/schemas/registry-org/update-registry-org-request.json
+++ b/schemas/registry-org/update-registry-org-request.json
@@ -101,21 +101,27 @@
"contact_info": {
"type": "object",
"properties": {
- "phone": {
- "type": "string"
- },
- "poc": {
- "type": "string"
+ "websites": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uri"
+ },
+ "uniqueItems": true
},
- "poc_email": {
- "type": "string",
- "format": "email"
+ "emails": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "email"
+ },
+ "uniqueItems": true
},
- "website": {
- "type": "string",
- "format": "uri"
+ "phone": {
+ "type": "string"
}
- }
+ },
+ "additionalProperties": false
},
"advisory_locations": {
"type": "array",
@@ -196,4 +202,4 @@
"description": "Additional partner metadata (restricted)"
}
}
-}
\ No newline at end of file
+}
diff --git a/schemas/registry-org/update-registry-org-response.json b/schemas/registry-org/update-registry-org-response.json
index 2a5e2cdcb..33a498cf7 100644
--- a/schemas/registry-org/update-registry-org-response.json
+++ b/schemas/registry-org/update-registry-org-response.json
@@ -115,26 +115,27 @@
"contact_info": {
"type": "object",
"properties": {
- "phone": {
- "type": "string"
- },
- "poc": {
- "type": "string"
+ "websites": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uri"
+ },
+ "uniqueItems": true
},
- "poc_email": {
- "type": "string",
- "format": "email"
+ "emails": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "email"
+ },
+ "uniqueItems": true
},
- "website": {
- "type": "string",
- "format": "uri"
+ "phone": {
+ "type": "string"
}
},
- "required": [
- "poc",
- "poc_email",
- "admins"
- ]
+ "additionalProperties": false
},
"advisory_locations": {
"type": "array",
@@ -173,4 +174,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/controller/audit.controller/audit.controller.js b/src/controller/audit.controller/audit.controller.js
index dc1c8c8a5..dd3103a2d 100644
--- a/src/controller/audit.controller/audit.controller.js
+++ b/src/controller/audit.controller/audit.controller.js
@@ -99,8 +99,7 @@ async function createAuditDocumentForOrg (req, res, next) {
audit_uuid: returnValue.uuid
})
} catch (err) {
- await session.abortTransaction()
- throw err
+ console.error('REAL ERROR WAS:', err.stack); try { await session.abortTransaction() } catch (e) {}; throw err
} finally {
await session.endSession()
}
diff --git a/src/controller/audit.controller/index.js b/src/controller/audit.controller/index.js
index 10da8f70f..07930c35c 100644
--- a/src/controller/audit.controller/index.js
+++ b/src/controller/audit.controller/index.js
@@ -29,14 +29,14 @@ router.get('/audit/org/document/:document_uuid',
// Get audit by org identifier (Secretariat or Admin)
router.get('/audit/org/:org_identifier',
mw.validateUser,
- mw.onlySecretariatOrAdmin,
+ mw.onlySecretariat,
auditMw.parseGetParams,
controller.AUDIT_GET_BY_ORG_IDENTIFIER
)
// Get last X changes (Secretariat or Org Admin)
router.get('/audit/org/:org_identifier/:number_of_changes',
- mw.onlySecretariatOrAdmin,
+ mw.onlySecretariat,
mw.validateUser,
auditMw.parseGetParams,
controller.AUDIT_GET_LAST
diff --git a/src/controller/glossary.controller/index.js b/src/controller/glossary.controller/index.js
index 8c374131b..6d097b5e3 100644
--- a/src/controller/glossary.controller/index.js
+++ b/src/controller/glossary.controller/index.js
@@ -2,17 +2,13 @@ const router = require('express').Router()
const controller = require('./glossary.controller')
const mw = require('../../middleware/middleware')
-// Get all glossary items - SEC only
+// Get all glossary items
router.get('/glossary',
/*
#swagger.tags = ['Glossary']
#swagger.operationId = 'glossaryAll'
- #swagger.summary = "Retrieves all glossary items (accessible to Secretariat only)"
- #swagger.description = "
- Access Control
- User must belong to an organization with the Secretariat role
- Expected Behavior
- Secretariat: Retrieves all glossary items
"
+ #swagger.summary = "Retrieves all glossary items"
+ #swagger.description = "Retrieves all glossary items
"
#swagger.parameters['$ref'] = [
'#/components/parameters/apiEntityHeader',
'#/components/parameters/apiUserHeader',
@@ -54,21 +50,16 @@ router.get('/glossary',
}
*/
mw.validateUser,
- mw.onlySecretariat,
controller.getAllGlossaryItems
)
-// Get glossary item by services_short_name - SEC only
+// Get glossary item by services_short_name
router.get('/glossary/:services_short_name',
/*
#swagger.tags = ['Glossary']
#swagger.operationId = 'glossarySingle'
- #swagger.summary = "Retrieves a single glossary item by its short name (accessible to Secretariat only)"
- #swagger.description = "
- Access Control
- User must belong to an organization with the Secretariat role
- Expected Behavior
- Secretariat: Retrieves the specified glossary item
"
+ #swagger.summary = "Retrieves a single glossary item by its short name"
+ #swagger.description = "Retrieves the specified glossary item
"
#swagger.parameters['services_short_name'] = { description: 'The short name of the glossary item' }
#swagger.parameters['$ref'] = [
'#/components/parameters/apiEntityHeader',
@@ -119,7 +110,6 @@ router.get('/glossary/:services_short_name',
}
*/
mw.validateUser,
- mw.onlySecretariat,
controller.getGlossaryItem
)
diff --git a/src/controller/org.controller/index.js b/src/controller/org.controller/index.js
index 1dd51a767..d69ae7c4a 100644
--- a/src/controller/org.controller/index.js
+++ b/src/controller/org.controller/index.js
@@ -552,10 +552,9 @@ router.put('/registry/org/:shortname',
charter_or_scope
product_list
disclosure_policy
- contact_info.poc
- contact_info.poc_email
- contact_info.poc_phone
- contact_info.org_email
+ contact_info.websites
+ contact_info.emails
+ contact_info.phone
partner_role_type
partner_country
advisory_locations
diff --git a/src/controller/org.controller/org.middleware.js b/src/controller/org.controller/org.middleware.js
index 1e986bb6e..931c01a5e 100644
--- a/src/controller/org.controller/org.middleware.js
+++ b/src/controller/org.controller/org.middleware.js
@@ -78,10 +78,9 @@ function validateCreateOrgParameters () {
'charter_or_scope',
'disclosure_policy',
'product_list',
- 'contact_info.poc',
- 'contact_info.poc_email',
+ 'contact_info.websites',
+ 'contact_info.emails',
'contact_info.phone',
- 'contact_info.website',
'',
'',
'partner_role_type',
@@ -136,16 +135,16 @@ function validateCreateOrgParameters () {
'aliases',
'hard_quota',
'contact_info.phone',
- 'contact_info.website',
+ 'contact_info.websites',
+ 'contact_info.emails',
'contact_info',
'users',
'charter_or_scope',
'disclosure_policy',
'product_list',
- 'contact_info.poc',
- 'contact_info.poc_email',
+ 'contact_info.websites',
+ 'contact_info.emails',
'contact_info.phone',
- 'contact_info.website',
'private_contacts',
'partner_role_type',
'partner_number',
@@ -231,10 +230,9 @@ function validateUpdateOrgParameters () {
'charter_or_scope',
'disclosure_policy',
'product_list',
- 'contact_info.poc',
- 'contact_info.poc_email',
+ 'contact_info.websites',
+ 'contact_info.emails',
'contact_info.phone',
- 'contact_info.website',
'',
'',
'partner_role_type',
@@ -325,10 +323,9 @@ const QUERY_PARAMETERS = {
'product_list',
'oversees',
'contact_info',
- 'contact_info.poc',
- 'contact_info.poc_email',
+ 'contact_info.websites',
+ 'contact_info.emails',
'contact_info.phone',
- 'contact_info.website',
'',
'',
'partner_role_type',
diff --git a/src/controller/registry-org.controller/registry-org.controller.js b/src/controller/registry-org.controller/registry-org.controller.js
index e66646d5a..d32c8577a 100644
--- a/src/controller/registry-org.controller/registry-org.controller.js
+++ b/src/controller/registry-org.controller/registry-org.controller.js
@@ -717,8 +717,9 @@ async function editConversationForOrg (req, res, next) {
// Make the edit
returnValue = await conversationRepo.editConversation(conversation.UUID, incomingParameters, { session })
- if (!isSecretariat && returnValue) {
+ if (!isSecretariat && returnValue && returnValue.author_role === 'Secretariat') {
delete returnValue.author_id
+ delete returnValue.author_name
}
await session.commitTransaction()
} catch (error) {
diff --git a/src/controller/registry-org.controller/registry-org.middleware.js b/src/controller/registry-org.controller/registry-org.middleware.js
index 939897911..88319d131 100644
--- a/src/controller/registry-org.controller/registry-org.middleware.js
+++ b/src/controller/registry-org.controller/registry-org.middleware.js
@@ -15,7 +15,7 @@ function parsePostParams (req, res, next) {
'top_level_root', 'users',
'charter_or_scope', 'disclosure_policy', 'product_list',
'soft_quota', 'hard_quota',
- 'private_contacts', 'contact_info.poc', 'contact_info.poc_email', 'contact_info.phone', 'contact_info.website',
+ 'private_contacts', 'contact_info.websites', 'contact_info.emails', 'contact_info.phone',
'partner_role_type',
'partner_number',
'partner_country',
diff --git a/src/controller/review-object.controller/index.js b/src/controller/review-object.controller/index.js
index daf8a7a74..8dfbecc01 100644
--- a/src/controller/review-object.controller/index.js
+++ b/src/controller/review-object.controller/index.js
@@ -146,7 +146,7 @@ router.get('/review/org/:identifier',
*/
mw.useRegistry(),
mw.validateUser,
- mw.onlySecretariat,
+ mw.onlySecretariatOrAdmin,
controller.getReviewObjectByOrgIdentifier
)
diff --git a/src/controller/review-object.controller/review-object.controller.js b/src/controller/review-object.controller/review-object.controller.js
index 7de67c58d..b30a17e94 100644
--- a/src/controller/review-object.controller/review-object.controller.js
+++ b/src/controller/review-object.controller/review-object.controller.js
@@ -20,6 +20,16 @@ async function getReviewObjectByOrgIdentifier (req, res, next) {
return res.status(400).json({ message: 'Missing identifier parameter' })
}
let value
+
+ if (!isSecretariat) {
+ const orgUUID = await orgRepo.getOrgUUID(req.ctx.org)
+ if (identifierIsUUID && identifier !== orgUUID) {
+ return res.status(403).json({ error: 'NOT_SAME_ORG_OR_SECRETARIAT', message: 'This information can only be viewed by the users of the same organization or the Secretariat.' })
+ } else if (!identifierIsUUID && identifier !== req.ctx.org) {
+ return res.status(403).json({ error: 'NOT_SAME_ORG_OR_SECRETARIAT', message: 'This information can only be viewed by the users of the same organization or the Secretariat.' })
+ }
+ }
+
// We may want this to be something different, but for now we are just testing
if (identifierIsUUID) {
value = await repo.getOrgReviewObjectByOrgUUID(identifier, isSecretariat, {})
diff --git a/src/middleware/schemas/BaseOrg.json b/src/middleware/schemas/BaseOrg.json
index a87e55fe4..b1982cfcb 100644
--- a/src/middleware/schemas/BaseOrg.json
+++ b/src/middleware/schemas/BaseOrg.json
@@ -100,24 +100,24 @@
"$ref": "#/definitions/uuidType"
}
},
- "poc": {
- "type": "string"
+ "websites": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uri"
+ },
+ "uniqueItems": true
},
- "poc_email": {
- "type": "string",
- "format": "email"
+ "emails": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "email"
+ },
+ "uniqueItems": true
},
- "poc_phone": {
+ "phone": {
"type": "string"
- },
- "org_email": {
- "type": "string",
- "format": "email"
- },
- "website": {
- "$ref": "#/definitions/uriType",
- "type": "string",
- "pattern": "^(ftp|http)s?://\\S+$"
}
},
"additionalProperties": false
diff --git a/src/middleware/schemas/CNAOrg.json b/src/middleware/schemas/CNAOrg.json
index 966056f75..55e0211cf 100644
--- a/src/middleware/schemas/CNAOrg.json
+++ b/src/middleware/schemas/CNAOrg.json
@@ -30,7 +30,7 @@
"maximum": 100000
},
"charter_or_scope": {
- "$ref": "/BaseOrg#/definitions/uriType"
+ "type": "string"
},
"disclosure_policy": {
"$ref": "/BaseOrg#/definitions/uriType"
diff --git a/src/model/baseorg.js b/src/model/baseorg.js
index 13777a5af..48a5205aa 100644
--- a/src/model/baseorg.js
+++ b/src/model/baseorg.js
@@ -15,10 +15,9 @@ const schema = {
users: { type: [String], set: toUndefined },
admins: [String],
contact_info: {
- phone: String,
- poc: String,
- poc_email: String,
- website: String
+ websites: [String],
+ emails: [String],
+ phone: String
},
private_contacts: [{
_id: false,
diff --git a/src/repositories/baseOrgRepository.js b/src/repositories/baseOrgRepository.js
index 3b1afc328..1bd9500aa 100644
--- a/src/repositories/baseOrgRepository.js
+++ b/src/repositories/baseOrgRepository.js
@@ -708,11 +708,9 @@ class BaseOrgRepository extends BaseRepository {
* @param {string[]} [incomingParameters.product_list] - A list of the organization's products. (Registry only)
* @param {string[]} [incomingParameters.oversees] - A list of short names of organizations this org oversees. (Registry only)
* @param {string} [incomingParameters.reports_to] - The short name of the organization this org reports to. (Registry only)
- * @param {string} [incomingParameters.contact_info.poc] - The primary point of contact's name. (Registry only)
- * @param {string} [incomingParameters.contact_info.poc_email] - The primary point of contact's email. (Registry only)
- * @param {string} [incomingParameters.contact_info.poc_phone] - The primary point of contact's phone number. (Registry only)
- * @param {string} [incomingParameters.contact_info.org_email] - The general organization email address. (Registry only)
- * @param {string} [incomingParameters.contact_info.website] - The organization's website URL. (Registry only)
+ * @param {string[]} [incomingParameters.contact_info.websites] - The organization's website URLs. (Registry only)
+ * @param {string[]} [incomingParameters.contact_info.emails] - The organization's email addresses. (Registry only)
+ * @param {string} [incomingParameters.contact_info.phone] - The organization's phone number. (Registry only)
* @param {string} [incomingParameters.cna_role_type] - (Registry only)
* @param {string} [incomingParameters.cna_country] - (Registry only)
* @param {string[]} [incomingParameters.advisory_locations] - (Registry only)
diff --git a/src/repositories/conversationRepository.js b/src/repositories/conversationRepository.js
index b4ef2e437..047de1c41 100644
--- a/src/repositories/conversationRepository.js
+++ b/src/repositories/conversationRepository.js
@@ -44,8 +44,9 @@ class ConversationRepository extends BaseRepository {
}
})
return conversations.map(convo => convo.toObject()).filter(conv => isSecretariat || conv.visibility === 'public').map(conv => {
- if (!isSecretariat) {
+ if (!isSecretariat && conv.author_role === 'Secretariat') {
delete conv.author_id
+ delete conv.author_name
}
return conv
})
diff --git a/src/repositories/reviewObjectRepository.js b/src/repositories/reviewObjectRepository.js
index 19730b6ae..401aa8c42 100644
--- a/src/repositories/reviewObjectRepository.js
+++ b/src/repositories/reviewObjectRepository.js
@@ -248,7 +248,10 @@ class ReviewObjectRepository extends BaseRepository {
// If non-secretariat, remove author_id
if (!isSecretariat) {
conversations = conversations.map(c => {
- delete c.author_id
+ if (c.author_role === 'Secretariat') {
+ delete c.author_id
+ delete c.author_name
+ }
return c
})
}
diff --git a/src/scripts/migrate.js b/src/scripts/migrate.js
index ad72a2875..e4a8ffdea 100644
--- a/src/scripts/migrate.js
+++ b/src/scripts/migrate.js
@@ -110,12 +110,9 @@ async function addCVEBoard (db) {
hard_quota: null,
private_contacts: [],
contact_info: {
- poc: null,
- poc_email: null,
- poc_phone: null,
- admins: [],
- org_email: null,
- website: null
+ phone: null,
+ emails: [],
+ websites: []
},
inUse: null,
created: null,
@@ -216,11 +213,9 @@ async function orgHelper (db) {
admins: admins,
private_contacts: [], // don't have now
contact_info: {
- poc: null, // don't have now
- poc_email: null, // don't have now
- poc_phone: null, // don't have now
- org_email: email,
- website: site
+ emails: email ? [email] : [],
+ websites: site ? [site] : [],
+ phone: null
},
inUse: doc.inUse,
created: doc.time.created,
diff --git a/test/integration-tests/constants.js b/test/integration-tests/constants.js
index df85f8051..1d3c343d0 100644
--- a/test/integration-tests/constants.js
+++ b/test/integration-tests/constants.js
@@ -381,10 +381,9 @@ const testRegistryOrg = {
short_name: 'test_registry_org',
long_name: 'Test Registry Organization',
contact_info: {
- poc: 'Dave',
- poc_email: 'dave@test.org',
- phone: '555-1234',
- website: 'https://test.org'
+ websites: ['https://test.org'],
+ emails: ['dave@test.org'],
+ phone: '555-1234'
},
private_contacts: [{
poc: 'Dave Private',
@@ -399,10 +398,9 @@ const testRegistryOrg2 = {
short_name: 'test_registry_org2',
long_name: 'Test Registry Organization2',
contact_info: {
- poc: 'Dave',
- poc_email: 'dave@test.org',
- phone: '555-1234',
- website: 'https://test.org'
+ websites: ['https://test.org'],
+ emails: ['dave@test.org'],
+ phone: '555-1234'
},
authority: ['CNA'],
hard_quota: 100000
@@ -426,10 +424,9 @@ const existingRegistryOrg = {
short_name: 'win_5',
long_name: 'Test Registry Organization',
contact_info: {
- poc: 'Dave',
- poc_email: 'dave@test.org',
- phone: '555-1234',
- website: 'https://test.org'
+ websites: ['https://test.org'],
+ emails: ['dave@test.org'],
+ phone: '555-1234'
},
authority: ['CNA'],
hard_quota: 100000
diff --git a/test/integration-tests/org/postOrgTest.js b/test/integration-tests/org/postOrgTest.js
index 5f11e07d5..209ec984a 100644
--- a/test/integration-tests/org/postOrgTest.js
+++ b/test/integration-tests/org/postOrgTest.js
@@ -60,7 +60,7 @@ describe('Testing Org post endpoint', () => {
expect(res.body.created.long_name).to.equal(constants.testRegistryOrg.long_name)
expect(res.body.created).to.haveOwnProperty('contact_info')
- expect(res.body.created.contact_info).to.include(constants.testRegistryOrg.contact_info)
+ expect(res.body.created.contact_info).to.deep.equal(constants.testRegistryOrg.contact_info)
expect(res.body.created).to.haveOwnProperty('private_contacts')
expect(res.body.created.private_contacts).to.deep.equal(constants.testRegistryOrg.private_contacts)
diff --git a/test/integration-tests/registry-org/registryOrgCRUDTest.js b/test/integration-tests/registry-org/registryOrgCRUDTest.js
index 6f6ec4823..52ca111e5 100644
--- a/test/integration-tests/registry-org/registryOrgCRUDTest.js
+++ b/test/integration-tests/registry-org/registryOrgCRUDTest.js
@@ -16,7 +16,8 @@ const testRegistryOrg = {
partner_role_type: 'Vendor',
partner_number: 'Initial Partner Number',
partner_country: 'US',
- advisory_locations: ['https://example.com/advisories']
+ advisory_locations: ['https://example.com/advisories'],
+ charter_or_scope: 'This is a normal string, not a URI'
}
let createdOrg
@@ -63,6 +64,9 @@ describe('Testing /registryOrg endpoints', () => {
expect(res.body.created).to.haveOwnProperty('advisory_locations')
expect(res.body.created.advisory_locations).to.deep.equal(testRegistryOrg.advisory_locations)
+ expect(res.body.created).to.haveOwnProperty('charter_or_scope')
+ expect(res.body.created.charter_or_scope).to.equal(testRegistryOrg.charter_or_scope)
+
expect(res.body.created).to.haveOwnProperty('program_data')
expect(res.body.created.program_data.status).to.equal('inactive')
expect(res.body.created.program_data).to.haveOwnProperty('partner_inactive_date')
diff --git a/test/integration-tests/registry-org/registryOrgWithJointReviewTest.js b/test/integration-tests/registry-org/registryOrgWithJointReviewTest.js
index db236a830..bbcd6f41d 100644
--- a/test/integration-tests/registry-org/registryOrgWithJointReviewTest.js
+++ b/test/integration-tests/registry-org/registryOrgWithJointReviewTest.js
@@ -116,7 +116,7 @@ describe('Testing Joint approval', () => {
await chai.request(app)
.put('/api/registry/org/non_secretariat_org')
.set(nonAdminHeaders)
- .send({ ...testRegistryOrgForReview, short_name: 'new_non_secretariat_org', contact_info: { website: 'https://www.example.com' } })
+ .send({ ...testRegistryOrgForReview, short_name: 'new_non_secretariat_org', contact_info: { websites: ['https://www.example.com'] } })
.then((res) => {
expect(res).to.have.status(200)
expect(res.body.message).to.contain('organization was successfully updated, but joint approval is required for some fields.')
@@ -144,11 +144,11 @@ describe('Testing Joint approval', () => {
expect(err).to.be.undefined
expect(res).to.have.status(200)
expect(res.body.short_name).to.equal('non_secretariat_org')
- expect(res.body.contact_info.website).to.equal('https://www.example.com')
+ expect(res.body.contact_info.websites[0]).to.equal('https://www.example.com')
})
})
it('Secretariat can approve the ORG review with body parameter', async function () {
- const newBody = { short_name: 'final_non_secretariat_org', contact_info: { website: 'https://final.example.com' }, hard_quota: 1000, authority: ['CNA'], long_name: 'Final Non Secretariat Organization' }
+ const newBody = { short_name: 'final_non_secretariat_org', contact_info: { websites: ['https://final.example.com'] }, hard_quota: 1000, authority: ['CNA'], long_name: 'Final Non Secretariat Organization' }
await chai.request(app)
.put(`/api/review/${reviewUUID}/approve`)
.set(secretariatHeaders)
@@ -164,7 +164,7 @@ describe('Testing Joint approval', () => {
expect(err).to.be.undefined
expect(res).to.have.status(200)
expect(res.body.short_name).to.equal('final_non_secretariat_org')
- expect(res.body.contact_info.website).to.equal('https://final.example.com')
+ expect(res.body.contact_info.websites[0]).to.equal('https://final.example.com')
})
})
})
@@ -219,7 +219,7 @@ describe('Testing Joint approval', () => {
await chai.request(app)
.put('/api/registry/org/non_with_comments')
.set(nonAdminHeaders2)
- .send({ ...testRegistryOrgForReviewWithComments, short_name: 'new_non_with_comments', contact_info: { website: 'https://www.example.com' } })
+ .send({ ...testRegistryOrgForReviewWithComments, short_name: 'new_non_with_comments', contact_info: { websites: ['https://www.example.com'] } })
.then((res) => {
expect(res).to.have.status(200)
expect(res.body.message).to.contain('organization was successfully updated, but joint approval is required for some fields.')
@@ -247,7 +247,7 @@ describe('Testing Joint approval', () => {
expect(err).to.be.undefined
expect(res).to.have.status(200)
expect(res.body.short_name).to.equal('non_with_comments')
- expect(res.body.contact_info.website).to.equal('https://www.example.com')
+ expect(res.body.contact_info.websites[0]).to.equal('https://www.example.com')
})
})
it('Secretariat leaves a public comment on the org review', async () => {
diff --git a/test/integration-tests/registry-org/verifyDeepRemoveEmpty.js b/test/integration-tests/registry-org/verifyDeepRemoveEmpty.js
index d2c056768..c88959459 100644
--- a/test/integration-tests/registry-org/verifyDeepRemoveEmpty.js
+++ b/test/integration-tests/registry-org/verifyDeepRemoveEmpty.js
@@ -14,8 +14,7 @@ const testNullRemovalOrg = {
authority: ['CNA'],
hard_quota: 1000,
contact_info: {
- website: null, // Should be removed
- org_email: undefined // Should be removed (or not present)
+ phone: null // Should be removed
}
}
@@ -40,14 +39,13 @@ describe('Testing Deep Remove Empty in Create Org', () => {
expect(createdOrg).to.haveOwnProperty('short_name')
expect(createdOrg.short_name).to.equal(testNullRemovalOrg.short_name)
- // Verify contact_info exists but does NOT contain website or org_email
+ // Verify contact_info exists but does NOT contain websites or emails
// Ideally if contact_info becomes empty, deepRemoveEmpty might remove the whole object if it recurses well.
// Let's check what happened.
if (createdOrg.contact_info) {
- expect(createdOrg.contact_info).to.not.have.property('website')
- expect(createdOrg.contact_info).to.not.have.property('org_email')
- // If deepRemoveEmpty works on nested empty objects, contact_info might be gone or empty.
- expect(Object.keys(createdOrg.contact_info)).to.be.empty
+ expect(createdOrg.contact_info).to.not.have.property('phone')
+ expect(createdOrg.contact_info).to.have.property('websites').that.is.an('array')
+ expect(createdOrg.contact_info).to.have.property('emails').that.is.an('array')
} else {
// This is also acceptable if deepRemoveEmpty removes empty objects
expect(createdOrg).to.not.have.property('contact_info')
diff --git a/test/integration-tests/review-object/reviewObjectTest.js b/test/integration-tests/review-object/reviewObjectTest.js
index 3d9c10e46..762315287 100644
--- a/test/integration-tests/review-object/reviewObjectTest.js
+++ b/test/integration-tests/review-object/reviewObjectTest.js
@@ -13,6 +13,7 @@ describe('Review Object Controller Integration Tests', () => {
let rejectTestReviewUUID
let autoApproveReviewUUID
let autoRejectReviewUUID
+ let adminRetrievalTestReviewUUID
context('Positive Tests', () => {
it('Creates an organization to use for review object tests', async () => {
@@ -199,14 +200,14 @@ describe('Review Object Controller Integration Tests', () => {
updateData.long_name = 'Approve Test Organization'
updateData.authority = ['CNA']
updateData.hard_quota = 1000
- updateData.contact_info = { website: 'https://www.example.com' }
+ updateData.contact_info = { websites: ['https://www.example.com'] }
const res = await chai
.request(app)
.put(`/api/registry/org/${constants.existingOrg.short_name}`)
.set({ ...constants.nonSecretariatUserHeaders2 })
.send(updateData)
expect(res).to.have.status(200)
- expect(res.body.updated.contact_info.website).to.equal('https://www.example.com')
+ expect(res.body.updated.contact_info.websites[0]).to.equal('https://www.example.com')
const reviewRes = await chai
.request(app)
@@ -216,7 +217,7 @@ describe('Review Object Controller Integration Tests', () => {
expect(reviewRes.body).to.have.property('uuid')
expect(reviewRes.body.status).to.equal('pending')
expect(reviewRes.body).to.have.nested.property('new_review_data.long_name', 'Approve Test Organization')
- expect(reviewRes.body).to.have.nested.property('new_review_data.contact_info.website', 'https://www.example.com')
+ expect(reviewRes.body.new_review_data.contact_info.websites[0]).to.equal('https://www.example.com')
approveTestReviewUUID = reviewRes.body.uuid
})
@@ -429,6 +430,96 @@ describe('Review Object Controller Integration Tests', () => {
expect(reviewRes.body).to.have.property('status', 'rejected')
})
// ------------------------------------------------------------------------------------------------
+
+ it('Org Admin can retrieve their pending review object by org identifier (short_name)', async () => {
+ const updateData = {
+ short_name: constants.existingOrg.short_name,
+ long_name: 'Admin Retrieval Test Org',
+ authority: ['CNA'],
+ hard_quota: 1000
+ }
+ const res = await chai
+ .request(app)
+ .put(`/api/registry/org/${constants.existingOrg.short_name}`)
+ .set({ ...constants.nonSecretariatUserHeaders2 })
+ .send(updateData)
+ expect(res).to.have.status(200)
+
+ const reviewRes = await chai
+ .request(app)
+ .get(`/api/review/org/${constants.existingOrg.short_name}`)
+ .set({ ...constants.nonSecretariatUserHeaders2 })
+
+ expect(reviewRes).to.have.status(200)
+ expect(reviewRes.body).to.have.property('uuid')
+ expect(reviewRes.body.status).to.equal('pending')
+ expect(reviewRes.body).to.have.nested.property('new_review_data.long_name', 'Admin Retrieval Test Org')
+
+ adminRetrievalTestReviewUUID = reviewRes.body.uuid
+ })
+
+ it('Org Admin can see Partner UUIDs in conversation but not Secretariat UUIDs', async () => {
+ // Get the target UUID (Org UUID) for win_5
+ const orgRes = await chai.request(app)
+ .get(`/api/registry/org/${constants.existingOrg.short_name}`)
+ .set({ ...constants.headers })
+ const targetUUID = orgRes.body.UUID
+
+ // 1. Secretariat posts a conversation message
+ const secMessage = { body: 'Secretariat message', visibility: 'public' }
+ let res = await chai.request(app)
+ .post(`/api/conversation/target/${targetUUID}`)
+ .set({ ...constants.headers })
+ .send(secMessage)
+ expect(res).to.have.status(200)
+
+ // 2. Org Admin posts a conversation message
+ const adminMessage = { body: 'Admin message' }
+ res = await chai.request(app)
+ .post(`/api/conversation/target/${targetUUID}`)
+ .set({ ...constants.nonSecretariatUserHeaders2 }) // They are Partner
+ .send(adminMessage)
+ expect(res).to.have.status(200)
+
+ // 3. Org Admin fetches the review object to see conversations
+ const reviewRes = await chai.request(app)
+ .get(`/api/review/byUUID/${adminRetrievalTestReviewUUID}`)
+ .set({ ...constants.nonSecretariatUserHeaders2 })
+
+ expect(reviewRes).to.have.status(200)
+ expect(reviewRes.body).to.have.property('conversation')
+ expect(reviewRes.body.conversation).to.be.an('array')
+
+ const secConvo = reviewRes.body.conversation.find(c => c.author_role === 'Secretariat')
+ const adminConvo = reviewRes.body.conversation.find(c => c.author_role === 'Partner')
+
+ expect(secConvo).to.exist
+ expect(secConvo).to.not.have.property('author_id') // Secretariat UUID hidden
+ expect(secConvo).to.not.have.property('author_name') // Secretariat name hidden
+
+ expect(adminConvo).to.exist
+ expect(adminConvo).to.have.property('author_id') // Partner UUID visible
+ expect(adminConvo).to.have.property('author_name') // Partner name visible
+ })
+
+ it('Org Admin can retrieve their review object by UUID', async () => {
+ const reviewRes = await chai
+ .request(app)
+ .get(`/api/review/byUUID/${adminRetrievalTestReviewUUID}`)
+ .set({ ...constants.nonSecretariatUserHeaders2 })
+
+ expect(reviewRes).to.have.status(200)
+ expect(reviewRes.body).to.have.property('uuid', adminRetrievalTestReviewUUID)
+ expect(reviewRes.body.status).to.equal('pending')
+ expect(reviewRes.body).to.have.nested.property('new_review_data.long_name', 'Admin Retrieval Test Org')
+
+ const rejectRes = await chai
+ .request(app)
+ .put(`/api/review/${adminRetrievalTestReviewUUID}/reject`)
+ .set({ ...constants.headers })
+ .send({})
+ expect(rejectRes).to.have.status(200)
+ })
})
context('Negative Tests', () => {