]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-13117 Handle 403 gracefully
authorJeremy Davis <jeremy.davis@sonarsource.com>
Mon, 24 Feb 2020 10:02:37 +0000 (11:02 +0100)
committersonartech <sonartech@sonarsource.com>
Mon, 2 Mar 2020 08:01:29 +0000 (09:01 +0100)
server/sonar-web/src/main/js/api/issues.ts
server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/CrossComponentSourceViewerWrapper.tsx
server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/CrossComponentSourceViewerWrapper-test.tsx
server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/CrossComponentSourceViewerWrapper-test.tsx.snap

index 769512154d476d5eb3ca573a86be20e3b9ee7b32..c4913ab6bfde0e5b1250c8a9c83a54aa6f7e104d 100644 (file)
@@ -183,5 +183,5 @@ export function getIssueFlowSnippets(issueKey: string): Promise<T.Dict<T.Snippet
       }
     });
     return result;
-  }, throwGlobalError);
+  });
 }
index 4b8262b38a0b766d8b221a0596f1cc4e2d0742fa..9e30ad96128a60e0eef6f9f34ab47543e4da2f72 100644 (file)
@@ -23,12 +23,14 @@ import { groupLocationsByComponent } from './utils';
 import DeferredSpinner from '../../../components/common/DeferredSpinner';
 import DuplicationPopup from '../../../components/SourceViewer/components/DuplicationPopup';
 import { SourceViewerContext } from '../../../components/SourceViewer/SourceViewerContext';
+import { Alert } from '../../../components/ui/Alert';
 import { WorkspaceContext } from '../../../components/workspace/context';
 import { getIssueFlowSnippets } from '../../../api/issues';
+import throwGlobalError from '../../../app/utils/throwGlobalError';
 import {
   filterDuplicationBlocksByLine,
-  isDuplicationBlockInRemovedComponent,
-  getDuplicationBlocksForIndex
+  getDuplicationBlocksForIndex,
+  isDuplicationBlockInRemovedComponent
 } from '../../../components/SourceViewer/helpers/duplications';
 import {
   duplicationsByLine,
@@ -36,6 +38,7 @@ import {
 } from '../../../components/SourceViewer/helpers/indexing';
 import { getDuplications } from '../../../api/components';
 import { getBranchLikeQuery } from '../../../helpers/branches';
+import { translate } from '../../../helpers/l10n';
 
 interface Props {
   branchLike: T.Branch | T.PullRequest | undefined;
@@ -58,6 +61,7 @@ interface State {
   issuePopup?: { issue: string; name: string };
   linePopup?: T.LinePopup & { component: string };
   loading: boolean;
+  notAccessible: boolean;
 }
 
 export default class CrossComponentSourceViewerWrapper extends React.PureComponent<Props, State> {
@@ -65,7 +69,8 @@ export default class CrossComponentSourceViewerWrapper extends React.PureCompone
   state: State = {
     components: {},
     duplicationsByLine: {},
-    loading: true
+    loading: true,
+    notAccessible: false
   };
 
   componentDidMount() {
@@ -121,9 +126,12 @@ export default class CrossComponentSourceViewerWrapper extends React.PureCompone
           }
         }
       },
-      () => {
+      ({ response }: { response: Response }) => {
+        if (response.status !== 403) {
+          throwGlobalError({ response });
+        }
         if (this.mounted) {
-          this.setState({ loading: false });
+          this.setState({ loading: false, notAccessible: response.status === 403 });
         }
       }
     );
@@ -196,7 +204,7 @@ export default class CrossComponentSourceViewerWrapper extends React.PureCompone
   };
 
   render() {
-    const { loading } = this.state;
+    const { loading, notAccessible } = this.state;
 
     if (loading) {
       return (
@@ -206,6 +214,14 @@ export default class CrossComponentSourceViewerWrapper extends React.PureCompone
       );
     }
 
+    if (notAccessible) {
+      return (
+        <Alert className="spacer-top" variant="warning">
+          {translate('code_viewer.no_source_code_displayed_due_to_security')}
+        </Alert>
+      );
+    }
+
     const { components, duplications, duplicationsByLine, linePopup } = this.state;
     const issuesByComponent = issuesByComponentAndLine(this.props.issues);
     const locationsByComponent = groupLocationsByComponent(this.props.locations, components);
index 4d283b416d1fa28cdcbc3940e6267d6b315c0a6f..ca19ef6b09294abeb5ed7e1ead726b1c5a5298a9 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-import * as React from 'react';
 import { shallow } from 'enzyme';
-import CrossComponentSourceViewerWrapper from '../CrossComponentSourceViewerWrapper';
+import * as React from 'react';
+import { getDuplications } from '../../../../api/components';
+import { getIssueFlowSnippets } from '../../../../api/issues';
 import {
   mockFlowLocation,
   mockIssue,
@@ -28,8 +29,7 @@ import {
   mockSourceViewerFile
 } from '../../../../helpers/testMocks';
 import { waitAndUpdate } from '../../../../helpers/testUtils';
-import { getIssueFlowSnippets } from '../../../../api/issues';
-import { getDuplications } from '../../../../api/components';
+import CrossComponentSourceViewerWrapper from '../CrossComponentSourceViewerWrapper';
 
 jest.mock('../../../../api/issues', () => {
   const { mockSnippetsByComponent } = require.requireActual('../../../../helpers/testMocks');
@@ -66,6 +66,16 @@ it('Should fetch data', async () => {
   expect(getIssueFlowSnippets).toBeCalledWith('foo');
 });
 
+it('Should handle no access rights', async () => {
+  (getIssueFlowSnippets as jest.Mock).mockRejectedValueOnce({ response: { status: 403 } });
+
+  const wrapper = shallowRender();
+  await waitAndUpdate(wrapper);
+
+  expect(wrapper.state().notAccessible).toBe(true);
+  expect(wrapper).toMatchSnapshot();
+});
+
 it('should handle issue popup', () => {
   const wrapper = shallowRender();
   // open
index 5f6913c5ace958df7c57e80824efb5e672e9426e..c6362cb8a7167adaf501d064df583aaf0da276c7 100644 (file)
@@ -1,5 +1,14 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`Should handle no access rights 1`] = `
+<Alert
+  className="spacer-top"
+  variant="warning"
+>
+  code_viewer.no_source_code_displayed_due_to_security
+</Alert>
+`;
+
 exports[`should handle duplication popup 1`] = `
 <Context.Consumer>
   [Function]