mirror of
https://github.com/wahyd4/pinpoint.git
synced 2026-08-18 01:06:03 +10:00
[임대현] #94 기간 조회 URL에서 time을 사람이 알아볼수 있는 형태로 지원해 주었으면 함.
git-svn-id: http://svn.bds.nhncorp.com/pe/hippo-web/trunk@3748 84d0f5b1-2673-498c-a247-62c4ff18d310
This commit is contained in:
@@ -8,19 +8,19 @@ pinpointApp.config(['$routeProvider', '$locationProvider', '$modalProvider', fun
|
||||
$routeProvider.when('/main', {
|
||||
templateUrl: 'views/ready.html',
|
||||
controller: 'MainCtrl'
|
||||
}).when('/main/:application/:period/:queryEndTime', {
|
||||
}).when('/main/:application/:readablePeriod/:queryEndDateTime', {
|
||||
templateUrl: 'views/main.html',
|
||||
controller: 'MainCtrl'
|
||||
}).when('/filteredMap/:application/:period/:queryEndTime/:filter', {
|
||||
}).when('/filteredMap/:application/:readablePeriod/:queryEndDateTime/:filter', {
|
||||
templateUrl: 'views/filteredMap.html',
|
||||
controller: 'FilteredMapCtrl'
|
||||
}).when('/inspecator/:pplication/:period/:queryEndTime', {
|
||||
}).when('/inspecator/:pplication/:readablePeriod/:queryEndDateTime', {
|
||||
templateUrl: 'views/inspector.html',
|
||||
controller: 'InspectorCtrl'
|
||||
}).when('/inspector/:application/:period/:queryEndTime/:agentId', {
|
||||
}).when('/inspector/:application/:readablePeriod/:queryEndDateTime/:agentId', {
|
||||
templateUrl: 'views/inspector.html',
|
||||
controller: 'InspectorCtrl'
|
||||
}).when('/transactionList/:application/:period/:queryEndTime', {
|
||||
}).when('/transactionList/:application/:readablePeriod/:queryEndDateTime', {
|
||||
templateUrl: 'views/transactionList.html',
|
||||
controller: 'TransactionListCtrl'
|
||||
}).when('/transactionDetail', {
|
||||
@@ -32,10 +32,10 @@ pinpointApp.config(['$routeProvider', '$locationProvider', '$modalProvider', fun
|
||||
}).when('/transactionView/:agentId/:traceId/:focusTimestamp', {
|
||||
templateUrl: 'views/transactionView.html',
|
||||
controller: 'TransactionViewCtrl'
|
||||
}).when('/scatterFullScreenMode/:application/:period/:queryEndTime', {
|
||||
}).when('/scatterFullScreenMode/:application/:readablePeriod/:queryEndDateTime', {
|
||||
templateUrl: 'views/scatterFullScreenMode.html',
|
||||
controller: 'ScatterFullScreenModeCtrl'
|
||||
}).when('/scatterFullScreenMode/:application/:period/:queryEndTime/:filter', {
|
||||
}).when('/scatterFullScreenMode/:application/:readablePeriod/:queryEndDateTime/:filter', {
|
||||
templateUrl: 'views/scatterFullScreenMode.html',
|
||||
controller: 'ScatterFullScreenModeCtrl'
|
||||
}).otherwise({
|
||||
|
||||
@@ -21,17 +21,17 @@ pinpointApp.controller('FilteredMapCtrl', [ 'filterConfig', '$scope', '$routePar
|
||||
if ($routeParams.application) {
|
||||
oNavbarVo.setApplication($routeParams.application);
|
||||
}
|
||||
if ($routeParams.period) {
|
||||
oNavbarVo.setPeriod(Number($routeParams.period, 10));
|
||||
if ($routeParams.readablePeriod) {
|
||||
oNavbarVo.setReadablePeriod($routeParams.readablePeriod);
|
||||
}
|
||||
if ($routeParams.queryEndTime) {
|
||||
oNavbarVo.setQueryEndTime(Number($routeParams.queryEndTime, 10));
|
||||
if ($routeParams.queryEndDateTime) {
|
||||
oNavbarVo.setQueryEndDateTime($routeParams.queryEndDateTime);
|
||||
}
|
||||
if ($routeParams.filter) {
|
||||
oNavbarVo.setFilter($routeParams.filter);
|
||||
}
|
||||
$window.$routeParams = $routeParams;
|
||||
oNavbarVo.autoCalculateByQueryEndTimeAndPeriod();
|
||||
oNavbarVo.autoCalculateByQueryEndDateTimeAndReadablePeriod();
|
||||
|
||||
oTimeSliderVo = new TimeSliderVo()
|
||||
.setFrom(oNavbarVo.getQueryStartTime())
|
||||
|
||||
@@ -17,16 +17,16 @@ pinpointApp.controller('InspectorCtrl', [ '$scope', '$timeout', '$routeParams',
|
||||
if ($routeParams.application) {
|
||||
oNavbarVo.setApplication($routeParams.application);
|
||||
}
|
||||
if ($routeParams.period) {
|
||||
oNavbarVo.setPeriod(Number($routeParams.period, 10));
|
||||
if ($routeParams.readablePeriod) {
|
||||
oNavbarVo.setReadablePeriod($routeParams.readablePeriod);
|
||||
}
|
||||
if ($routeParams.queryEndTime) {
|
||||
oNavbarVo.setQueryEndTime(Number($routeParams.queryEndTime, 10));
|
||||
if ($routeParams.queryEndDateTime) {
|
||||
oNavbarVo.setQueryEndDateTime($routeParams.queryEndDateTime);
|
||||
}
|
||||
if ($routeParams.agentId) {
|
||||
oNavbarVo.setAgentId($routeParams.agentId);
|
||||
}
|
||||
oNavbarVo.autoCalculateByQueryEndTimeAndPeriod();
|
||||
oNavbarVo.autoCalculateByQueryEndDateTimeAndReadablePeriod();
|
||||
$scope.$emit('navbar.initializeWithStaticApplication', oNavbarVo);
|
||||
$scope.$emit('agentList.initialize', oNavbarVo);
|
||||
}, 100);
|
||||
|
||||
@@ -21,17 +21,18 @@ pinpointApp.controller('MainCtrl', [ 'filterConfig', '$scope', '$timeout', '$rou
|
||||
if ($routeParams.application) {
|
||||
oNavbarVo.setApplication($routeParams.application);
|
||||
}
|
||||
if ($routeParams.period) {
|
||||
oNavbarVo.setPeriod(Number($routeParams.period, 10));
|
||||
if ($routeParams.readablePeriod) {
|
||||
oNavbarVo.setReadablePeriod($routeParams.readablePeriod);
|
||||
}
|
||||
if ($routeParams.queryEndTime) {
|
||||
oNavbarVo.setQueryEndTime(Number($routeParams.queryEndTime, 10));
|
||||
if ($routeParams.queryEndDateTime) {
|
||||
oNavbarVo.setQueryEndDateTime($routeParams.queryEndDateTime);
|
||||
}
|
||||
$window.$routeParams = $routeParams;
|
||||
oNavbarVo.autoCalculateByQueryEndTimeAndPeriod();
|
||||
oNavbarVo.autoCalculateByQueryEndDateTimeAndReadablePeriod();
|
||||
$scope.$broadcast('navbar.initialize', oNavbarVo);
|
||||
$scope.$broadcast('scatter.initialize', oNavbarVo);
|
||||
$scope.$broadcast('serverMap.initialize', oNavbarVo);
|
||||
|
||||
}, 500);
|
||||
|
||||
|
||||
@@ -49,8 +50,8 @@ pinpointApp.controller('MainCtrl', [ 'filterConfig', '$scope', '$timeout', '$rou
|
||||
* change location
|
||||
*/
|
||||
changeLocation = function () {
|
||||
var url = '/' + getFirstPathOfLocation() + '/' + oNavbarVo.getApplication() + '/' + oNavbarVo.getPeriod() +
|
||||
'/' + oNavbarVo.getQueryEndTime();
|
||||
var url = '/' + getFirstPathOfLocation() + '/' + oNavbarVo.getApplication() + '/' + oNavbarVo.getReadablePeriod() +
|
||||
'/' + oNavbarVo.getQueryEndDateTime();
|
||||
if (location.path() !== url) {
|
||||
if (location.path() === '/main') {
|
||||
location.path(url).replace();
|
||||
@@ -59,8 +60,8 @@ pinpointApp.controller('MainCtrl', [ 'filterConfig', '$scope', '$timeout', '$rou
|
||||
}
|
||||
$window.$routeParams = {
|
||||
application: oNavbarVo.getApplication(),
|
||||
period: (oNavbarVo.getPeriod()).toString(),
|
||||
queryEndTime: (oNavbarVo.getQueryEndTime()).toString()
|
||||
readablePeriod: (oNavbarVo.getReadablePeriod()).toString(),
|
||||
queryEndDateTime: (oNavbarVo.getQueryEndDateTime()).toString()
|
||||
};
|
||||
if (!$scope.$$phase) {
|
||||
$scope.$apply();
|
||||
|
||||
@@ -20,13 +20,13 @@ pinpointApp.controller('ScatterFullScreenModeCtrl', [ '$scope', '$rootScope', '$
|
||||
if ($routeParams.application) {
|
||||
oNavbarVo.setApplication($routeParams.application);
|
||||
}
|
||||
if ($routeParams.period) {
|
||||
oNavbarVo.setPeriod(Number($routeParams.period, 10));
|
||||
if ($routeParams.readablePeriod) {
|
||||
oNavbarVo.setReadablePeriod($routeParams.readablePeriod);
|
||||
}
|
||||
if ($routeParams.queryEndTime) {
|
||||
oNavbarVo.setQueryEndTime(Number($routeParams.queryEndTime, 10));
|
||||
if ($routeParams.queryEndDateTime) {
|
||||
oNavbarVo.setQueryEndDateTime($routeParams.queryEndDateTime);
|
||||
}
|
||||
oNavbarVo.autoCalculateByQueryEndTimeAndPeriod();
|
||||
oNavbarVo.autoCalculateByQueryEndDateTimeAndReadablePeriod();
|
||||
$scope.$emit('scatter.initialize', oNavbarVo);
|
||||
$scope.$emit('scatter.initializeWithNode', {applicationName: oNavbarVo.getApplicationName()}, 800, 600)
|
||||
}, 500);
|
||||
|
||||
@@ -72,8 +72,8 @@ pinpointApp.controller('TransactionListCtrl', ['TransactionListConfig', '$scope'
|
||||
return angular.isDefined($routeParams) &&
|
||||
angular.isDefined($parentParams) &&
|
||||
angular.equals($routeParams.application, $parentParams.application) &&
|
||||
angular.equals($routeParams.period, $parentParams.period) &&
|
||||
angular.equals($routeParams.queryEndTime, $parentParams.queryEndTime);
|
||||
angular.equals($routeParams.readablePeriod, $parentParams.readablePeriod) &&
|
||||
angular.equals($routeParams.queryEndDateTime, $parentParams.queryEndDateTime);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,7 +50,7 @@ pinpointApp.directive('navbar', [ 'cfg', '$rootScope', '$http',
|
||||
];
|
||||
scope.application = oNavbarVo.getApplication() || '';
|
||||
scope.disableApplication = true;
|
||||
scope.period = oNavbarVo.getPeriod() || 20;
|
||||
scope.readablePeriod = oNavbarVo.getReadablePeriod() || '20m';
|
||||
scope.queryEndTime = oNavbarVo.getQueryEndTime() || '';
|
||||
// $http.defaults.useXDomain = true;
|
||||
|
||||
@@ -72,7 +72,7 @@ pinpointApp.directive('navbar', [ 'cfg', '$rootScope', '$http',
|
||||
$application = element.find('.application');
|
||||
scope.application = oNavbarVo.getApplication() || '';
|
||||
scope.applicationName = oNavbarVo.getApplicationName() || '';
|
||||
scope.period = oNavbarVo.getPeriod() || 20;
|
||||
scope.readablePeriod = oNavbarVo.getReadablePeriod() || '20m';
|
||||
scope.queryEndTime = oNavbarVo.getQueryEndTime() || '';
|
||||
|
||||
initializeDateTimePicker();
|
||||
@@ -173,11 +173,13 @@ pinpointApp.directive('navbar', [ 'cfg', '$rootScope', '$http',
|
||||
}
|
||||
oNavbarVo.setApplication(scope.application);
|
||||
|
||||
if (scope.periodType === 'last' && scope.period) {
|
||||
if (scope.periodType === 'last' && scope.readablePeriod) {
|
||||
getQueryEndTimeFromServer(function (currentServerTime) {
|
||||
oNavbarVo.setPeriod(scope.period);
|
||||
oNavbarVo.setQueryEndTime(currentServerTime);
|
||||
oNavbarVo.autoCalculateByQueryEndTimeAndPeriod();
|
||||
// oNavbarVo.setPeriod(scope.period);
|
||||
// oNavbarVo.setQueryEndTime(currentServerTime);
|
||||
oNavbarVo.setReadablePeriod(scope.readablePeriod);
|
||||
oNavbarVo.setQueryEndDateTime(moment(currentServerTime).format('YYYY-MM-DD-HH-mm-ss'));
|
||||
oNavbarVo.autoCalculateByQueryEndDateTimeAndReadablePeriod();
|
||||
emitAsChanged();
|
||||
setDateTime($fromPicker, oNavbarVo.getQueryStartTime());
|
||||
setDateTime($toPicker, oNavbarVo.getQueryEndTime());
|
||||
@@ -195,6 +197,7 @@ pinpointApp.directive('navbar', [ 'cfg', '$rootScope', '$http',
|
||||
*/
|
||||
emitAsChanged = function () {
|
||||
setPeriodTypeAsCurrent();
|
||||
console.log('emitAsChanged', oNavbarVo);
|
||||
scope.$emit('navbar.changed', oNavbarVo);
|
||||
};
|
||||
|
||||
@@ -339,11 +342,11 @@ pinpointApp.directive('navbar', [ 'cfg', '$rootScope', '$http',
|
||||
|
||||
/**
|
||||
* set period
|
||||
* @param period
|
||||
* @param readablePeriod
|
||||
*/
|
||||
scope.setPeriod = function (period) {
|
||||
scope.setPeriod = function (readablePeriod) {
|
||||
scope.periodDelay = true;
|
||||
scope.period = period;
|
||||
scope.readablePeriod = readablePeriod;
|
||||
broadcast();
|
||||
$timeout(function () {
|
||||
scope.periodDelay = false;
|
||||
@@ -355,12 +358,12 @@ pinpointApp.directive('navbar', [ 'cfg', '$rootScope', '$http',
|
||||
|
||||
/**
|
||||
* get period class
|
||||
* @param period
|
||||
* @param readablePeriod
|
||||
* @returns {string}
|
||||
*/
|
||||
scope.getPeriodClass = function (period) {
|
||||
scope.getPeriodClass = function (readablePeriod) {
|
||||
var periodClass = '';
|
||||
if (scope.period === period) {
|
||||
if (scope.readablePeriod === readablePeriod) {
|
||||
periodClass += 'btn-info';
|
||||
}
|
||||
|
||||
|
||||
@@ -214,11 +214,11 @@ pinpointApp.directive('scatter',
|
||||
|
||||
var token = htLastNode.text + '|' + htXY.nXFrom + '|' + htXY.nXTo + '|' + htXY.nYFrom + '|' + htXY.nYTo;
|
||||
$window.open('#/transactionList/' + oNavbarVo.getApplication() + '/' +
|
||||
oNavbarVo.getPeriod() + '/' + oNavbarVo.getQueryEndTime(), token);
|
||||
oNavbarVo.getReadablePeriod() + '/' + oNavbarVo.getQueryEndDateTime(), token);
|
||||
};
|
||||
options.fFullScreenMode = function () {
|
||||
var url = '#/scatterFullScreenMode/' + htLastNode.text + '@' + htLastNode.serviceTypeCode + '/' +
|
||||
oNavbarVo.getPeriod() + '/' + oNavbarVo.getQueryEndTime();
|
||||
oNavbarVo.getReadablePeriod() + '/' + oNavbarVo.getQueryEndDateTime();
|
||||
if (oNavbarVo.getFilter()) {
|
||||
url += '/' + oNavbarVo.getFilter();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,9 @@ pinpointApp.factory('NavbarVo', function () {
|
||||
this._nQueryPeriod = false;
|
||||
this._nQueryStartTime = false;
|
||||
|
||||
this._sReadablePeriod = false;
|
||||
this._sQueryEndDateTime = false;
|
||||
|
||||
this.setApplication = function (application) {
|
||||
if (angular.isString(application) && application.indexOf('@') > 0) {
|
||||
self._sApplication = application;
|
||||
@@ -93,6 +96,58 @@ pinpointApp.factory('NavbarVo', function () {
|
||||
return self._sAgentId;
|
||||
};
|
||||
|
||||
this.setReadablePeriod = function (readablePeriod) {
|
||||
var regex = /^(\d)+(s|m|h|d|w|M|y)$/,
|
||||
match = regex.exec(readablePeriod);
|
||||
if (match) {
|
||||
self._sReadablePeriod = readablePeriod;
|
||||
var period = parseInt(readablePeriod, 10);
|
||||
switch (match[2]) {
|
||||
case 'm':
|
||||
self.setPeriod(period * 60);
|
||||
break;
|
||||
case 'h':
|
||||
self.setPeriod(period * 60 * 60);
|
||||
break;
|
||||
case 'd':
|
||||
self.setPeriod(period * 60 * 60 * 24);
|
||||
break;
|
||||
case 'w':
|
||||
self.setPeriod(period * 60 * 60 * 24 * 7);
|
||||
break;
|
||||
case 'M':
|
||||
self.setPeriod(period * 60 * 60 * 24 * 30);
|
||||
break;
|
||||
case 'y':
|
||||
self.setPeriod(period * 60 * 60 * 24 * 30 * 12);
|
||||
break;
|
||||
default:
|
||||
self.setPeriod(period);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
};
|
||||
this.getReadablePeriod = function () {
|
||||
return self._sReadablePeriod;
|
||||
};
|
||||
|
||||
this.setQueryEndDateTime = function (queryEndDateTime) {
|
||||
var regex = /^(19[7-9][0-9]|20\d{2})-(0[0-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])-(0[0-9]|1[0-9]|2[0-3])-([0-5][0-9])-([0-5][0-9])$/;
|
||||
if (regex.test(queryEndDateTime)) {
|
||||
self._sQueryEndDateTime = queryEndDateTime;
|
||||
self.setQueryEndTime(self._parseQueryEndDateTimeToTimestamp(queryEndDateTime));
|
||||
}
|
||||
return self;
|
||||
};
|
||||
this.getQueryEndDateTime = function () {
|
||||
return self._sQueryEndDateTime;
|
||||
};
|
||||
|
||||
this._parseQueryEndDateTimeToTimestamp = function (queryEndDateTime) {
|
||||
return moment(queryEndDateTime, 'YYYY-MM-DD-HH-mm-ss').valueOf();
|
||||
};
|
||||
|
||||
this.autoCalculateByQueryEndTimeAndPeriod = function () {
|
||||
self._nQueryPeriod = self._nPeriod * 1000 * 60;
|
||||
self._nQueryStartTime = self._nQueryEndTime - self._nQueryPeriod;
|
||||
@@ -102,6 +157,14 @@ pinpointApp.factory('NavbarVo', function () {
|
||||
this.autoCalcultateByQueryStartTimeAndQueryEndTime = function () {
|
||||
self._nQueryPeriod = self._nQueryEndTime - self._nQueryStartTime;
|
||||
self._nPeriod = self._nQueryPeriod / 1000 / 60;
|
||||
self._sReadablePeriod = self._nQueryPeriod / 1000 + 's';
|
||||
self._sQueryEndDateTime = moment(self._nQueryEndTime).format('YYYY-MM-DD-HH-mm-ss');
|
||||
return self;
|
||||
};
|
||||
|
||||
this.autoCalculateByQueryEndDateTimeAndReadablePeriod = function () {
|
||||
self._nQueryPeriod = self._nPeriod * 1000;
|
||||
self._nQueryStartTime = self._nQueryEndTime - self._nQueryPeriod;
|
||||
return self;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -69,8 +69,8 @@ pinpointApp.factory('filteredMapUtil', [ 'filterConfig', 'encodeURIComponentFilt
|
||||
getFilteredMapUrlWithFilterVo: function (oServerMapFilterVo, oNavbarVo) {
|
||||
var newFilter = this.mergeFilters(oServerMapFilterVo, oNavbarVo),
|
||||
mainApplication = oServerMapFilterVo.getMainApplication() + '@' + oServerMapFilterVo.getMainServiceTypeCode(),
|
||||
url = '#/filteredMap/' + mainApplication + '/' + oNavbarVo.getPeriod() + '/' +
|
||||
oNavbarVo.getQueryEndTime() + '/' + encodeURIComponentFilter(JSON.stringify(newFilter));
|
||||
url = '#/filteredMap/' + mainApplication + '/' + oNavbarVo.getReadablePeriod() + '/' +
|
||||
oNavbarVo.getQueryEndDateTime() + '/' + encodeURIComponentFilter(JSON.stringify(newFilter));
|
||||
return url;
|
||||
},
|
||||
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
<li class="for-datetimepicker">
|
||||
<div ng-show="periodType == 'last'" class="btn-group btn-group-sm" style="margin-top:0px;">
|
||||
<button type="button" class="btn btn-success" ng-click="periodType = 'range'"><span class="glyphicon glyphicon-th-list"></span></button>
|
||||
<button type="button" class="btn btn-default" ng-class="getPeriodClass(5)" ng-click="setPeriod(5)" ng-disabled="periodDelay">Last 5m</button>
|
||||
<button type="button" class="btn btn-default" ng-class="getPeriodClass(20)" ng-click="setPeriod(20)" ng-disabled="periodDelay">20m</button>
|
||||
<button type="button" class="btn btn-default" ng-class="getPeriodClass(60)" ng-click="setPeriod(60)" ng-disabled="periodDelay">1h</button>
|
||||
<button type="button" class="btn btn-default" ng-class="getPeriodClass(180)" ng-click="setPeriod(180)" ng-disabled="periodDelay">3h</button>
|
||||
<button type="button" class="btn btn-default" ng-class="getPeriodClass(360)" ng-click="setPeriod(360)" ng-disabled="periodDelay">6h</button>
|
||||
<button type="button" class="btn btn-default" ng-class="getPeriodClass(740)" ng-click="setPeriod(740)" ng-disabled="periodDelay">12h</button>
|
||||
<button type="button" class="btn btn-default" ng-class="getPeriodClass(1440)" ng-click="setPeriod(1440)" ng-disabled="periodDelay">1d</button>
|
||||
<button type="button" class="btn btn-default" ng-class="getPeriodClass(2880)" ng-click="setPeriod(2880)" ng-disabled="periodDelay">2d</button>
|
||||
<button type="button" class="btn btn-default" ng-class="getPeriodClass('5m')" ng-click="setPeriod('5m')" ng-disabled="periodDelay">Last 5m</button>
|
||||
<button type="button" class="btn btn-default" ng-class="getPeriodClass('20m')" ng-click="setPeriod('20m')" ng-disabled="periodDelay">20m</button>
|
||||
<button type="button" class="btn btn-default" ng-class="getPeriodClass('1h')" ng-click="setPeriod('1h')" ng-disabled="periodDelay">1h</button>
|
||||
<button type="button" class="btn btn-default" ng-class="getPeriodClass('3h')" ng-click="setPeriod('3h')" ng-disabled="periodDelay">3h</button>
|
||||
<button type="button" class="btn btn-default" ng-class="getPeriodClass('6h')" ng-click="setPeriod('6h')" ng-disabled="periodDelay">6h</button>
|
||||
<button type="button" class="btn btn-default" ng-class="getPeriodClass('12h')" ng-click="setPeriod('12h')" ng-disabled="periodDelay">12h</button>
|
||||
<button type="button" class="btn btn-default" ng-class="getPeriodClass('1d')" ng-click="setPeriod('1d')" ng-disabled="periodDelay">1d</button>
|
||||
<button type="button" class="btn btn-default" ng-class="getPeriodClass('2d')" ng-click="setPeriod('2d')" ng-disabled="periodDelay">2d</button>
|
||||
</div>
|
||||
<div ng-show="periodType == 'range'" class="datetimepicker input-group input-group-sm date" style="width:400px">
|
||||
<span class="input-group-btn">
|
||||
|
||||
Reference in New Issue
Block a user