Skip to content

Commit 0681e62

Browse files
authored
fix: catch error within customerIntent endpoints (#1226)
## Related issues LLMO-371 | Do not throw on customerIntent endpoints when access is not valid
1 parent 290bbae commit 0681e62

File tree

4 files changed

+226
-77
lines changed

4 files changed

+226
-77
lines changed

src/controllers/llmo/llmo.js

Lines changed: 81 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212

13-
import { ok, badRequest } from '@adobe/spacecat-shared-http-utils';
13+
import { ok, badRequest, forbidden } from '@adobe/spacecat-shared-http-utils';
1414
import {
1515
SPACECAT_USER_AGENT,
1616
tracingFetch as fetch,
@@ -437,91 +437,122 @@ function LlmoController(ctx) {
437437

438438
// Handles requests to the LLMO customer intent endpoint, returns customer intent array
439439
const getLlmoCustomerIntent = async (context) => {
440-
const { llmoConfig } = await getSiteAndValidateLlmo(context);
441-
return ok(llmoConfig.customerIntent || []);
440+
try {
441+
const { llmoConfig } = await getSiteAndValidateLlmo(context);
442+
return ok(llmoConfig.customerIntent || []);
443+
} catch (error) {
444+
if (error.message === 'Only users belonging to the organization can view its sites') {
445+
return forbidden(error.message);
446+
}
447+
return badRequest(error.message);
448+
}
442449
};
443450

444451
// Handles requests to the LLMO customer intent endpoint, adds new customer intent items
445452
const addLlmoCustomerIntent = async (context) => {
446453
const { log } = context;
447-
const { site, config } = await getSiteAndValidateLlmo(context);
448454

449-
const newCustomerIntent = context.data;
450-
if (!Array.isArray(newCustomerIntent)) {
451-
return badRequest('Customer intent must be provided as an array');
452-
}
453-
454-
// Get existing customer intent keys to check for duplicates
455-
const existingCustomerIntent = config.getLlmoCustomerIntent() || [];
456-
const existingKeys = new Set(existingCustomerIntent.map((item) => item.key));
457-
const newKeys = new Set();
455+
try {
456+
const { site, config } = await getSiteAndValidateLlmo(context);
458457

459-
// Validate structure of each customer intent item and check for duplicates
460-
for (const intent of newCustomerIntent) {
461-
if (!hasText(intent.key) || !hasText(intent.value)) {
462-
return badRequest('Each customer intent item must have both key and value properties');
458+
const newCustomerIntent = context.data;
459+
if (!Array.isArray(newCustomerIntent)) {
460+
return badRequest('Customer intent must be provided as an array');
463461
}
464462

465-
if (existingKeys.has(intent.key)) {
466-
return badRequest(`Customer intent key '${intent.key}' already exists`);
467-
}
463+
// Get existing customer intent keys to check for duplicates
464+
const existingCustomerIntent = config.getLlmoCustomerIntent() || [];
465+
const existingKeys = new Set(existingCustomerIntent.map((item) => item.key));
466+
const newKeys = new Set();
468467

469-
if (newKeys.has(intent.key)) {
470-
return badRequest(`Duplicate customer intent key '${intent.key}' in request`);
471-
}
468+
// Validate structure of each customer intent item and check for duplicates
469+
for (const intent of newCustomerIntent) {
470+
if (!hasText(intent.key) || !hasText(intent.value)) {
471+
return badRequest('Each customer intent item must have both key and value properties');
472+
}
472473

473-
newKeys.add(intent.key);
474-
}
474+
if (existingKeys.has(intent.key)) {
475+
return badRequest(`Customer intent key '${intent.key}' already exists`);
476+
}
477+
478+
if (newKeys.has(intent.key)) {
479+
return badRequest(`Duplicate customer intent key '${intent.key}' in request`);
480+
}
475481

476-
config.addLlmoCustomerIntent(newCustomerIntent);
477-
await saveSiteConfig(site, config, log, 'adding customer intent');
482+
newKeys.add(intent.key);
483+
}
478484

479-
// return the updated llmoConfig customer intent
480-
return ok(config.getLlmoConfig().customerIntent || []);
485+
config.addLlmoCustomerIntent(newCustomerIntent);
486+
await saveSiteConfig(site, config, log, 'adding customer intent');
487+
488+
// return the updated llmoConfig customer intent
489+
return ok(config.getLlmoConfig().customerIntent || []);
490+
} catch (error) {
491+
if (error.message === 'Only users belonging to the organization can view its sites') {
492+
return forbidden(error.message);
493+
}
494+
return badRequest(error.message);
495+
}
481496
};
482497

483498
// Handles requests to the LLMO customer intent endpoint, removes a customer intent item
484499
const removeLlmoCustomerIntent = async (context) => {
485500
const { log } = context;
486501
const { intentKey } = context.params;
487-
const { site, config } = await getSiteAndValidateLlmo(context);
488502

489-
validateCustomerIntentKey(config, intentKey);
503+
try {
504+
const { site, config } = await getSiteAndValidateLlmo(context);
505+
506+
validateCustomerIntentKey(config, intentKey);
490507

491-
// remove the customer intent using the config method
492-
config.removeLlmoCustomerIntent(intentKey);
508+
// remove the customer intent using the config method
509+
config.removeLlmoCustomerIntent(intentKey);
493510

494-
await saveSiteConfig(site, config, log, 'removing customer intent');
511+
await saveSiteConfig(site, config, log, 'removing customer intent');
495512

496-
// return the updated llmoConfig customer intent
497-
return ok(config.getLlmoConfig().customerIntent || []);
513+
// return the updated llmoConfig customer intent
514+
return ok(config.getLlmoConfig().customerIntent || []);
515+
} catch (error) {
516+
if (error.message === 'Only users belonging to the organization can view its sites') {
517+
return forbidden(error.message);
518+
}
519+
return badRequest(error.message);
520+
}
498521
};
499522

500523
// Handles requests to the LLMO customer intent endpoint, updates a customer intent item
501524
const patchLlmoCustomerIntent = async (context) => {
502525
const { log } = context;
503526
const { intentKey } = context.params;
504527
const { data } = context;
505-
const { site, config } = await getSiteAndValidateLlmo(context);
506528

507-
validateCustomerIntentKey(config, intentKey);
529+
try {
530+
const { site, config } = await getSiteAndValidateLlmo(context);
531+
532+
validateCustomerIntentKey(config, intentKey);
508533

509-
// Validate the update data
510-
if (!isObject(data)) {
511-
return badRequest('Update data must be provided as an object');
512-
}
534+
// Validate the update data
535+
if (!isObject(data)) {
536+
return badRequest('Update data must be provided as an object');
537+
}
513538

514-
if (!hasText(data.value)) {
515-
return badRequest('Customer intent value must be a non-empty string');
516-
}
539+
if (!hasText(data.value)) {
540+
return badRequest('Customer intent value must be a non-empty string');
541+
}
517542

518-
// update the customer intent using the config method
519-
config.updateLlmoCustomerIntent(intentKey, data);
543+
// update the customer intent using the config method
544+
config.updateLlmoCustomerIntent(intentKey, data);
520545

521-
await saveSiteConfig(site, config, log, 'updating customer intent');
546+
await saveSiteConfig(site, config, log, 'updating customer intent');
522547

523-
// return the updated llmoConfig customer intent
524-
return ok(config.getLlmoConfig().customerIntent || []);
548+
// return the updated llmoConfig customer intent
549+
return ok(config.getLlmoConfig().customerIntent || []);
550+
} catch (error) {
551+
if (error.message === 'Only users belonging to the organization can view its sites') {
552+
return forbidden(error.message);
553+
}
554+
return badRequest(error.message);
555+
}
525556
};
526557

527558
// Handles requests to the LLMO CDN logs filter endpoint, updates CDN logs filter configuration

src/support/access-control-util.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,12 @@ export default class AccessControlUtil {
166166
} else if (entity instanceof Organization) {
167167
org = entity;
168168
}
169-
await this.validateEntitlement(org, site, productCode);
169+
try {
170+
await this.validateEntitlement(org, site, productCode);
171+
} catch (e) {
172+
this.log.error(`Error validating entitlement for ${entity.getId()}: ${e.message}`);
173+
return false;
174+
}
170175
}
171176
if (subService.length > 0) {
172177
return hasOrgAccess && authInfo.hasScope('user', `${SERVICE_CODE}_${subService}`);

0 commit comments

Comments
 (0)