- Add log view under repos
- Make the logs a bit nicer by adding context-sensitive icons - Fix some of the log descriptions
This commit is contained in:
parent
64c9081587
commit
782405fe65
7 changed files with 108 additions and 23 deletions
|
@ -1058,9 +1058,12 @@ def delete_webhook(namespace_name, repository_name, public_id):
|
|||
webhook.delete_instance()
|
||||
return webhook
|
||||
|
||||
def list_logs(user_or_organization_name):
|
||||
def list_logs(user_or_organization_name, repository = None):
|
||||
week_ago = datetime.today() - timedelta(7) # One week
|
||||
joined = LogEntry.select().join(User)
|
||||
if repository:
|
||||
joined = joined.where(LogEntry.repository == repository)
|
||||
|
||||
return joined.where(User.username == user_or_organization_name, LogEntry.datetime >= week_ago).order_by(LogEntry.datetime.desc())
|
||||
|
||||
def log_action(kind_name, user_or_organization_name, performer=None, repository=None,
|
||||
|
|
|
@ -713,6 +713,27 @@ def update_repo_api(namespace, repository):
|
|||
abort(403)
|
||||
|
||||
|
||||
@app.route('/api/repository/<path:repository>/logs', methods=['GET'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
def repo_logs_api(namespace, repository):
|
||||
permission = AdministerRepositoryPermission(namespace, repository)
|
||||
if permission.can():
|
||||
print namespace
|
||||
print repository
|
||||
repo = model.get_repository(namespace, repository)
|
||||
print repo
|
||||
if not repo:
|
||||
abort(404)
|
||||
|
||||
logs = model.list_logs(namespace, repository = repo)
|
||||
return jsonify({
|
||||
'logs': [log_view(log) for log in logs]
|
||||
})
|
||||
|
||||
abort(403)
|
||||
|
||||
|
||||
@app.route('/api/repository/<path:repository>/changevisibility',
|
||||
methods=['POST'])
|
||||
@api_login_required
|
||||
|
@ -1201,7 +1222,7 @@ def change_team_permissions(namespace, repository, teamname):
|
|||
new_permission['role'])
|
||||
|
||||
log_action('change_repo_permission', namespace,
|
||||
{'team': team, 'repo': repository, 'role': new_permission['role']},
|
||||
{'team': teamname, 'repo': repository, 'role': new_permission['role']},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
|
||||
resp = jsonify(role_view(perm))
|
||||
|
@ -1324,7 +1345,7 @@ def change_token(namespace, repository, code):
|
|||
new_permission['role'])
|
||||
|
||||
log_action('change_repo_permission', namespace,
|
||||
{'repo': repository, 'token': token.friendly_name, 'code': code},
|
||||
{'repo': repository, 'token': token.friendly_name, 'code': code, 'role': new_permission['role']},
|
||||
repo = model.get_repository(namespace, repository))
|
||||
|
||||
resp = jsonify(token_view(token))
|
||||
|
@ -1688,9 +1709,6 @@ def delete_org_robot(orgname, robot_shortname):
|
|||
abort(403)
|
||||
|
||||
|
||||
@app.route('/api/organization/<orgname>/logs', methods=['GET'])
|
||||
@api_login_required
|
||||
def org_logs_api(orgname):
|
||||
def log_view(log):
|
||||
view = {
|
||||
'kind': log.kind.name,
|
||||
|
@ -1707,6 +1725,9 @@ def org_logs_api(orgname):
|
|||
|
||||
return view
|
||||
|
||||
@app.route('/api/organization/<orgname>/logs', methods=['GET'])
|
||||
@api_login_required
|
||||
def org_logs_api(orgname):
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
logs = model.list_logs(orgname)
|
||||
|
@ -1715,3 +1736,4 @@ def org_logs_api(orgname):
|
|||
})
|
||||
|
||||
abort(403)
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ html, body {
|
|||
border-bottom: 1px dashed #aaa;
|
||||
}
|
||||
|
||||
|
||||
.entity-reference .prefix {
|
||||
color: #aaa;
|
||||
}
|
||||
|
@ -142,6 +143,10 @@ html, body {
|
|||
float: right;
|
||||
}
|
||||
|
||||
.logs-view-element .log i.fa {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.logs-view-element .log .circle {
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
|
|
|
@ -678,7 +678,8 @@ quayApp.directive('logsView', function () {
|
|||
scope: {
|
||||
'organization': '=organization',
|
||||
'user': '=user',
|
||||
'visible': '=visible'
|
||||
'visible': '=visible',
|
||||
'repository': '=repository'
|
||||
},
|
||||
controller: function($scope, $element, $sce, Restangular) {
|
||||
$scope.loading = true;
|
||||
|
@ -705,8 +706,24 @@ quayApp.directive('logsView', function () {
|
|||
}
|
||||
},
|
||||
'delete_repo': 'Delete repository: {repo}',
|
||||
'change_repo_permission': 'Change permission for user {username} in repository {repo} to {role}',
|
||||
'delete_repo_permission': 'Remove permission for user {username} from repository {repo}',
|
||||
'change_repo_permission': function(metadata) {
|
||||
if (metadata.username) {
|
||||
return 'Change permission for user {username} in repository {repo} to {role}';
|
||||
} else if (metadata.team) {
|
||||
return 'Change permission for team {team} in repository {repo} to {role}';
|
||||
} else if (metadata.token) {
|
||||
return 'Change permission for token {token} in repository {repo} to {role}';
|
||||
}
|
||||
},
|
||||
'delete_repo_permission': function(metadata) {
|
||||
if (metadata.username) {
|
||||
return 'Remove permission for user {username} from repository {repo}';
|
||||
} else if (metadata.team) {
|
||||
return 'Remove permission for team {team} from repository {repo}';
|
||||
} else if (metadata.token) {
|
||||
return 'Remove permission for token {token} from repository {repo}';
|
||||
}
|
||||
},
|
||||
'change_repo_visibility': 'Change visibility for repository {repo} to {visibility}',
|
||||
'add_repo_accesstoken': 'Create access token {token} in repository {repo}',
|
||||
'delete_repo_accesstoken': 'Delete access token {token} in repository {repo}',
|
||||
|
@ -751,14 +768,20 @@ quayApp.directive('logsView', function () {
|
|||
};
|
||||
|
||||
var update = function() {
|
||||
if (!$scope.visible || (!$scope.organization && !$scope.user)) {
|
||||
if (!$scope.visible || (!$scope.organization && !$scope.user && !$scope.repository)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.loading = true;
|
||||
|
||||
var url = $scope.organization ? getRestUrl('organization', $scope.organization.name, 'logs') :
|
||||
getRestUrl('user/logs');
|
||||
var url = getRestUrl('user/logs');
|
||||
if ($scope.organization) {
|
||||
url = getRestUrl('organization', $scope.organization.name, 'logs');
|
||||
}
|
||||
if ($scope.repository) {
|
||||
url = getRestUrl('repository', $scope.repository.namespace, $scope.repository.name, 'logs');
|
||||
}
|
||||
|
||||
var loadLogs = Restangular.one(url);
|
||||
loadLogs.customGET().then(function(resp) {
|
||||
if (!$scope.chart) {
|
||||
|
@ -788,6 +811,14 @@ quayApp.directive('logsView', function () {
|
|||
};
|
||||
|
||||
$scope.getDescription = function(log) {
|
||||
var fieldIcons = {
|
||||
'username': 'user',
|
||||
'team': 'group',
|
||||
'token': 'key',
|
||||
'repo': 'hdd',
|
||||
'robot': 'wrench'
|
||||
};
|
||||
|
||||
log.metadata['_ip'] = log.ip;
|
||||
|
||||
var description = logDescriptions[log.kind] || logTitles[log.kind] || log.kind;
|
||||
|
@ -799,6 +830,12 @@ quayApp.directive('logsView', function () {
|
|||
if (log.metadata.hasOwnProperty(key)) {
|
||||
var markedDown = getMarkedDown(log.metadata[key].toString());
|
||||
markedDown = markedDown.substr('<p>'.length, markedDown.length - '<p></p>'.length);
|
||||
|
||||
var icon = fieldIcons[key];
|
||||
if (icon) {
|
||||
markedDown = '<i class="fa fa-' + icon + '"></i>' + markedDown;
|
||||
}
|
||||
|
||||
description = description.replace('{' + key + '}', '<code>' + markedDown + '</code>');
|
||||
}
|
||||
}
|
||||
|
@ -807,6 +844,7 @@ quayApp.directive('logsView', function () {
|
|||
|
||||
$scope.$watch('organization', update);
|
||||
$scope.$watch('user', update);
|
||||
$scope.$watch('repository', update);
|
||||
$scope.$watch('visible', update);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -426,6 +426,11 @@ function RepoAdminCtrl($scope, Restangular, $routeParams, $rootScope) {
|
|||
var name = $routeParams.name;
|
||||
|
||||
$scope.permissions = {'team': [], 'user': []};
|
||||
$scope.logsShown = 0;
|
||||
|
||||
$scope.loadLogs = function() {
|
||||
$scope.logsShown++;
|
||||
};
|
||||
|
||||
$scope.grantRole = function() {
|
||||
$('#confirmaddoutsideModal').modal('hide');
|
||||
|
|
|
@ -1289,7 +1289,12 @@ LogUsageChart.prototype.buildData_ = function(logs) {
|
|||
var log = logs[i];
|
||||
var title = this.titleMap_[log.kind] || log.kind;
|
||||
var datetime = parseDate(log.datetime);
|
||||
var formatted = (datetime.getMonth() + 1) + '/' + datetime.getDate();
|
||||
var dateDay = datetime.getDate();
|
||||
if (dateDay < 10) {
|
||||
dateDay = '0' + dateDay;
|
||||
}
|
||||
|
||||
var formatted = (datetime.getMonth() + 1) + '/' + dateDay;
|
||||
var adjusted = new Date(datetime.getFullYear(), datetime.getMonth(), datetime.getDate());
|
||||
var key = title + '_' + formatted;
|
||||
var found = map[key];
|
||||
|
@ -1374,7 +1379,8 @@ LogUsageChart.prototype.buildData_ = function(logs) {
|
|||
* Renders the tooltip when hovering over an element in the chart.
|
||||
*/
|
||||
LogUsageChart.prototype.renderTooltip_ = function(d, e) {
|
||||
var entry = this.entries_[d + '_' + e];
|
||||
var key = d + '_' + e;
|
||||
var entry = this.entries_[key];
|
||||
if (!entry) {
|
||||
entry = {'count': 0};
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#webhook" ng-click="loadWebhooks()">Web Hooks</a></li>
|
||||
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#publicprivate">Public/Private</a></li>
|
||||
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#delete">Delete</a></li>
|
||||
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#logs" ng-click="loadLogs()">Usage Logs</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
@ -30,6 +31,11 @@
|
|||
<div class="col-md-10">
|
||||
|
||||
<div class="tab-content">
|
||||
<!-- Logs tab -->
|
||||
<div id="logs" class="tab-pane">
|
||||
<div class="logs-view" repository="repo" visible="logsShown"></div>
|
||||
</div>
|
||||
|
||||
<!-- Permissions tab -->
|
||||
<div id="permissions" class="tab-pane active">
|
||||
<!-- User Access Permissions -->
|
||||
|
|
Reference in a new issue