aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStas Vilchik <stasvilchik@Stas-Vilchik-iMac.local>2014-12-10 13:58:37 +0100
committerStas Vilchik <stasvilchik@Stas-Vilchik-iMac.local>2014-12-10 14:15:39 +0100
commit8bec488ab21ecfeacdc5089df7623d80569e2844 (patch)
tree9e92a4d425dadca95aa9a69e7cd642d430e053c7
parenta4f5098c74bb4bccfa33b288cc497029828144fb (diff)
downloadsonarqube-8bec488ab21ecfeacdc5089df7623d80569e2844.tar.gz
sonarqube-8bec488ab21ecfeacdc5089df7623d80569e2844.zip
SONAR-5884 Show error message when no permission to see the source code
-rw-r--r--server/sonar-web/src/main/hbs/source-viewer/source-viewer.hbs104
-rw-r--r--server/sonar-web/src/main/js/source-viewer/source.js4
-rw-r--r--server/sonar-web/src/main/js/source-viewer/viewer.js51
-rw-r--r--server/sonar-web/src/main/js/tests/e2e/tests/source-viewer-should-not-show-source-if-no-permission.js30
-rw-r--r--server/sonar-web/src/main/js/tests/e2e/tests/source-viewer-should-not-show-source-if-no-permission/api-components-app.json95
-rw-r--r--server/sonar-web/src/main/js/tests/e2e/tests/source-viewer-should-not-show-source-if-no-permission/api-issues-search.json234
6 files changed, 450 insertions, 68 deletions
diff --git a/server/sonar-web/src/main/hbs/source-viewer/source-viewer.hbs b/server/sonar-web/src/main/hbs/source-viewer/source-viewer.hbs
index 1739fd3b6dd..c47a2a3749c 100644
--- a/server/sonar-web/src/main/hbs/source-viewer/source-viewer.hbs
+++ b/server/sonar-web/src/main/hbs/source-viewer/source-viewer.hbs
@@ -1,54 +1,62 @@
<div class="source-viewer-header"></div>
-{{#if hasSourceBefore}}
- <i class="spinner js-component-viewer-source-before"></i>
-{{/if}}
+{{#if canSeeCode}}
+
+ {{#if hasSourceBefore}}
+ <i class="spinner js-component-viewer-source-before"></i>
+ {{/if}}
+
+ <table class="source-table">
+ {{#each source}}
+ <tr class="source-line {{#eq line 0}}{{#empty issues}}hidden{{/empty}}{{/eq}}" {{#if line}}data-line-number="{{line}}"{{/if}}>
+ <td class="source-meta source-line-number" {{#if line}}data-line-number="{{line}}"{{/if}}></td>
+
+ <td class="source-meta source-line-scm" {{#if line}}data-line-number="{{line}}"{{/if}}>
+ {{#ifSCMChanged2 ../source line}}
+ <div class="source-line-scm-inner" data-author="{{scmAuthor}}"></div>
+ {{/ifSCMChanged2}}
+ </td>
+
+ <td class="source-meta source-line-coverage {{#notNull coverageStatus}}source-line-{{coverageStatus}}{{/notNull}}"
+ data-line-number="{{line}}">
+ <div class="source-line-bar"></div>
+ </td>
-<table class="source-table">
- {{#each source}}
- <tr class="source-line {{#eq line 0}}{{#empty issues}}hidden{{/empty}}{{/eq}}" {{#if line}}data-line-number="{{line}}"{{/if}}>
- <td class="source-meta source-line-number" {{#if line}}data-line-number="{{line}}"{{/if}}></td>
-
- <td class="source-meta source-line-scm" {{#if line}}data-line-number="{{line}}"{{/if}}>
- {{#ifSCMChanged2 ../source line}}
- <div class="source-line-scm-inner" data-author="{{scmAuthor}}"></div>
- {{/ifSCMChanged2}}
- </td>
-
- <td class="source-meta source-line-coverage {{#notNull coverageStatus}}source-line-{{coverageStatus}}{{/notNull}}"
- data-line-number="{{line}}">
- <div class="source-line-bar"></div>
- </td>
-
- <td class="source-meta source-line-duplications {{#if duplicated}}source-line-duplicated{{/if}}"
- title="{{t 'source_viewer.expand_duplications'}}">
- <div class="source-line-bar"></div>
- </td>
-
- {{#each duplications}}
- <td class="source-meta source-line-duplications-extra {{#if this}}source-line-duplicated{{/if}}"
- data-index="{{this}}" data-line-number="{{line}}">
+ <td class="source-meta source-line-duplications {{#if duplicated}}source-line-duplicated{{/if}}"
+ title="{{t 'source_viewer.expand_duplications'}}">
<div class="source-line-bar"></div>
</td>
- {{/each}}
-
- <td class="source-line-code code {{#notEmpty issues}}has-issues{{/notEmpty}}" data-line-number="{{line}}">
- {{#notNull code}}
- <pre>{{#if code}}{{{code}}}{{else}}&nbsp;{{/if}}</pre>
- {{/notNull}}
-
- {{#notEmpty issues}}
- <div class="issue-list">
- {{#each issues}}
- <div class="issue" id="issue-{{key}}"></div>
- {{/each}}
- </div>
- {{/notEmpty}}
- </td>
- </tr>
- {{/each}}
-</table>
-
-{{#if hasSourceAfter}}
- <i class="spinner js-component-viewer-source-after"></i>
+
+ {{#each duplications}}
+ <td class="source-meta source-line-duplications-extra {{#if this}}source-line-duplicated{{/if}}"
+ data-index="{{this}}" data-line-number="{{line}}">
+ <div class="source-line-bar"></div>
+ </td>
+ {{/each}}
+
+ <td class="source-line-code code {{#notEmpty issues}}has-issues{{/notEmpty}}" data-line-number="{{line}}">
+ {{#notNull code}}
+ <pre>{{#if code}}{{{code}}}{{else}}&nbsp;{{/if}}</pre>
+ {{/notNull}}
+
+ {{#notEmpty issues}}
+ <div class="issue-list">
+ {{#each issues}}
+ <div class="issue" id="issue-{{key}}"></div>
+ {{/each}}
+ </div>
+ {{/notEmpty}}
+ </td>
+ </tr>
+ {{/each}}
+ </table>
+
+ {{#if hasSourceAfter}}
+ <i class="spinner js-component-viewer-source-after"></i>
+ {{/if}}
+
+{{else}}
+
+ <div class="message-error">{{t 'code_viewer.no_source_code_displayed_due_to_security'}}</div>
+
{{/if}}
diff --git a/server/sonar-web/src/main/js/source-viewer/source.js b/server/sonar-web/src/main/js/source-viewer/source.js
index 1ded0471cb7..a620f11245e 100644
--- a/server/sonar-web/src/main/js/source-viewer/source.js
+++ b/server/sonar-web/src/main/js/source-viewer/source.js
@@ -10,7 +10,9 @@ define([
hasSource: false,
hasCoverage: false,
hasDuplications: false,
- hasSCM: false
+ hasSCM: false,
+
+ canSeeCode: true
};
},
diff --git a/server/sonar-web/src/main/js/source-viewer/viewer.js b/server/sonar-web/src/main/js/source-viewer/viewer.js
index d8e8230e9f4..e5f9d49d005 100644
--- a/server/sonar-web/src/main/js/source-viewer/viewer.js
+++ b/server/sonar-web/src/main/js/source-viewer/viewer.js
@@ -72,7 +72,7 @@ define([
},
renderHeader: function () {
- this.headerRegion.show(new HeaderView({ model: this.model }));
+ this.headerRegion.show(new HeaderView({model: this.model}));
},
onRender: function () {
@@ -102,18 +102,22 @@ define([
that.trigger('loaded');
});
};
- this.model.clear();
- this.model.set({
- uuid: id,
- key: key
- });
+ this.model
+ .clear()
+ .set(_.result(this.model, 'defaults'))
+ .set({
+ uuid: id,
+ key: key
+ });
this.requestComponent().done(function () {
that.requestSource()
.done(finalize)
.fail(function () {
- that.model.set({ source: [
- { line: 0 }
- ] });
+ that.model.set({
+ source: [
+ {line: 0}
+ ]
+ });
finalize();
});
});
@@ -123,10 +127,10 @@ define([
requestComponent: function () {
var that = this,
url = baseUrl + '/api/components/app',
- options = { key: this.model.key() };
+ options = {key: this.model.key()};
return $.get(url, options).done(function (data) {
that.model.set(data);
- that.model.set({ isUnitTest: data.q === 'UTS' });
+ that.model.set({isUnitTest: data.q === 'UTS'});
});
},
@@ -154,14 +158,14 @@ define([
requestSource: function () {
var that = this,
url = baseUrl + '/api/sources/lines',
- options = _.extend({ uuid: this.model.id }, this.linesLimit());
- return $.get(url, options, function (data) {
+ options = _.extend({uuid: this.model.id}, this.linesLimit());
+ return $.get(url, options).done(function (data) {
var source = (data.sources || []).slice(0);
if (source.length === 0 || (source.length > 0 && _.first(source).line === 1)) {
- source.unshift({ line: 0 });
+ source.unshift({line: 0});
}
source = source.map(function (row) {
- return _.extend(row, { coverageStatus: that.getCoverageStatus(row) });
+ return _.extend(row, {coverageStatus: that.getCoverageStatus(row)});
});
var firstLine = _.first(source).line,
linesRequested = options.to - options.from + 1;
@@ -170,13 +174,22 @@ define([
hasSourceBefore: firstLine > 1,
hasSourceAfter: data.sources.length === linesRequested
});
+ }).fail(function (request) {
+ if (request.status === 403) {
+ that.model.set({
+ source: [],
+ hasSourceBefore: false,
+ hasSourceAfter: false,
+ canSeeCode: false
+ });
+ }
});
},
requestDuplications: function () {
var that = this,
url = baseUrl + '/api/duplications/show',
- options = { key: this.model.key() };
+ options = {key: this.model.key()};
return $.get(url, options, function (data) {
var hasDuplications = (data != null) && (data.duplications != null),
duplications = [];
@@ -276,7 +289,7 @@ define([
e.stopPropagation();
$('body').click();
var line = +$(e.currentTarget).data('line-number'),
- row = _.findWhere(this.model.get('source'), { line: line }),
+ row = _.findWhere(this.model.get('source'), {line: line}),
popup = new SCMPopupView({
triggerEl: $(e.currentTarget),
model: new Backbone.Model(row)
@@ -289,7 +302,7 @@ define([
$('body').click();
var r = window.process.addBackgroundProcess(),
line = $(e.currentTarget).data('line-number'),
- row = _.findWhere(this.model.get('source'), { line: line }),
+ row = _.findWhere(this.model.get('source'), {line: line}),
url = baseUrl + '/api/tests/test_cases',
options = {
key: this.model.key(),
@@ -437,7 +450,7 @@ define([
return $.get(url, options).done(function (data) {
source = (data.sources || []).concat(source);
if (source.length === 0 || (source.length > 0 && _.first(source).line === 1)) {
- source.unshift({ line: 0 });
+ source.unshift({line: 0});
}
that.model.set({
source: source,
diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/source-viewer-should-not-show-source-if-no-permission.js b/server/sonar-web/src/main/js/tests/e2e/tests/source-viewer-should-not-show-source-if-no-permission.js
new file mode 100644
index 00000000000..49406ab01ee
--- /dev/null
+++ b/server/sonar-web/src/main/js/tests/e2e/tests/source-viewer-should-not-show-source-if-no-permission.js
@@ -0,0 +1,30 @@
+/* global casper:false */
+
+var lib = require('../lib'),
+ testName = lib.testName('Source Viewer');
+
+lib.initMessages();
+lib.changeWorkingDirectory('source-viewer-should-not-show-source-if-no-permission');
+
+
+casper.test.begin(testName('source-viewer-should-not-show-source-if-no-permission'), function (test) {
+ casper
+ .start(lib.buildUrl('source-viewer'), function () {
+ lib.setDefaultViewport();
+
+ lib.mockRequest('/api/l10n/index', '{}');
+ lib.mockRequestFromFile('/api/components/app', 'api-components-app.json');
+ lib.mockRequest('/api/sources/lines', '{}', { status: 403 });
+ lib.mockRequestFromFile('/api/issues/search', 'api-issues-search.json');
+ })
+
+ .then(function () {
+ casper.waitForSelector('.message-error', function () {
+ test.assertDoesntExist('.source-line');
+ });
+ })
+
+ .run(function () {
+ test.done();
+ });
+});
diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/source-viewer-should-not-show-source-if-no-permission/api-components-app.json b/server/sonar-web/src/main/js/tests/e2e/tests/source-viewer-should-not-show-source-if-no-permission/api-components-app.json
new file mode 100644
index 00000000000..25b2e1e70f1
--- /dev/null
+++ b/server/sonar-web/src/main/js/tests/e2e/tests/source-viewer-should-not-show-source-if-no-permission/api-components-app.json
@@ -0,0 +1,95 @@
+{
+ "key": "test:fake-project-for-tests:src/main/java/foo/Simplest.java",
+ "path": "src/main/java/foo/Simplest.java",
+ "name": "Simplest.java",
+ "longName": "src/main/java/foo/Simplest.java",
+ "q": "FIL",
+ "project": "test:fake-project-for-tests",
+ "projectName": "Fake Project for Tests",
+ "fav": false,
+ "canMarkAsFavourite": true,
+ "canBulkChange": true,
+ "canCreateManualIssue": true,
+ "periods": [
+ [
+ 1,
+ "since previous analysis (2014 Dec 09)",
+ "2014-12-09T10:47:33+0100"
+ ],
+ [
+ 2,
+ "over 365 days (2014 Dec 09)",
+ "2014-12-09T10:47:33+0100"
+ ]
+ ],
+ "severities": [
+ [
+ "MINOR",
+ "Minor",
+ 1
+ ],
+ [
+ "MAJOR",
+ "Major",
+ 4
+ ]
+ ],
+ "rules": [
+ [
+ "squid:IndentationCheck",
+ "Source code should be correctly indented",
+ 2
+ ],
+ [
+ "squid:S1118",
+ "Utility classes should not have a public constructor",
+ 1
+ ],
+ [
+ "squid:S00105",
+ "Tabulation characters should not be used",
+ 1
+ ],
+ [
+ "squid:S106",
+ "System.out and System.err should not be used as loggers",
+ 1
+ ]
+ ],
+ "measures": {
+ "fNcloc": "8",
+ "fCoverage": "75.0%",
+ "fDebt": "44min",
+ "fSqaleRating": "C",
+ "fSqaleDebtRatio": "18.3%",
+ "fIssues": "5",
+ "fMinorIssues": "1",
+ "fMajorIssues": "4"
+ },
+ "tabs": [
+ "scm",
+ "coverage"
+ ],
+ "manual_rules": [
+ {
+ "key": "manual:api",
+ "name": "API"
+ },
+ {
+ "key": "manual:design",
+ "name": "Design"
+ },
+ {
+ "key": "manual:error_handling",
+ "name": "Error handling"
+ },
+ {
+ "key": "manual:performance",
+ "name": "Performance"
+ },
+ {
+ "key": "manual:sql_pitfalls",
+ "name": "SQL Pitfall"
+ }
+ ]
+}
diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/source-viewer-should-not-show-source-if-no-permission/api-issues-search.json b/server/sonar-web/src/main/js/tests/e2e/tests/source-viewer-should-not-show-source-if-no-permission/api-issues-search.json
new file mode 100644
index 00000000000..73d6a9fcf3d
--- /dev/null
+++ b/server/sonar-web/src/main/js/tests/e2e/tests/source-viewer-should-not-show-source-if-no-permission/api-issues-search.json
@@ -0,0 +1,234 @@
+{
+ "total": 5,
+ "p": 1,
+ "ps": 100,
+ "projects": [
+ {
+ "uuid": "e07e9bed-f45d-4538-a5e8-77031c1ecae7",
+ "key": "test:fake-project-for-tests",
+ "id": 36125,
+ "qualifier": "TRK",
+ "name": "Fake Project for Tests",
+ "longName": "Fake Project for Tests"
+ }
+ ],
+ "components": [
+ {
+ "uuid": "b4248001-df0c-436a-8acd-a152809b8a23",
+ "key": "test:fake-project-for-tests:src/main/java/foo/Simplest.java",
+ "id": 36129,
+ "enabled": true,
+ "qualifier": "FIL",
+ "name": "Simplest.java",
+ "longName": "src/main/java/foo/Simplest.java",
+ "path": "src/main/java/foo/Simplest.java",
+ "projectId": 36125,
+ "subProjectId": 36125
+ },
+ {
+ "uuid": "e07e9bed-f45d-4538-a5e8-77031c1ecae7",
+ "key": "test:fake-project-for-tests",
+ "id": 36125,
+ "enabled": true,
+ "qualifier": "TRK",
+ "name": "Fake Project for Tests",
+ "longName": "Fake Project for Tests"
+ }
+ ],
+ "issues": [
+ {
+ "key": "91b13078-6f69-4b51-ab0f-8fd0bc391532",
+ "component": "test:fake-project-for-tests:src/main/java/foo/Simplest.java",
+ "componentId": 36129,
+ "project": "test:fake-project-for-tests",
+ "rule": "squid:S00105",
+ "status": "OPEN",
+ "severity": "MINOR",
+ "message": "Replace all tab characters in this file by sequences of white-spaces.",
+ "debt": "2min",
+ "creationDate": "2014-12-09T10:47:33+0100",
+ "updateDate": "2014-12-09T10:47:33+0100",
+ "fUpdateAge": "3 hours",
+ "actions": [
+ "comment",
+ "assign",
+ "assign_to_me",
+ "plan",
+ "set_severity"
+ ],
+ "transitions": [
+ "confirm",
+ "resolve",
+ "falsepositive"
+ ]
+ },
+ {
+ "key": "c18ae6fa-fac7-46b5-bd71-feef7906b05a",
+ "component": "test:fake-project-for-tests:src/main/java/foo/Simplest.java",
+ "componentId": 36129,
+ "project": "test:fake-project-for-tests",
+ "rule": "squid:S1118",
+ "status": "OPEN",
+ "severity": "MAJOR",
+ "message": "Add a private constructor to hide the implicit public one.",
+ "line": 6,
+ "debt": "30min",
+ "creationDate": "2014-12-09T10:47:33+0100",
+ "updateDate": "2014-12-09T10:47:33+0100",
+ "fUpdateAge": "3 hours",
+ "actions": [
+ "comment",
+ "assign",
+ "assign_to_me",
+ "plan",
+ "set_severity"
+ ],
+ "transitions": [
+ "confirm",
+ "resolve",
+ "falsepositive"
+ ]
+ },
+ {
+ "key": "816282ec-0ca9-4d03-b8bc-22b515496fe4",
+ "component": "test:fake-project-for-tests:src/main/java/foo/Simplest.java",
+ "componentId": 36129,
+ "project": "test:fake-project-for-tests",
+ "rule": "squid:IndentationCheck",
+ "status": "OPEN",
+ "severity": "MAJOR",
+ "message": "Make this line start at column 3.",
+ "line": 8,
+ "debt": "1min",
+ "creationDate": "2014-12-09T10:47:33+0100",
+ "updateDate": "2014-12-09T10:47:33+0100",
+ "fUpdateAge": "3 hours",
+ "actions": [
+ "comment",
+ "assign",
+ "assign_to_me",
+ "plan",
+ "set_severity"
+ ],
+ "transitions": [
+ "confirm",
+ "resolve",
+ "falsepositive"
+ ]
+ },
+ {
+ "key": "0229497b-a613-48f3-83ed-2b98983e5e60",
+ "component": "test:fake-project-for-tests:src/main/java/foo/Simplest.java",
+ "componentId": 36129,
+ "project": "test:fake-project-for-tests",
+ "rule": "squid:IndentationCheck",
+ "status": "OPEN",
+ "severity": "MAJOR",
+ "message": "Make this line start at column 5.",
+ "line": 10,
+ "debt": "1min",
+ "creationDate": "2014-12-09T10:47:33+0100",
+ "updateDate": "2014-12-09T10:47:33+0100",
+ "fUpdateAge": "3 hours",
+ "actions": [
+ "comment",
+ "assign",
+ "assign_to_me",
+ "plan",
+ "set_severity"
+ ],
+ "transitions": [
+ "confirm",
+ "resolve",
+ "falsepositive"
+ ]
+ },
+ {
+ "key": "896ccfe0-bb85-4155-be1f-1aaece716539",
+ "component": "test:fake-project-for-tests:src/main/java/foo/Simplest.java",
+ "componentId": 36129,
+ "project": "test:fake-project-for-tests",
+ "rule": "squid:S106",
+ "status": "OPEN",
+ "severity": "MAJOR",
+ "message": "Replace this usage of System.out or System.err by a logger.",
+ "line": 12,
+ "debt": "10min",
+ "creationDate": "2014-12-09T10:47:33+0100",
+ "updateDate": "2014-12-09T10:47:33+0100",
+ "fUpdateAge": "3 hours",
+ "actions": [
+ "comment",
+ "assign",
+ "assign_to_me",
+ "plan",
+ "set_severity"
+ ],
+ "transitions": [
+ "confirm",
+ "resolve",
+ "falsepositive"
+ ]
+ }
+ ],
+ "rules": [
+ {
+ "key": "squid:IndentationCheck",
+ "name": "Source code should be correctly indented",
+ "lang": "java",
+ "desc": "<p>\nProper indentation is a simple and effective way to improve the code's readability.\nConsistent indentation among developers also reduces the differences that are committed to source control systems, making code reviews easier.\n</p>\n\n<p>The following code illustrates this rule with an indentation level of 2:</p>\n\n<pre>\nclass Foo {\n public int a; // Compliant\npublic int b; // Non-Compliant\n}\n</pre>",
+ "status": "READY",
+ "langName": "Java"
+ },
+ {
+ "key": "squid:S1118",
+ "name": "Utility classes should not have a public constructor",
+ "lang": "java",
+ "desc": "<p>\nUtility classes, which are a collection of static members, are not meant to be instantiated.\nThey should therefore not have public constructors.\n</p>\n\n<p>\nJava adds an implicit public constructor to every class which does not define at least one explicitly.\nHence, at least one non-public constructor should be defined.\n</p>\n\n<p>The following code:</p>\n\n<pre>\nclass StringUtils { // Non-Compliant\n\n public static String concatenate(String s1, String s2) {\n return s1 + s2;\n }\n\n}\n</pre>\n\n<p>should be refactored into:</p>\n\n<pre>\nclass StringUtils { // Compliant\n\n private StringUtils() {\n }\n\n public static String concatenate(String s1, String s2) {\n return s1 + s2;\n }\n\n}\n</pre>",
+ "status": "READY",
+ "langName": "Java"
+ },
+ {
+ "key": "squid:S00105",
+ "name": "Tabulation characters should not be used",
+ "lang": "java",
+ "desc": "<p>\nDevelopers should not need to configure the tab width of their text editors in order to be able to read source code.\nSo the use of tabulation character must be banned.\n</p>",
+ "status": "READY",
+ "langName": "Java"
+ },
+ {
+ "key": "squid:S106",
+ "name": "System.out and System.err should not be used as loggers",
+ "lang": "java",
+ "desc": "<p>Two important requirements must be fulfilled when logging messages:</p>\n\n<ul>\n <li>The user must be able to easily retrieve the logs.</li>\n <li>The format of all messages must be uniform to enable users to easily browse them.</li>\n</ul>\n\n<p>\nIf a program directly writes to the standard output, there is absolutely no way to comply with these requirements.\nThat's why defining and using a dedicated logger is highly recommended.\n</p>\n\n<p>\nThe following code snippet illustrates this rule:\n</p>\n\n<pre>\nSystem.out.println(\"My Message\"); // Non-Compliant\n\nlogger.log(\"My Message\"); // Compliant\n</pre>",
+ "status": "READY",
+ "langName": "Java"
+ }
+ ],
+ "users": [
+ {
+ "login": "admin",
+ "name": "Admin Admin",
+ "active": true,
+ "email": "admin@sonarsource.com"
+ }
+ ],
+ "languages": [
+ {
+ "key": "js",
+ "name": "JavaScript"
+ },
+ {
+ "key": "java",
+ "name": "Java"
+ }
+ ],
+ "maxResultsReached": false,
+ "paging": {
+ "pageIndex": 1,
+ "pageSize": 100,
+ "total": 5,
+ "fTotal": "5",
+ "pages": 1
+ }
+}