#20: Display logs on documents

This commit is contained in:
jendib 2015-05-23 19:16:38 +02:00
parent ea4e3fd8f2
commit 6add34bb33
10 changed files with 117 additions and 49 deletions

View File

@ -75,6 +75,7 @@ public class AuditLogDao {
if (criteria.getUserId() != null) {
StringBuilder sb0 = new StringBuilder(" (l.LOG_IDENTITY_C = :userId and l.LOG_CLASSENTITY_C = 'User' ");
sb0.append(" or l.LOG_IDENTITY_C in (select t.TAG_ID_C from T_TAG t where t.TAG_IDUSER_C = :userId) and l.LOG_CLASSENTITY_C = 'Tag' ");
// Show only logs from owned documents, ACL are lost on delete
sb0.append(" or l.LOG_IDENTITY_C in (select d.DOC_ID_C from T_DOCUMENT d where d.DOC_IDUSER_C = :userId) and l.LOG_CLASSENTITY_C = 'Document') ");
criteriaList.add(sb0.toString());
parameterMap.put("userId", criteria.getUserId());

View File

@ -45,7 +45,7 @@ public class AuditLogResource extends BaseResource {
}
// On a document or a user?
PaginatedList<AuditLogDto> paginatedList = PaginatedLists.create(100, 0);
PaginatedList<AuditLogDto> paginatedList = PaginatedLists.create(20, 0);
SortCriteria sortCriteria = new SortCriteria(1, true);
AuditLogCriteria criteria = new AuditLogCriteria();
if (documentId == null) {

View File

@ -57,6 +57,7 @@ import com.sismics.rest.exception.ServerException;
import com.sismics.rest.util.ValidationUtil;
import com.sismics.util.mime.MimeType;
import com.sismics.util.mime.MimeTypeUtil;
import com.sun.jersey.api.client.ClientResponse.Status;
import com.sun.jersey.multipart.FormDataBodyPart;
import com.sun.jersey.multipart.FormDataParam;
@ -417,7 +418,7 @@ public class FileResource extends BaseResource {
}
}
} catch (NoResultException e) {
throw new ClientException("FileNotFound", MessageFormat.format("File not found: {0}", fileId));
return Response.status(Status.NOT_FOUND).build();
}
@ -461,7 +462,7 @@ public class FileResource extends BaseResource {
}
};
} catch (Exception e) {
throw new ServerException("FileError", "Error while reading the file", e);
return Response.status(Status.SERVICE_UNAVAILABLE).build();
}
return Response.ok(stream)

View File

@ -4,11 +4,18 @@
* Document view controller.
*/
angular.module('docs').controller('DocumentView', function ($scope, $state, $stateParams, $location, $dialog, $modal, Restangular, $upload, $q) {
// Load data from server
// Load document data from server
Restangular.one('document', $stateParams.id).get().then(function(data) {
$scope.document = data;
});
// Load audit log data from server
Restangular.one('auditlog').get({
document: $stateParams.id
}).then(function(data) {
$scope.logs = data.logs;
});
// Watch for ACLs change and group them for easy displaying
$scope.$watch('document.acls', function(acls) {
$scope.acls = _.groupBy(acls, function(acl) {

View File

@ -0,0 +1,15 @@
'use strict';
/**
* Audit log directive.
*/
angular.module('docs').directive('auditLog', function() {
return {
restrict: 'E',
templateUrl: 'partial/docs/directive.auditlog.html',
replace: true,
scope: {
logs: '='
}
}
});

View File

@ -62,6 +62,7 @@
<script src="app/docs/filter/Shorten.js" type="text/javascript"></script>
<script src="app/docs/directive/File.js" type="text/javascript"></script>
<script src="app/docs/directive/SelectTag.js" type="text/javascript"></script>
<script src="app/docs/directive/AuditLog.js" type="text/javascript"></script>
<script src="app/docs/directive/InlineEdit.js" type="text/javascript"></script>
<!-- endref -->
</head>

View File

@ -0,0 +1,32 @@
<table class="table">
<tr ng-repeat="log in logs">
<td>{{ log.create_date | date: 'yyyy-MM-dd HH:mm' }}</td>
<td>
{{ log.class }}
<span ng-switch="log.type">
<span ng-switch-when="CREATE">created</span>
<span ng-switch-when="UPDATE">updated</span>
<span ng-switch-when="DELETE">deleted</span>
</span>
<span ng-switch="log.class">
:
<span ng-switch-when="Document">
<a ng-href="#/document/view/{{ log.target }}">{{ log.message }}</a>
</span>
<span ng-switch-when="File">
<a ng-href="#/document/view/{{ log.message }}/file/{{ log.target }}">Open</a>
</span>
<span ng-switch-when="Acl">
{{ log.message }}
</span>
<span ng-switch-when="Tag">
<a href="#/tag">{{ log.message }}</a>
</span>
<span ng-switch-when="User">
<a href="#/settings/account">{{ log.message }}</a>
</span>
</span>
</td>
</tr>
</table>

View File

@ -1,61 +1,58 @@
<img src="img/loader.gif" ng-show="!app" />
<div ng-show="app">
<div class="row upload-zone" ng-model="dropFiles" ng-file-drop drag-over-class="bg-success"
ng-multiple="true" allow-dir="false" accept="image/*,application/pdf,application/zip" ng-file-change="fileDropped($files, $event, $rejectedFiles)">
<div class="col-xs-6 col-sm-4 col-md-3 col-lg-2 text-center" ng-repeat="file in files">
<div class="thumbnail" ng-class="{ 'thumbnail-checked': file.checked }" ng-if="file.id">
<a ng-click="openFile(file)">
<img class="thumbnail-file" ng-src="../api/file/{{ file.id }}/data?size=thumb" tooltip="{{ file.mimetype }}" tooltip-placement="top" />
</a>
<div class="caption pointer" ng-click="file.checked = !file.checked">
<div class="pull-left">
<input type="checkbox" ng-model="file.checked" />
<div class="well">
<h3>Quick upload</h3>
<div class="row upload-zone" ng-model="dropFiles" ng-file-drop drag-over-class="bg-success"
ng-multiple="true" allow-dir="false" accept="image/*,application/pdf,application/zip" ng-file-change="fileDropped($files, $event, $rejectedFiles)">
<div class="col-xs-6 col-sm-4 col-md-3 col-lg-2 text-center" ng-repeat="file in files">
<div class="thumbnail" ng-class="{ 'thumbnail-checked': file.checked }" ng-if="file.id">
<a ng-click="openFile(file)">
<img class="thumbnail-file" ng-src="../api/file/{{ file.id }}/data?size=thumb" tooltip="{{ file.mimetype }}" tooltip-placement="top" />
</a>
<div class="caption pointer" ng-click="file.checked = !file.checked">
<div class="pull-left">
<input type="checkbox" ng-model="file.checked" />
</div>
<div class="pull-right">
<button class="btn btn-danger" ng-click="deleteFile($event, file)"><span class="glyphicon glyphicon-trash"></span></button>
</div>
<div class="clearfix"></div>
</div>
<div class="pull-right">
<button class="btn btn-danger" ng-click="deleteFile($event, file)"><span class="glyphicon glyphicon-trash"></span></button>
</div>
<div class="thumbnail" ng-if="!file.id">
<p class="text-center lead">
{{ file.status }}
</p>
<div class="caption">
<progressbar value="file.progress" class="progress-info active"></progressbar>
</div>
<div class="clearfix"></div>
</div>
</div>
<div class="thumbnail" ng-if="!file.id">
<p class="text-center lead">
{{ file.status }}
</p>
<div class="caption">
<progressbar value="file.progress" class="progress-info active"></progressbar>
</div>
</div>
<p class="text-center well-lg" ng-if="files.length == 0">
<span class="glyphicon glyphicon-move"></span>
Drag &amp; drop files here to upload
</p>
</div>
<p class="text-center well-lg" ng-if="files.length == 0">
<span class="glyphicon glyphicon-move"></span>
Drag &amp; drop files here to upload
</p>
</div>
<div class="btn-group" ng-show="checkedFiles().length > 0">
<button class="btn btn-primary" ng-click="addDocument()"><span class="glyphicon glyphicon-plus"></span> Add to new document</button>
<div class="btn-group" ng-show="checkedFiles().length > 0">
<button class="btn btn-primary" ng-click="addDocument()"><span class="glyphicon glyphicon-plus"></span> Add to new document</button>
</div>
</div>
<div ui-view="file"></div>
<table class="table">
<tr>
<th>Date</th>
<th>Message</th>
</tr>
<tr ng-repeat="log in logs">
<td>{{ log.create_date | date: 'yyyy-MM-dd HH:mm' }}</td>
<td>{{ log.class }} {{ log.type }} {{ log.message }}</td>
</tr>
</table>
<div class="well">
<h3>Latest activity</h3>
<audit-log logs="logs" />
</div>
<div class="text-muted text-right">
<ul class="list-inline">
<li><strong>Version:</strong> {{ app.current_version }}</li>
<li><strong>Memory:</strong> {{ app.free_memory / 1000000 | number: 0 }}/{{ app.total_memory / 1000000 | number: 0 }} MB</li>
</ul>
</div>
<div class="text-muted text-right">
<ul class="list-inline">
<li><strong>Version:</strong> {{ app.current_version }}</li>
<li><strong>Memory:</strong> {{ app.free_memory / 1000000 | number: 0 }}/{{ app.total_memory / 1000000 | number: 0 }} MB</li>
</ul>
</div>
</div>

View File

@ -135,6 +135,14 @@
</form>
</div>
</tab>
<tab>
<tab-heading class="pointer">
<span class="glyphicon glyphicon-tasks"></span> Activity
</tab-heading>
<audit-log logs="logs" />
</tab>
</tabset>
<div ui-view="file"></div>

View File

@ -178,6 +178,12 @@ public class TestFileResource extends BaseJerseyTest {
json = response.getEntity(JSONObject.class);
Assert.assertEquals("ok", json.getString("status"));
// Get the file data (not found)
fileResource = resource().path("/file/" + file1Id + "/data");
fileResource.addFilter(new CookieAuthenticationFilter(file1AuthenticationToken));
response = fileResource.get(ClientResponse.class);
Assert.assertEquals(Status.NOT_FOUND, Status.fromStatusCode(response.getStatus()));
// Check that files are deleted from FS
storedFile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file1Id).toFile();
java.io.File webFile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file1Id + "_web").toFile();