package com.constellio.model.services.logging;
import com.constellio.data.utils.LangUtils;
import com.constellio.data.utils.LangUtils.ListComparisonResults;
import com.constellio.data.utils.TimeProvider;
import com.constellio.model.entities.records.Record;
import com.constellio.model.entities.records.wrappers.Event;
import com.constellio.model.entities.records.wrappers.EventType;
import com.constellio.model.entities.records.wrappers.User;
import com.constellio.model.entities.schemas.Metadata;
import com.constellio.model.entities.schemas.MetadataSchema;
import com.constellio.model.entities.schemas.Schemas;
import com.constellio.model.entities.schemas.entries.DataEntryType;
import com.constellio.model.entities.security.Authorization;
import com.constellio.model.entities.security.global.AuthorizationDetails;
import com.constellio.model.services.factories.ModelLayerFactory;
import com.constellio.model.services.records.RecordImpl;
import com.constellio.model.services.records.RecordServices;
import com.constellio.model.services.records.SchemasRecordsServices;
import com.constellio.model.services.schemas.MetadataSchemasManager;
import com.constellio.model.services.schemas.SchemaUtils;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class EventFactory {
ModelLayerFactory modelLayerFactory;
MetadataSchemasManager metadataSchemasManager;
RecordServices recordServices;
public EventFactory(ModelLayerFactory modelLayerFactory) {
this.modelLayerFactory = modelLayerFactory;
this.metadataSchemasManager = modelLayerFactory.getMetadataSchemasManager();
this.recordServices = modelLayerFactory.newRecordServices();
}
public Event newLoginEvent(User user) {
SchemasRecordsServices schemasRecords = new SchemasRecordsServices(user.getCollection(), modelLayerFactory);
Event event = schemasRecords.newEvent();
setDefaultMetadata(event, user);
event.setType(EventType.OPEN_SESSION);
return event;
}
public Event newLogoutEvent(User user) {
SchemasRecordsServices schemasRecords = new SchemasRecordsServices(user.getCollection(), modelLayerFactory);
Event event = schemasRecords.newEvent();
setDefaultMetadata(event, user);
event.setType(EventType.CLOSE_SESSION);
return event;
}
public Event newRecordEvent(Record record, User currentUser, String eventType) {
return newRecordEvent(record, currentUser, eventType, null);
}
public Event newRecordEvent(Record record, User currentUser, String eventType, String reason) {
return newRecordEvent(record, currentUser, eventType, reason, null);
}
public Event newRecordEvent(Record record, User currentUser, String eventType, String reason, LocalDateTime eventDateTime) {
if (record.getCollection().endsWith(currentUser.getCollection())) {
return createRecordEvent(record, currentUser, eventType, reason, eventDateTime, currentUser.getCollection());
} else {
return null;
}
}
public Event newRecordEvent(Record record, User currentUser, String eventType, String reason, LocalDateTime eventDateTime,
String collection) {
return createRecordEvent(record, currentUser, eventType, reason, eventDateTime, collection);
}
private Event createRecordEvent(Record record, User currentUser, String eventType, String reason, LocalDateTime eventDateTime,
String collection) {
SchemasRecordsServices schemasRecords = new SchemasRecordsServices(collection, modelLayerFactory);
Event event = schemasRecords.newEvent();
setDefaultMetadata(event, currentUser);
setRecordMetadata(event, record);
if (reason != null) {
event.setReason(reason);
}
if (eventDateTime != null) {
event.setCreatedOn(eventDateTime);
event.setModifiedOn(eventDateTime);
}
String recordSchema = record.getSchemaCode();
SchemaUtils schemaUtils = new SchemaUtils();
String recordSchemaType = schemaUtils.getSchemaTypeCode(recordSchema);
event.setType(eventType + "_" + recordSchemaType);
return event;
}
private void setRecordMetadata(Event event, Record record) {
event.setRecordId(record.getId());
String principalPath = record.get(Schemas.PRINCIPAL_PATH);
event.setEventPrincipalPath(principalPath);
Object title = record.get(Schemas.TITLE);
if (title != null) {
event.setTitle((String) title);
}
}
private void setDefaultMetadata(Event event, User user) {
event.setUsername(user.getUsername());
List<String> roles = user.getAllRoles();
event.setUserRoles(StringUtils.join(roles.toArray(), "; "));
event.setCreatedOn(TimeProvider.getLocalDateTime());
String ipAddress = user.getLastIPAddress();
event.setIp(ipAddress);
}
public Event logAddUpdateRecord(Record record, User user) {
SchemasRecordsServices schemasRecords = new SchemasRecordsServices(user.getCollection(), modelLayerFactory);
Event event = schemasRecords.newEvent();
setDefaultMetadata(event, user);
setRecordMetadata(event, record);
String recordSchema = record.getSchemaCode();
SchemaUtils schemaUtils = new SchemaUtils();
String recordSchemaType = schemaUtils.getSchemaTypeCode(recordSchema);
if (record.isSaved()) {
if (record.isModified(Schemas.LOGICALLY_DELETED_STATUS)) {
// event.setType(EventType.DELETE + "_" + recordSchemaType);
// Deletions are logged separately
return null;
} else {
event.setType(EventType.MODIFY + "_" + recordSchemaType);
setDeltaMetadata(event, record);
}
} else {
event.setType(EventType.CREATE + "_" + recordSchemaType);
}
return event;
}
public String getBorrowDurationDelta(LocalDateTime oldValue, LocalDateTime newValue) {
StringBuilder delta = new StringBuilder();
if (!oldValue.toString().equals(newValue.toString())) {
delta.append("\tAvant : " + limitContentLength(oldValue.toString()) + "\n");
delta.append("\tAprès : " + limitContentLength(newValue.toString()));
}
return delta.toString();
}
private void setDeltaMetadata(Event event, Record record) {
//FIXME
StringBuilder delta = new StringBuilder();
RecordImpl recordImpl = (RecordImpl) record;
Map<String, Object> modifiedValues = recordImpl.getModifiedValues();
if (record.isSaved()) {
for (Entry<String, Object> modifiedValueEntry : modifiedValues.entrySet()) {
String metadataDatastoreCode = modifiedValueEntry.getKey();
String metadataLocalCode = new SchemaUtils().getLocalCodeFromDataStoreCode(metadataDatastoreCode);
MetadataSchema schema = metadataSchemasManager.getSchemaTypes(record.getCollection())
.getSchema(record.getSchemaCode());
if (schema.hasMetadataWithCode(metadataLocalCode)) {
Metadata metadata = schema.getMetadata(metadataLocalCode);
if (notAccepted(metadata)) {
continue;
}
Object newValue = modifiedValueEntry.getValue();
Object oldValue = recordImpl.getRecordDTO().getFields().get(metadataDatastoreCode);
if (newValue == null) {
if (oldValue != null) {
delta.append("-[" + metadata.getCode() + " : " + oldValue.toString() + "]\n");
}
} else {
if (oldValue == null) {
delta.append("+[" + metadata.getCode() + " : " + newValue.toString() + "]\n");
} else {
if (!oldValue.toString().equals(newValue.toString())) {
delta.append("[ " + metadata.getCode() + " :\n");
delta.append("\tAvant : " + limitContentLength(oldValue.toString()) + "\n");
delta.append("\tAprès : " + limitContentLength(newValue.toString()) + "]\n");
}
}
}
}
}
}
event.setDelta(delta.toString());
}
private String limitContentLength(String text) {
return StringUtils.abbreviate(text, 100);
}
private boolean notAccepted(Metadata metadata) {
if (metadata.isSystemReserved()) {
return true;
}
if (!metadata.getDataEntry().getType().name().equals(DataEntryType.MANUAL.name())) {
return true;
}
return false;
}
public Event eventPermission(Authorization authorization, Authorization authorizationBefore, User user,
String recordId, String eventPermissionType) {
SchemasRecordsServices schemasRecords = new SchemasRecordsServices(user.getCollection(), modelLayerFactory);
if (recordId == null) {
recordId = authorization.getGrantedOnRecord();
}
String deltaString = compareAuthorizations(authorizationBefore, authorization);
SchemaUtils schemaUtils = new SchemaUtils();
String authorizationRolesString = StringUtils.join(authorization.getDetail().getRoles(), "; ");
String authorizationPrincipalsString = getAuthorizationPrincipals(authorization);
String dateRangeString = getAuthorizationDateRange(authorization);
Event event = schemasRecords.newEvent();
setDefaultMetadata(event, user);
event.setPermissionUsers(authorizationPrincipalsString);
event.setPermissionDateRange(dateRangeString);
event.setPermissionRoles(authorizationRolesString);
event.setDelta(deltaString);
Record currentRecord = recordServices.getDocumentById(recordId);
String recordSchema = currentRecord.getSchemaCode();
String recordSchemaType = schemaUtils.getSchemaTypeCode(recordSchema);
setRecordMetadata(event, currentRecord);
event.setType(eventPermissionType + "_" + recordSchemaType);
return event;
}
private String compareAuthorizations(Authorization authorizationBefore, Authorization authorization) {
StringBuilder deltaStringBuilder = new StringBuilder("");
if (authorizationBefore != null) {
String principalsDelta = getAuthorizationsPrincipalsDelta(authorizationBefore, authorization);
if (StringUtils.isNotBlank(principalsDelta)) {
deltaStringBuilder.append("\n" + principalsDelta);
}
String datesDelta = getAuthorizationsDatesDelta(authorizationBefore, authorization);
if (StringUtils.isNotBlank(datesDelta)) {
deltaStringBuilder.append("\n" + datesDelta);
}
}
return deltaStringBuilder.toString();
}
private String getAuthorizationsDatesDelta(Authorization authorizationBefore, Authorization authorization) {
String datesBefore = getAuthorizationDateRange(authorizationBefore);
String datesAfter = getAuthorizationDateRange(authorization);
if (datesAfter.equals(datesBefore)) {
return "";
} else {
//FIXME
return "Dates avant :" + datesBefore;
}
}
private String getAuthorizationsPrincipalsDelta(Authorization authorizationBefore, Authorization authorization) {
ListComparisonResults<String> principalsComparisonResults = new LangUtils()
.compare(authorizationBefore.getGrantedToPrincipals(), authorization.getGrantedToPrincipals());
if (principalsComparisonResults.getRemovedItems().size() == 0 && principalsComparisonResults.getNewItems().size() == 0) {
return "";
}
List<String> addPrincipals = new ArrayList<>();
for (String principalId : principalsComparisonResults.getNewItems()) {
Record currentPrincipal = recordServices.getDocumentById(principalId);
addPrincipals.add((String) currentPrincipal.get(Schemas.TITLE));
}
List<String> removedPrincipals = new ArrayList<>();
for (String principalId : principalsComparisonResults.getRemovedItems()) {
Record currentPrincipal = recordServices.getDocumentById(principalId);
removedPrincipals.add((String) currentPrincipal.get(Schemas.TITLE));
}
//FIXME
StringBuilder principalsDelta = new StringBuilder(("Utilisateurs :\n-["));
principalsDelta.append(StringUtils.join(removedPrincipals, "; "));
principalsDelta.append("]\n+[");
principalsDelta.append(StringUtils.join(addPrincipals, "; "));
principalsDelta.append("]\n");
return principalsDelta.toString();
}
private String getAuthorizationDateRange(Authorization authorization) {
AuthorizationDetails detail = authorization.getDetail();
StringBuilder dateRangeStringBuilder = new StringBuilder("[");
if (detail.getStartDate() != null) {
dateRangeStringBuilder.append(detail.getStartDate());
}
dateRangeStringBuilder.append(", ");
if (detail.getEndDate() != null) {
dateRangeStringBuilder.append(detail.getEndDate());
}
dateRangeStringBuilder.append("]");
return dateRangeStringBuilder.toString();
}
private String getAuthorizationPrincipals(Authorization authorization) {
List<String> usersNames = new ArrayList<>();
for (String userId : authorization.getGrantedToPrincipals()) {
Record userRecord = recordServices.getDocumentById(userId);
usersNames.add((String) userRecord.get(Schemas.TITLE));
}
return StringUtils.join(usersNames, "; ");
}
}