- 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:
Joseph Schorr 2013-12-02 14:55:04 -05:00
parent 64c9081587
commit 782405fe65
7 changed files with 108 additions and 23 deletions

View file

@ -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,

View file

@ -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,10 +1709,7 @@ 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):
def log_view(log):
view = {
'kind': log.kind.name,
'metadata': json.loads(log.metadata_json),
@ -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)

View file

@ -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;

View file

@ -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;
@ -696,17 +697,33 @@ quayApp.directive('logsView', function () {
'create_repo': 'Create Repository: {repo}',
'push_repo': 'Push to repository: {repo}',
'pull_repo': function(metadata) {
if (metadata.token) {
return 'Pull repository {repo} via token {token}';
} else if (metadata.username) {
return 'Pull repository {repo} by {username}';
} else {
return 'Public pull of repository {repo} by {_ip}';
}
if (metadata.token) {
return 'Pull repository {repo} via token {token}';
} else if (metadata.username) {
return 'Pull repository {repo} by {username}';
} else {
return 'Public pull of repository {repo} by {_ip}';
}
},
'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);
}
};

View file

@ -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');

View file

@ -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};
}

View file

@ -23,13 +23,19 @@
<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>
<!-- Content -->
<div class="col-md-10">
<div class="tab-content">
<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 -->