Add filter for signed test results and related UI
With this patch users can list their own test results. Change-Id: Ie2d944924f6ae966a13d0ca9908810c315ade5ab
This commit is contained in:
parent
217cadd608
commit
2b89f65ad4
@ -26,8 +26,13 @@ refstackApp.config([
|
|||||||
templateUrl: '/components/capabilities/capabilities.html',
|
templateUrl: '/components/capabilities/capabilities.html',
|
||||||
controller: 'capabilitiesController'
|
controller: 'capabilitiesController'
|
||||||
}).
|
}).
|
||||||
state('results', {
|
state('community_results', {
|
||||||
url: '/results',
|
url: '/community_results',
|
||||||
|
templateUrl: '/components/results/results.html',
|
||||||
|
controller: 'resultsController'
|
||||||
|
}).
|
||||||
|
state('user_results', {
|
||||||
|
url: '/user_results',
|
||||||
templateUrl: '/components/results/results.html',
|
templateUrl: '/components/results/results.html',
|
||||||
controller: 'resultsController'
|
controller: 'resultsController'
|
||||||
}).
|
}).
|
||||||
@ -45,19 +50,46 @@ refstackApp.config([
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to authenticate user
|
* Injections in $rootscope
|
||||||
*/
|
*/
|
||||||
|
|
||||||
refstackApp.run(['$http', '$rootScope', 'refstackApiUrl',
|
refstackApp.run(['$http', '$rootScope', '$window', 'refstackApiUrl',
|
||||||
function($http, $rootScope, refstackApiUrl) {
|
function($http, $rootScope, $window, refstackApiUrl) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function injects sign in function in all scopes
|
||||||
|
*/
|
||||||
|
|
||||||
|
$rootScope.auth = {};
|
||||||
|
|
||||||
|
var sign_in_url = refstackApiUrl + '/auth/signin';
|
||||||
|
$rootScope.auth.doSignIn = function () {
|
||||||
|
$window.location.href = sign_in_url;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function injects sign out function in all scopes
|
||||||
|
*/
|
||||||
|
var sign_out_url = refstackApiUrl + '/auth/signout';
|
||||||
|
$rootScope.auth.doSignOut = function () {
|
||||||
|
$rootScope.currentUser = null;
|
||||||
|
$rootScope.isAuthenticated = false;
|
||||||
|
$window.location.href = sign_out_url;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This block tries to authenticate user
|
||||||
|
*/
|
||||||
var profile_url = refstackApiUrl + '/profile';
|
var profile_url = refstackApiUrl + '/profile';
|
||||||
$http.get(profile_url, {withCredentials: true}).
|
$http.get(profile_url, {withCredentials: true}).
|
||||||
success(function(data) {
|
success(function(data) {
|
||||||
$rootScope.currentUser = data;
|
$rootScope.auth.currentUser = data;
|
||||||
|
$rootScope.auth.isAuthenticated = true;
|
||||||
}).
|
}).
|
||||||
error(function() {
|
error(function() {
|
||||||
$rootScope.currentUser = null;
|
$rootScope.auth.currentUser = null;
|
||||||
|
$rootScope.auth.isAuthenticated = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
var refstackApp = angular.module('refstackApp');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Refstack Auth Controller
|
|
||||||
* This controller handles account authentication for users.
|
|
||||||
*/
|
|
||||||
|
|
||||||
refstackApp.controller('authController',
|
|
||||||
['$scope', '$window', '$rootScope', 'refstackApiUrl',
|
|
||||||
function($scope, $window, $rootScope, refstackApiUrl){
|
|
||||||
'use strict';
|
|
||||||
var sign_in_url = refstackApiUrl + '/auth/signin';
|
|
||||||
$scope.doSignIn = function () {
|
|
||||||
$window.location.href = sign_in_url;
|
|
||||||
};
|
|
||||||
|
|
||||||
var sign_out_url = refstackApiUrl + '/auth/signout';
|
|
||||||
$scope.doSignOut = function () {
|
|
||||||
$rootScope.currentUser = null;
|
|
||||||
$window.location.href = sign_out_url;
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.isAuthenticated = function () {
|
|
||||||
if ($scope.currentUser) {
|
|
||||||
return !!$scope.currentUser.openid;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
}]);
|
|
@ -58,7 +58,7 @@
|
|||||||
<div cg-busy="{promise:capsRequest,message:'Loading capabilities'}"></div>
|
<div cg-busy="{promise:capsRequest,message:'Loading capabilities'}"></div>
|
||||||
|
|
||||||
<!-- Get the version-specific template -->
|
<!-- Get the version-specific template -->
|
||||||
<div ng-include src="detailsTemplate"></header>
|
<div ng-include src="detailsTemplate"></div>
|
||||||
|
|
||||||
<div ng-show="showError" class="alert alert-danger" role="alert">
|
<div ng-show="showError" class="alert alert-danger" role="alert">
|
||||||
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
|
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<h3>User profile</h3>
|
<h3>User profile</h3>
|
||||||
|
|
||||||
<div ng-show="user">
|
<div>
|
||||||
<table ng-show="user" class="table table-striped table-hover">
|
<table class="table table-striped table-hover">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr> <td>User name</td> <td>{{user.fullname}}</td> </tr>
|
<tr> <td>User name</td> <td>{{auth.currentUser.fullname}}</td> </tr>
|
||||||
<tr> <td>User OpenId</td> <td>{{user.openid}}</td> </tr>
|
<tr> <td>User OpenId</td> <td>{{auth.currentUser.openid}}</td> </tr>
|
||||||
<tr> <td>Email</td> <td>{{user.email}}</td> </tr>
|
<tr> <td>Email</td> <td>{{auth.currentUser.email}}</td> </tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@ -22,8 +22,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-show="pubkeys">
|
<div>
|
||||||
<table ng-show="pubkeys" class="table table-striped table-hover">
|
<table class="table table-striped table-hover">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="pubKey in pubkeys" ng-click="openShowPubKeyModal(pubKey)">
|
<tr ng-repeat="pubKey in pubkeys" ng-click="openShowPubKeyModal(pubKey)">
|
||||||
<td>{{pubKey.format}}</td>
|
<td>{{pubKey.format}}</td>
|
||||||
@ -33,4 +33,3 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -19,16 +19,6 @@ refstackApp.controller('profileController',
|
|||||||
function($scope, $http, refstackApiUrl, $state,
|
function($scope, $http, refstackApiUrl, $state,
|
||||||
PubKeys, $modal, raiseAlert) {
|
PubKeys, $modal, raiseAlert) {
|
||||||
'use strict';
|
'use strict';
|
||||||
$scope.updateProfile = function () {
|
|
||||||
var profile_url = refstackApiUrl + '/profile';
|
|
||||||
$http.get(profile_url, {withCredentials: true}).
|
|
||||||
success(function(data) {
|
|
||||||
$scope.user = data;
|
|
||||||
}).
|
|
||||||
error(function() {
|
|
||||||
$state.go('home');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.updatePubKeys = function (){
|
$scope.updatePubKeys = function (){
|
||||||
var keys = PubKeys.query(function(){
|
var keys = PubKeys.query(function(){
|
||||||
@ -77,7 +67,6 @@ refstackApp.controller('profileController',
|
|||||||
$scope.showRes = function(pubKey){
|
$scope.showRes = function(pubKey){
|
||||||
raiseAlert('success', '', pubKey.key);
|
raiseAlert('success', '', pubKey.key);
|
||||||
};
|
};
|
||||||
$scope.updateProfile();
|
|
||||||
$scope.updatePubKeys();
|
$scope.updatePubKeys();
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<h3>Community Results</h3>
|
<h3>{{pageHeader}}</h3>
|
||||||
<p>The most recently uploaded community test results are listed here. Currently, these results are anonymous.</p>
|
<p>The most recently uploaded community test results are listed here. Currently, these results are anonymous.</p>
|
||||||
|
|
||||||
<div class="result-filters">
|
<div class="result-filters">
|
||||||
|
@ -6,8 +6,8 @@ var refstackApp = angular.module('refstackApp');
|
|||||||
* a listing of community uploaded results.
|
* a listing of community uploaded results.
|
||||||
*/
|
*/
|
||||||
refstackApp.controller('resultsController',
|
refstackApp.controller('resultsController',
|
||||||
['$scope', '$http', '$filter', 'refstackApiUrl',
|
['$scope', '$http', '$filter', '$state', 'refstackApiUrl',
|
||||||
function ($scope, $http, $filter, refstackApiUrl) {
|
function ($scope, $http, $filter, $state, refstackApiUrl) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/** Initial page to be on. */
|
/** Initial page to be on. */
|
||||||
@ -33,6 +33,9 @@ refstackApp.controller('resultsController',
|
|||||||
/** The upload date upper limit to be used in filtering results. */
|
/** The upload date upper limit to be used in filtering results. */
|
||||||
$scope.endDate = '';
|
$scope.endDate = '';
|
||||||
|
|
||||||
|
$scope.isUserResults = $state.current.name === 'user_results';
|
||||||
|
$scope.pageHeader = $scope.isUserResults ?
|
||||||
|
'Private test results' : 'Community test results';
|
||||||
/**
|
/**
|
||||||
* This will contact the Refstack API to get a listing of test run
|
* This will contact the Refstack API to get a listing of test run
|
||||||
* results.
|
* results.
|
||||||
@ -51,7 +54,9 @@ refstackApp.controller('resultsController',
|
|||||||
if (end) {
|
if (end) {
|
||||||
content_url = content_url + '&end_date=' + end + ' 23:59:59';
|
content_url = content_url + '&end_date=' + end + ' 23:59:59';
|
||||||
}
|
}
|
||||||
|
if ($scope.isUserResults) {
|
||||||
|
content_url = content_url + '&signed';
|
||||||
|
}
|
||||||
$scope.resultsRequest =
|
$scope.resultsRequest =
|
||||||
$http.get(content_url).success(function (data) {
|
$http.get(content_url).success(function (data) {
|
||||||
$scope.data = data;
|
$scope.data = data;
|
||||||
|
@ -38,12 +38,11 @@
|
|||||||
|
|
||||||
<!-- Controllers -->
|
<!-- Controllers -->
|
||||||
<script src="shared/header/headerController.js"></script>
|
<script src="shared/header/headerController.js"></script>
|
||||||
|
<script src="shared/alerts/alertModalFactory.js"></script>
|
||||||
<script src="components/capabilities/capabilitiesController.js"></script>
|
<script src="components/capabilities/capabilitiesController.js"></script>
|
||||||
<script src="components/results/resultsController.js"></script>
|
<script src="components/results/resultsController.js"></script>
|
||||||
<script src="components/results-report/resultsReportController.js"></script>
|
<script src="components/results-report/resultsReportController.js"></script>
|
||||||
<script src="components/profile/profileController.js"></script>
|
<script src="components/profile/profileController.js"></script>
|
||||||
<script src="components/auth/authController.js"></script>
|
|
||||||
<script src="components/alerts/alertModalFactory.js"></script>
|
|
||||||
|
|
||||||
<!-- Filters -->
|
<!-- Filters -->
|
||||||
<script src="shared/filters.js"></script>
|
<script src="shared/filters.js"></script>
|
||||||
|
@ -5,7 +5,7 @@ refstackApp.factory('raiseAlert',
|
|||||||
'use strict';
|
'use strict';
|
||||||
return function(mode, title, text) {
|
return function(mode, title, text) {
|
||||||
$modal.open({
|
$modal.open({
|
||||||
templateUrl: '/components/alerts/alertModal.html',
|
templateUrl: '/shared/alerts/alertModal.html',
|
||||||
controller: 'raiseAlertModalController',
|
controller: 'raiseAlertModalController',
|
||||||
backdrop: true,
|
backdrop: true,
|
||||||
keyboard: true,
|
keyboard: true,
|
@ -18,14 +18,14 @@ Refstack
|
|||||||
<li ng-class="{ active: isActive('/')}"><a ui-sref="home">Home</a></li>
|
<li ng-class="{ active: isActive('/')}"><a ui-sref="home">Home</a></li>
|
||||||
<li ng-class="{ active: isActive('/about')}"><a ui-sref="about">About</a></li>
|
<li ng-class="{ active: isActive('/about')}"><a ui-sref="about">About</a></li>
|
||||||
<li ng-class="{ active: isActive('/capabilities')}"><a ui-sref="capabilities">DefCore Capabilities</a></li>
|
<li ng-class="{ active: isActive('/capabilities')}"><a ui-sref="capabilities">DefCore Capabilities</a></li>
|
||||||
<li ng-class="{ active: isActive('/results')}"><a ui-sref="results">Community Results</a></li>
|
<li ng-class="{ active: isActive('/community_results')}"><a ui-sref="community_results">Community Results</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul ng-controller="authController" class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li ng-class="{ active: isActive('/profile')}" ng-if="isAuthenticated()"><a ui-sref="profile">{{currentUser.fullname}}</a></li>
|
<li ng-class="{ active: isActive('/user_results')}" ng-if="auth.isAuthenticated"><a ui-sref="user_results">My Results</a></li>
|
||||||
<li ng-if="isAuthenticated()"><a href="" ng-click="doSignOut()">Sign Out</a></li>
|
<li ng-class="{ active: isActive('/profile')}" ng-if="auth.isAuthenticated"><a ui-sref="profile">Profile</a></li>
|
||||||
<li ng-if="!isAuthenticated()"><a href="" ng-click="doSignIn()">Sign In / Sign Up</a></li>
|
<li ng-if="auth.isAuthenticated"><a href="" ng-click="auth.doSignOut()">Sign Out</a></li>
|
||||||
|
<li ng-if="!auth.isAuthenticated"><a href="" ng-click="auth.doSignIn()">Sign In / Sign Up</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
40
refstack-ui/tests/unit/AuthSpec.js
Normal file
40
refstack-ui/tests/unit/AuthSpec.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
describe('Auth', function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var fakeApiUrl = 'http://foo.bar/v1';
|
||||||
|
var $window;
|
||||||
|
beforeEach(function () {
|
||||||
|
$window = {location: { href: jasmine.createSpy()} };
|
||||||
|
module(function ($provide) {
|
||||||
|
$provide.constant('refstackApiUrl', fakeApiUrl);
|
||||||
|
$provide.value('$window', $window);
|
||||||
|
});
|
||||||
|
module('refstackApp');
|
||||||
|
});
|
||||||
|
|
||||||
|
var $rootScope, $httpBackend;
|
||||||
|
beforeEach(inject(function (_$httpBackend_, _$rootScope_) {
|
||||||
|
$httpBackend = _$httpBackend_;
|
||||||
|
$rootScope = _$rootScope_;
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should show signin url for signed user', function () {
|
||||||
|
$httpBackend.expectGET(fakeApiUrl +
|
||||||
|
'/profile').respond({'openid': 'foo@bar.com',
|
||||||
|
'email': 'foo@bar.com',
|
||||||
|
'fullname': 'foo' });
|
||||||
|
$httpBackend.flush();
|
||||||
|
$rootScope.auth.doSignIn();
|
||||||
|
expect($window.location.href).toBe(fakeApiUrl + '/auth/signin');
|
||||||
|
expect($rootScope.auth.isAuthenticated).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show signout url for not signed user', function () {
|
||||||
|
$httpBackend.expectGET(fakeApiUrl +
|
||||||
|
'/profile').respond(401);
|
||||||
|
$httpBackend.flush();
|
||||||
|
$rootScope.auth.doSignOut();
|
||||||
|
expect($window.location.href).toBe(fakeApiUrl + '/auth/signout');
|
||||||
|
expect($rootScope.auth.isAuthenticated).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
@ -3,11 +3,18 @@ describe('Refstack controllers', function () {
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var fakeApiUrl = 'http://foo.bar/v1';
|
var fakeApiUrl = 'http://foo.bar/v1';
|
||||||
|
var $httpBackend;
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
module(function ($provide) {
|
module(function ($provide) {
|
||||||
$provide.constant('refstackApiUrl', fakeApiUrl);
|
$provide.constant('refstackApiUrl', fakeApiUrl);
|
||||||
});
|
});
|
||||||
module('refstackApp');
|
module('refstackApp');
|
||||||
|
inject(function(_$httpBackend_){
|
||||||
|
$httpBackend = _$httpBackend_;
|
||||||
|
});
|
||||||
|
$httpBackend.whenGET(fakeApiUrl + '/profile').respond(401);
|
||||||
|
$httpBackend.whenGET('/components/home/home.html')
|
||||||
|
.respond('<div>mock template</div>');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('headerController', function () {
|
describe('headerController', function () {
|
||||||
@ -36,42 +43,10 @@ describe('Refstack controllers', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('authController', function () {
|
|
||||||
var scope, $httpBackend, $window;
|
|
||||||
|
|
||||||
beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) {
|
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
scope = $rootScope.$new();
|
|
||||||
$window = {location: { href: jasmine.createSpy()} };
|
|
||||||
$controller('authController', {$scope: scope, $window: $window});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should show signin url for signed user', function () {
|
|
||||||
$httpBackend.expectGET(fakeApiUrl +
|
|
||||||
'/profile').respond({'openid': 'foo@bar.com',
|
|
||||||
'email': 'foo@bar.com',
|
|
||||||
'fullname': 'foo' });
|
|
||||||
$httpBackend.flush();
|
|
||||||
scope.doSignIn();
|
|
||||||
expect($window.location.href).toBe(fakeApiUrl + '/auth/signin');
|
|
||||||
expect(scope.isAuthenticated()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show signout url for not signed user', function () {
|
|
||||||
$httpBackend.expectGET(fakeApiUrl +
|
|
||||||
'/profile').respond(401);
|
|
||||||
$httpBackend.flush();
|
|
||||||
scope.doSignOut();
|
|
||||||
expect($window.location.href).toBe(fakeApiUrl + '/auth/signout');
|
|
||||||
expect(scope.isAuthenticated()).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('capabilitiesController', function () {
|
describe('capabilitiesController', function () {
|
||||||
var scope, $httpBackend;
|
var scope;
|
||||||
|
|
||||||
beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) {
|
beforeEach(inject(function ($rootScope, $controller) {
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
scope = $rootScope.$new();
|
scope = $rootScope.$new();
|
||||||
$controller('capabilitiesController', {$scope: scope});
|
$controller('capabilitiesController', {$scope: scope});
|
||||||
}));
|
}));
|
||||||
@ -102,8 +77,6 @@ describe('Refstack controllers', function () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$httpBackend.expectGET(fakeApiUrl +
|
|
||||||
'/profile').respond(401);
|
|
||||||
$httpBackend.expectGET(fakeApiUrl +
|
$httpBackend.expectGET(fakeApiUrl +
|
||||||
'/capabilities').respond(['2015.03.json', '2015.04.json']);
|
'/capabilities').respond(['2015.03.json', '2015.04.json']);
|
||||||
// Should call request with latest version.
|
// Should call request with latest version.
|
||||||
@ -170,7 +143,7 @@ describe('Refstack controllers', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('resultsController', function () {
|
describe('resultsController', function () {
|
||||||
var scope, $httpBackend;
|
var scope;
|
||||||
var fakeResponse = {
|
var fakeResponse = {
|
||||||
'pagination': {'current_page': 1, 'total_pages': 2},
|
'pagination': {'current_page': 1, 'total_pages': 2},
|
||||||
'results': [{
|
'results': [{
|
||||||
@ -180,8 +153,7 @@ describe('Refstack controllers', function () {
|
|||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) {
|
beforeEach(inject(function ($rootScope, $controller) {
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
scope = $rootScope.$new();
|
scope = $rootScope.$new();
|
||||||
$controller('resultsController', {$scope: scope});
|
$controller('resultsController', {$scope: scope});
|
||||||
}));
|
}));
|
||||||
@ -189,9 +161,8 @@ describe('Refstack controllers', function () {
|
|||||||
it('should fetch the first page of results with proper URL args',
|
it('should fetch the first page of results with proper URL args',
|
||||||
function () {
|
function () {
|
||||||
// Initial results should be page 1 of all results.
|
// Initial results should be page 1 of all results.
|
||||||
$httpBackend.expectGET(fakeApiUrl + '/profile').respond(401);
|
$httpBackend.expectGET(fakeApiUrl + '/results?page=1')
|
||||||
$httpBackend.expectGET(fakeApiUrl +
|
.respond(fakeResponse);
|
||||||
'/results?page=1').respond(fakeResponse);
|
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
expect(scope.data).toEqual(fakeResponse);
|
expect(scope.data).toEqual(fakeResponse);
|
||||||
expect(scope.currentPage).toBe(1);
|
expect(scope.currentPage).toBe(1);
|
||||||
@ -211,7 +182,6 @@ describe('Refstack controllers', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should set an error when results cannot be retrieved', function () {
|
it('should set an error when results cannot be retrieved', function () {
|
||||||
$httpBackend.expectGET(fakeApiUrl + '/profile').respond(401);
|
|
||||||
$httpBackend.expectGET(fakeApiUrl + '/results?page=1').respond(404,
|
$httpBackend.expectGET(fakeApiUrl + '/results?page=1').respond(404,
|
||||||
{'detail': 'Not Found'});
|
{'detail': 'Not Found'});
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
@ -224,23 +194,16 @@ describe('Refstack controllers', function () {
|
|||||||
|
|
||||||
it('should have an function to clear filters and update the view',
|
it('should have an function to clear filters and update the view',
|
||||||
function () {
|
function () {
|
||||||
$httpBackend.expectGET(fakeApiUrl + '/profile').respond(401);
|
|
||||||
$httpBackend.expectGET(fakeApiUrl +
|
|
||||||
'/results?page=1').respond(fakeResponse);
|
|
||||||
scope.startDate = 'some date';
|
scope.startDate = 'some date';
|
||||||
scope.endDate = 'some other date';
|
scope.endDate = 'some other date';
|
||||||
scope.clearFilters();
|
scope.clearFilters();
|
||||||
expect(scope.startDate).toBe(null);
|
expect(scope.startDate).toBe(null);
|
||||||
expect(scope.endDate).toBe(null);
|
expect(scope.endDate).toBe(null);
|
||||||
$httpBackend.expectGET(fakeApiUrl +
|
|
||||||
'/results?page=1').respond(fakeResponse);
|
|
||||||
$httpBackend.flush();
|
|
||||||
expect(scope.data).toEqual(fakeResponse);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('resultsReportController', function () {
|
describe('resultsReportController', function () {
|
||||||
var scope, $httpBackend, stateparams;
|
var scope, stateparams;
|
||||||
var fakeResultResponse = {'results': ['test_id_1']};
|
var fakeResultResponse = {'results': ['test_id_1']};
|
||||||
var fakeCapabilityResponse = {
|
var fakeCapabilityResponse = {
|
||||||
'platform': {'required': ['compute']},
|
'platform': {'required': ['compute']},
|
||||||
@ -261,8 +224,7 @@ describe('Refstack controllers', function () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) {
|
beforeEach(inject(function ($rootScope, $controller) {
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
stateparams = {testID: 1234};
|
stateparams = {testID: 1234};
|
||||||
scope = $rootScope.$new();
|
scope = $rootScope.$new();
|
||||||
$controller('resultsReportController',
|
$controller('resultsReportController',
|
||||||
@ -272,7 +234,6 @@ describe('Refstack controllers', function () {
|
|||||||
it('should make all necessary API requests to get results ' +
|
it('should make all necessary API requests to get results ' +
|
||||||
'and capabilities',
|
'and capabilities',
|
||||||
function () {
|
function () {
|
||||||
$httpBackend.expectGET(fakeApiUrl + '/profile').respond(401);
|
|
||||||
$httpBackend.expectGET(fakeApiUrl +
|
$httpBackend.expectGET(fakeApiUrl +
|
||||||
'/results/1234').respond(fakeResultResponse);
|
'/results/1234').respond(fakeResultResponse);
|
||||||
$httpBackend.expectGET(fakeApiUrl +
|
$httpBackend.expectGET(fakeApiUrl +
|
||||||
|
@ -19,6 +19,7 @@ START_DATE = 'start_date'
|
|||||||
END_DATE = 'end_date'
|
END_DATE = 'end_date'
|
||||||
CPID = 'cpid'
|
CPID = 'cpid'
|
||||||
PAGE = 'page'
|
PAGE = 'page'
|
||||||
|
SIGNED = 'signed'
|
||||||
|
|
||||||
# OpenID parameters
|
# OpenID parameters
|
||||||
OPENID_MODE = 'openid.mode'
|
OPENID_MODE = 'openid.mode'
|
||||||
@ -36,3 +37,6 @@ OPENID_ERROR = 'openid.error'
|
|||||||
# User session parameters
|
# User session parameters
|
||||||
CSRF_TOKEN = 'csrf_token'
|
CSRF_TOKEN = 'csrf_token'
|
||||||
USER_OPENID = 'user_openid'
|
USER_OPENID = 'user_openid'
|
||||||
|
|
||||||
|
# Test metadata fields
|
||||||
|
PUBLIC_KEY = 'public_key'
|
||||||
|
@ -55,7 +55,7 @@ class ResultsController(validation.BaseRestControllerWithValidation):
|
|||||||
if pecan.request.headers.get('X-Public-Key'):
|
if pecan.request.headers.get('X-Public-Key'):
|
||||||
if 'metadata' not in item:
|
if 'metadata' not in item:
|
||||||
item['metadata'] = {}
|
item['metadata'] = {}
|
||||||
item['metadata']['public_key'] = \
|
item['metadata'][const.PUBLIC_KEY] = \
|
||||||
pecan.request.headers.get('X-Public-Key')
|
pecan.request.headers.get('X-Public-Key')
|
||||||
test_id = db.store_results(item)
|
test_id = db.store_results(item)
|
||||||
LOG.debug(item)
|
LOG.debug(item)
|
||||||
@ -79,6 +79,7 @@ class ResultsController(validation.BaseRestControllerWithValidation):
|
|||||||
const.START_DATE,
|
const.START_DATE,
|
||||||
const.END_DATE,
|
const.END_DATE,
|
||||||
const.CPID,
|
const.CPID,
|
||||||
|
const.SIGNED
|
||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -88,9 +89,6 @@ class ResultsController(validation.BaseRestControllerWithValidation):
|
|||||||
api_utils.get_page_number(records_count)
|
api_utils.get_page_number(records_count)
|
||||||
except api_utils.ParseInputsError as ex:
|
except api_utils.ParseInputsError as ex:
|
||||||
pecan.abort(400, 'Reason: %s' % ex)
|
pecan.abort(400, 'Reason: %s' % ex)
|
||||||
except Exception as ex:
|
|
||||||
LOG.debug('An error occurred: %s' % ex)
|
|
||||||
pecan.abort(500)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
per_page = CONF.api.results_per_page
|
per_page = CONF.api.results_per_page
|
||||||
@ -102,7 +100,8 @@ class ResultsController(validation.BaseRestControllerWithValidation):
|
|||||||
'test_id': r.id,
|
'test_id': r.id,
|
||||||
'created_at': r.created_at,
|
'created_at': r.created_at,
|
||||||
'cpid': r.cpid,
|
'cpid': r.cpid,
|
||||||
'url': CONF.api.test_results_url % r.id
|
'url': parse.urljoin(CONF.ui_url,
|
||||||
|
CONF.api.test_results_url) % r.id
|
||||||
})
|
})
|
||||||
|
|
||||||
page = {'results': results,
|
page = {'results': results,
|
||||||
|
@ -86,6 +86,16 @@ def parse_input_params(expected_input_params):
|
|||||||
'start': const.START_DATE,
|
'start': const.START_DATE,
|
||||||
'end': const.END_DATE
|
'end': const.END_DATE
|
||||||
})
|
})
|
||||||
|
if const.SIGNED in filters:
|
||||||
|
if is_authenticated():
|
||||||
|
filters['openid'] = get_user_id()
|
||||||
|
filters['pubkeys'] = [
|
||||||
|
' '.join((pk['format'], pk['key']))
|
||||||
|
for pk in db.get_user_pubkeys(filters['openid'])
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
raise ParseInputsError('To see signed test '
|
||||||
|
'results you need to authenticate')
|
||||||
return filters
|
return filters
|
||||||
|
|
||||||
|
|
||||||
@ -176,6 +186,11 @@ def get_user():
|
|||||||
return db.user_get(get_user_id())
|
return db.user_get(get_user_id())
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_public_keys():
|
||||||
|
"""Return db record for authenticated user."""
|
||||||
|
return db.get_user_pubkeys(get_user_id())
|
||||||
|
|
||||||
|
|
||||||
def is_authenticated():
|
def is_authenticated():
|
||||||
"""Return True if user is authenticated."""
|
"""Return True if user is authenticated."""
|
||||||
if get_user_id():
|
if get_user_id():
|
||||||
|
@ -34,6 +34,7 @@ def upgrade():
|
|||||||
sa.ForeignKeyConstraint(['openid'], ['user.openid'], ),
|
sa.ForeignKeyConstraint(['openid'], ['user.openid'], ),
|
||||||
mysql_charset=MYSQL_CHARSET
|
mysql_charset=MYSQL_CHARSET
|
||||||
)
|
)
|
||||||
|
op.create_index('indx_meta_value', 'meta', ['value'], mysql_length=32)
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
def downgrade():
|
||||||
|
@ -117,6 +117,19 @@ def _apply_filters_for_query(query, filters):
|
|||||||
if cpid:
|
if cpid:
|
||||||
query = query.filter(models.Test.cpid == cpid)
|
query = query.filter(models.Test.cpid == cpid)
|
||||||
|
|
||||||
|
signed = api_const.SIGNED in filters
|
||||||
|
if signed:
|
||||||
|
query = (query
|
||||||
|
.join(models.Test.meta)
|
||||||
|
.filter(models.TestMeta.meta_key == api_const.PUBLIC_KEY)
|
||||||
|
.filter(models.TestMeta.value.in_(filters['pubkeys']))
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
signed_results = (query.session
|
||||||
|
.query(models.TestMeta.test_id)
|
||||||
|
.filter_by(meta_key=api_const.PUBLIC_KEY))
|
||||||
|
query = query.filter(models.Test.id.notin_(signed_results))
|
||||||
|
|
||||||
return query
|
return query
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ class ResultsControllerTestCase(base.BaseTestCase):
|
|||||||
'url': self.test_results_url % 'fake_test_id'})
|
'url': self.test_results_url % 'fake_test_id'})
|
||||||
self.assertEqual(mock_response.status, 201)
|
self.assertEqual(mock_response.status, 201)
|
||||||
mock_store_results.assert_called_once_with(
|
mock_store_results.assert_called_once_with(
|
||||||
{'answer': 42, 'metadata': {'public_key': 'fake-key'}}
|
{'answer': 42, 'metadata': {const.PUBLIC_KEY: 'fake-key'}}
|
||||||
)
|
)
|
||||||
|
|
||||||
@mock.patch('pecan.abort')
|
@mock.patch('pecan.abort')
|
||||||
@ -216,6 +216,7 @@ class ResultsControllerTestCase(base.BaseTestCase):
|
|||||||
const.START_DATE,
|
const.START_DATE,
|
||||||
const.END_DATE,
|
const.END_DATE,
|
||||||
const.CPID,
|
const.CPID,
|
||||||
|
const.SIGNED
|
||||||
]
|
]
|
||||||
page_number = 1
|
page_number = 1
|
||||||
total_pages_number = 10
|
total_pages_number = 10
|
||||||
|
@ -193,9 +193,12 @@ class DBBackendTestCase(base.BaseTestCase):
|
|||||||
self.assertEqual(expected_result, actual_result)
|
self.assertEqual(expected_result, actual_result)
|
||||||
|
|
||||||
@mock.patch('refstack.db.sqlalchemy.models.Test')
|
@mock.patch('refstack.db.sqlalchemy.models.Test')
|
||||||
def test_apply_filters_for_query(self, mock_model):
|
@mock.patch('refstack.db.sqlalchemy.models.TestMeta')
|
||||||
|
def test_apply_filters_for_query_unsigned(self, mock_meta,
|
||||||
|
mock_test):
|
||||||
query = mock.Mock()
|
query = mock.Mock()
|
||||||
mock_model.created_at = six.text_type()
|
mock_test.created_at = six.text_type()
|
||||||
|
mock_meta.test_id = six.text_type()
|
||||||
|
|
||||||
filters = {
|
filters = {
|
||||||
api_const.START_DATE: 'fake1',
|
api_const.START_DATE: 'fake1',
|
||||||
@ -205,19 +208,30 @@ class DBBackendTestCase(base.BaseTestCase):
|
|||||||
|
|
||||||
result = api._apply_filters_for_query(query, filters)
|
result = api._apply_filters_for_query(query, filters)
|
||||||
|
|
||||||
query.filter.assert_called_once_with(mock_model.created_at >=
|
query.filter.assert_called_once_with(mock_test.created_at >=
|
||||||
filters[api_const.START_DATE])
|
filters[api_const.START_DATE])
|
||||||
|
|
||||||
query = query.filter.return_value
|
query = query.filter.return_value
|
||||||
query.filter.assert_called_once_with(mock_model.created_at <=
|
query.filter.assert_called_once_with(mock_test.created_at <=
|
||||||
filters[api_const.END_DATE])
|
filters[api_const.END_DATE])
|
||||||
|
|
||||||
query = query.filter.return_value
|
query = query.filter.return_value
|
||||||
query.filter.assert_called_once_with(mock_model.cpid ==
|
query.filter.assert_called_once_with(mock_test.cpid ==
|
||||||
filters[api_const.CPID])
|
filters[api_const.CPID])
|
||||||
|
|
||||||
query = query.filter.return_value
|
query = query.filter.return_value
|
||||||
self.assertEqual(result, query)
|
|
||||||
|
query.session.query.assert_called_once_with(mock_meta.test_id)
|
||||||
|
meta_query = query.session.query.return_value
|
||||||
|
|
||||||
|
meta_query.filter_by.\
|
||||||
|
assert_called_once_with(meta_key=api_const.PUBLIC_KEY)
|
||||||
|
unsigned_test_id_query = meta_query.filter_by.return_value
|
||||||
|
mock_test.id.notin_.assert_called_once_with(unsigned_test_id_query)
|
||||||
|
query.filter.assert_called_once_with(mock_test.id.notin_.return_value)
|
||||||
|
|
||||||
|
filtered_query = query.filter.return_value
|
||||||
|
self.assertEqual(result, filtered_query)
|
||||||
|
|
||||||
@mock.patch.object(api, '_apply_filters_for_query')
|
@mock.patch.object(api, '_apply_filters_for_query')
|
||||||
@mock.patch.object(api, 'get_session')
|
@mock.patch.object(api, 'get_session')
|
||||||
|
@ -8,6 +8,5 @@ oslotest>=1.2.0 # Apache-2.0
|
|||||||
python-subunit>=0.0.18
|
python-subunit>=0.0.18
|
||||||
testrepository>=0.0.18
|
testrepository>=0.0.18
|
||||||
testtools>=0.9.34
|
testtools>=0.9.34
|
||||||
mysqlclient
|
|
||||||
six>=1.7.0
|
six>=1.7.0
|
||||||
pep257>=0.5.0
|
pep257>=0.5.0
|
Loading…
x
Reference in New Issue
Block a user