sanitizePath.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /**
  2. * Remove slugs from the path - we do not want them displayed in the Issues Stream (having them in issue details is ok)
  3. */
  4. const TYPE_TO_PLACEHOLDER = {
  5. 'alert-rules': '{ruleId}',
  6. customers: '{orgSlug}',
  7. environments: '{environmentId}',
  8. events: '{eventId}',
  9. groups: '{groupId}',
  10. issues: '{issueId}',
  11. members: '{memberId}',
  12. organizations: '{orgSlug}',
  13. projects: '{projectSlug}',
  14. releases: '{releaseId}',
  15. replays: '{replayId}',
  16. subscriptions: '{orgSlug}',
  17. tags: '{tagName}',
  18. teams: '{teamSlug}',
  19. };
  20. function getSlugPlaceholder(rawSlugType: string, slugValue: string): string {
  21. if (slugValue === '') {
  22. return slugValue;
  23. }
  24. // Pull off the trailing slash, if there is one
  25. const slugType = rawSlugType.replace(/\/$/, '');
  26. return slugType in TYPE_TO_PLACEHOLDER
  27. ? TYPE_TO_PLACEHOLDER[slugType] + '/'
  28. : slugValue;
  29. }
  30. export function sanitizePath(path: string) {
  31. return (
  32. path
  33. // Remove any querystring
  34. .split('?')[0]
  35. .replace(
  36. /(?<start>.*?\/)(?<type>organizations|issues|groups|customers|subscriptions|projects|teams|users)\/(?<second>[^/]+)\/(?<third>[^/]+\/)?(?<fourth>[^/]+\/)?(?<fifth>[^/]+\/)?(?<sixth>[^/]+\/)?(?<seventh>[^/]+\/)?(?<end>.*)/,
  37. function (...args) {
  38. const matches = args[args.length - 1];
  39. let {type} = matches;
  40. const {
  41. start,
  42. second,
  43. third = '',
  44. fourth = '',
  45. fifth = '',
  46. sixth = '',
  47. seventh = '',
  48. end,
  49. } = matches;
  50. // The `rule-conditions` endpoint really ought to be an org endpoint,
  51. // and it's formatted like one, so for now, let's treat it like one.
  52. // We can fix it before we return our final value. See
  53. // `ProjectAgnosticRuleConditionsEndpoint` in `sentry/api/urls.py`.
  54. if (third === 'rule-conditions/') {
  55. type = 'organizations';
  56. }
  57. const isOrgLike = [
  58. 'organizations',
  59. 'customers',
  60. 'issues',
  61. 'groups',
  62. 'users',
  63. 'subscriptions',
  64. ].includes(type);
  65. const isProjectLike = ['projects', 'teams'].includes(type);
  66. // Org-like urls look like `/<type>/<slug>/<contentType>/...`, whereas
  67. // project-like urls look like `/<type>/<org-slug>/<slug>/<contentType>/...`.
  68. const primarySlug = isOrgLike ? second : third;
  69. const contentType = isOrgLike ? third : fourth;
  70. const secondarySlug = isOrgLike ? fourth : fifth;
  71. const contentSubtype = isOrgLike ? fifth : sixth;
  72. const tertiarySlug = isOrgLike ? sixth : seventh;
  73. let primarySlugPlaceholder = getSlugPlaceholder(type, primarySlug);
  74. let secondarySlugPlaceholder = getSlugPlaceholder(contentType, secondarySlug);
  75. const tertiarySlugPlaceholder = getSlugPlaceholder(
  76. contentSubtype,
  77. tertiarySlug
  78. );
  79. if (isProjectLike) {
  80. primarySlugPlaceholder = '{orgSlug}/' + primarySlugPlaceholder;
  81. }
  82. if (isOrgLike) {
  83. if (contentType === 'events/') {
  84. if (secondarySlug.includes(':')) {
  85. // OrganizationEventDetailsEndpoint
  86. secondarySlugPlaceholder = '{projectSlug}:{eventId}/';
  87. } else if (['latest/', 'oldest/'].includes(secondarySlug)) {
  88. // GroupEventDetailsEndpoint
  89. secondarySlugPlaceholder = secondarySlug;
  90. }
  91. } else if (contentType === 'plugins/') {
  92. if (secondarySlug === 'configs/') {
  93. // OrganizationPluginsConfigsEndpoint
  94. secondarySlugPlaceholder = secondarySlug;
  95. }
  96. }
  97. }
  98. // Now that we've handled all our special cases based on type, we can
  99. // restore the correct value for `rule-conditions`
  100. if (contentType === 'rule-conditions/') {
  101. type = 'projects';
  102. }
  103. return `${start}${type}/${primarySlugPlaceholder}${contentType}${secondarySlugPlaceholder}${contentSubtype}${tertiarySlugPlaceholder}${end}`;
  104. }
  105. )
  106. );
  107. }