RM-777: Destruction report generation

* template now correct and matches email notification style
  * record or folder details shown including basic disposition details
  * destroyed records shown if record folder
  * generalised report action
  * other tweaks
 


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@52685 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall
2013-07-16 05:27:37 +00:00
parent 0b916c241f
commit 21f98c25b4
9 changed files with 283 additions and 47 deletions

View File

@@ -201,8 +201,6 @@
<view:aspects> <view:aspects>
<cm:titled></cm:titled> <cm:titled></cm:titled>
<cm:author></cm:author> <cm:author></cm:author>
<app:inlineeditable></app:inlineeditable>
<cm:versionable></cm:versionable>
</view:aspects> </view:aspects>
<view:properties> <view:properties>
<sys:store-protocol>workspace</sys:store-protocol> <sys:store-protocol>workspace</sys:store-protocol>

View File

@@ -1,10 +1,120 @@
<html> <html>
<head>
<style type="text/css"><!--
body
{
font-family: Arial, sans-serif;
font-size: 14px;
color: #4c4c4c;
}
<head> a, a:visited
</head> {
color: #0072cf;
}
--></style>
</head>
<body> <body bgcolor="#dddddd">
<h1>Destruction Report</h1> <table width="100%" cellpadding="20" cellspacing="0" border="0" bgcolor="#dddddd">
</body> <tr>
<td width="100%" align="center">
<table width="70%" cellpadding="0" cellspacing="0" bgcolor="white" style="background-color: white; border: 1px solid #aaaaaa;">
<tr>
<td width="100%">
<table width="100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td style="padding: 10px 30px 0px;">
<table width="100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td>
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td>
<img src="${shareUrl}/res/components/images/task-64.png" alt="" width="64" height="64" border="0" style="padding-right: 20px;" />
</td>
<td>
<div style="font-size: 22px; padding-bottom: 4px;">
Destruction Report
</div>
</td>
</tr>
</table>
<div style="font-size: 14px; margin: 12px 0px 24px 0px; padding-top: 10px; border-top: 1px solid #aaaaaa;">
<table cellpadding="2" cellspacing="3" border="0">
<tr>
<td><i>Destroyed <#if node.hasAspect("rma:record")>Record<#else>Record Folder</#if>:</i></td>
<td>${node.properties["rma:identifier"]} <b>${node.properties.name}</b></td>
</tr>
<tr>
<td><i>Disposition Authority:</i></td>
<td>${node.properties["rma:recordSearchDispositionAuthority"]}</td>
</tr>
<tr>
<td><i>Disposition Instructions:</i></td>
<td>${node.properties["rma:recordSearchDispositionInstructions"]}</td>
</tr>
</table>
<#if node.childAssociations["cm:contains"]??>
<div style="font-size: 14px; margin: 12px 0px 24px 0px; padding-top: 10px; border-top: 1px solid #aaaaaa;">
<table cellpadding="2" cellspacing="3" border="0">
<tr>
<td><i>Destroyed Records:</i></td>
<td></td>
</tr>
</table>
<table cellpadding="0" callspacing="0" border="0" bgcolor="#eeeeee" style="padding:10px; border: 1px solid #aaaaaa;">
<tr>
<td>
<table cellpadding="0" cellspacing="0" border="0">
<#list node.childAssociations["cm:contains"] as child>
<tr>
<td valign="top">
<img src="${url}/${child.icon32}" alt="" width="32" height="32" border="0" style="padding-right: 10px;" />
</td>
<td>
<table cellpadding="2" cellspacing="0" border="0">
<tr>
<td>${child.properties["rma:identifier"]} <b>${child.properties.name}</b></td>
</tr>
</table>
</td>
</tr>
</#list>
</table>
</td>
</tr>
</table>
</#if>
<div style="font-size: 14px; margin: 12px 0px 24px 0px; padding-top: 10px; border-top: 1px solid #aaaaaa;">
</div>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="padding: 10px 30px;">
<img src="${shareUrl}/themes/default/images/app-logo.png" alt="" width="117" height="48" border="0" />
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html> </html>

View File

@@ -122,6 +122,28 @@
<property name="index" value="60" /> <property name="index" value="60" />
</bean> </bean>
<!-- file destruction report capability -->
<bean id="rmFileDestructionReportCapability"
parent="declarativeCapability">
<property name="name" value="FileDestructionReport" />
<property name="permission" value="FileDestructionReport" /> <!-- Associated permission -->
<property name="kinds">
<list>
<value>RECORD</value> <!-- Only applies to records and record folders -->
<value>RECORD_FOLDER</value>
</list>
</property>
<property name="conditions">
<map>
<entry key="capabilityCondition.filling" value="true"/> <!-- Must have read and file permissions -->
<entry key="capabilityCondition.frozen" value="false"/> <!-- Not for frozen records -->
<entry key="capabilityCondition.destroyed" value="true"/> <!-- Only for destroyed things -->
</map>
</property>
<property name="group"><ref bean="dispositionAndTransfersGroup"/></property> <!-- Part of the disposition group of capabilities -->
<property name="index" value="110" />
</bean>
<!-- Non-assignable Capabilities --> <!-- Non-assignable Capabilities -->
<bean id="rmInitiateAllTransfersCapability" <bean id="rmInitiateAllTransfersCapability"

View File

@@ -300,26 +300,4 @@
<property name="index" value="100" /> <property name="index" value="100" />
</bean> </bean>
<!-- file destruction report capability -->
<bean id="rmFileDestructionReportCapability"
parent="declarativeCapability">
<property name="name" value="FileDestructionReport" />
<property name="permission" value="FileDestructionReport" /> <!-- Associated permission -->
<property name="kinds">
<list>
<value>RECORD</value> <!-- Only applies to records and record folders -->
<value>RECORD_FOLDER</value>
</list>
</property>
<property name="conditions">
<map>
<entry key="capabilityCondition.filling" value="true"/> <!-- Must have read and file permissions -->
<entry key="capabilityCondition.frozen" value="false"/> <!-- Not for frozen records -->
<entry key="capabilityCondition.destroyIsScheduledOrComplete" value="true"/> <!-- Only for records scheduled for destruction or destroyed -->
</map>
</property>
<property name="group"><ref bean="recordsGroup"/></property> <!-- Part of the records group of capabilities -->
<property name="index" value="110" />
</bean>
</beans> </beans>

View File

@@ -0,0 +1,2 @@
report.rmr_destructionReport.name=Destruction Report (${node.rma:identifier} ${node.cm:name}).html

View File

@@ -3,9 +3,9 @@
<beans> <beans>
<!-- Report Content Model --> <!-- Report Content Model -->
<bean id="org_alfresco_module_rm_report_dictionaryBootstrap" parent="dictionaryModelBootstrap"> <bean id="org_alfresco_module_rm_report_dictionaryBootstrap" parent="dictionaryModelBootstrap">
<property name="models"> <property name="models">
<list> <list>
<value>alfresco/module/org_alfresco_module_rm/model/reportModel.xml</value> <value>alfresco/module/org_alfresco_module_rm/model/reportModel.xml</value>
@@ -16,6 +16,16 @@
<value>alfresco/module/org_alfresco_module_rm/messages/report-model</value> <value>alfresco/module/org_alfresco_module_rm/messages/report-model</value>
</list> </list>
</property> </property>
</bean>
<!-- Report Service Message Bundle -->
<bean id="org_alfresco_module_rm_report_resourceBundles" class="org.alfresco.i18n.ResourceBundleBootstrapComponent">
<property name="resourceBundles">
<list>
<value>alfresco.module.org_alfresco_module_rm.messages.report-service</value>
</list>
</property>
</bean> </bean>
<!-- Report Service --> <!-- Report Service -->
@@ -67,9 +77,13 @@
<property name="mimetypeService" ref="MimetypeService"/> <property name="mimetypeService" ref="MimetypeService"/>
<property name="fileFolderService" ref="FileFolderService"/> <property name="fileFolderService" ref="FileFolderService"/>
<property name="templateService" ref="TemplateService"/> <property name="templateService" ref="TemplateService"/>
<property name="nodeService" ref="NodeService" />
<property name="parameterProcessorComponent" ref="parameterProcessorComponent"/>
<property name="repository" ref="repositoryHelper" />
<property name="sysAdminParams" ref="sysAdminParams" />
</bean> </bean>
<bean id="destructionReportGenerator" parent="declarativeReportGenerator" > <bean id="destructionReportGenerator" parent="declarativeReportGenerator">
<property name="reportTypeName" value="rmr:destructionReport" /> <property name="reportTypeName" value="rmr:destructionReport" />
</bean> </bean>
@@ -97,10 +111,11 @@
</bean> </bean>
<bean id="fileDestructionReport" <bean id="fileDestructionReport"
class="org.alfresco.module.org_alfresco_module_rm.report.action.FileDestructionReport" class="org.alfresco.module.org_alfresco_module_rm.report.action.FileReportAction"
parent="rmAction"> parent="rmAction">
<property name="reportService" ref="ReportService" /> <property name="reportService" ref="ReportService" />
<property name="filePlanService" ref="FilePlanService" /> <property name="filePlanService" ref="FilePlanService" />
<property name="reportType" value="rmr:destructionReport" />
</bean> </bean>
</beans> </beans>

View File

@@ -26,25 +26,27 @@ import org.alfresco.module.org_alfresco_module_rm.report.ReportModel;
import org.alfresco.module.org_alfresco_module_rm.report.ReportService; import org.alfresco.module.org_alfresco_module_rm.report.ReportService;
import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ParameterCheck;
/** /**
* File Destruction Report * File Report Action
* *
* @author Roy Wetherall * @author Roy Wetherall
* @since 2.1 * @since 2.1
*/ */
public class FileDestructionReport extends RMActionExecuterAbstractBase public class FileReportAction extends RMActionExecuterAbstractBase
implements ReportModel implements ReportModel
{ {
/** Action name */
public static final String NAME = "fileDestructionReport";
/** report service */ /** report service */
protected ReportService reportService; protected ReportService reportService;
/** file plan service */ /** file plan service */
protected FilePlanService filePlanService; protected FilePlanService filePlanService;
/** report type string value */
private String reportType;
/** /**
* @param reportService report service * @param reportService report service
*/ */
@@ -61,6 +63,23 @@ public class FileDestructionReport extends RMActionExecuterAbstractBase
this.filePlanService = filePlanService; this.filePlanService = filePlanService;
} }
/**
* @param reportType report type string value
*/
public void setReportType(String reportType)
{
this.reportType = reportType;
}
/**
* @return QName report type
*/
protected QName getReportType()
{
ParameterCheck.mandatory("this.reportType", reportType);
return QName.createQName(reportType, namespaceService);
}
/** /**
* @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef) * @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef)
*/ */
@@ -78,7 +97,7 @@ public class FileDestructionReport extends RMActionExecuterAbstractBase
throw new AlfrescoRuntimeException("Unable to file destruction report, because file plan could not be resolved."); throw new AlfrescoRuntimeException("Unable to file destruction report, because file plan could not be resolved.");
} }
Report report = reportService.generateReport(TYPE_DESTRUCTION_REPORT, actionedUponNodeRef); Report report = reportService.generateReport(getReportType(), actionedUponNodeRef);
reportService.fileReport(filePlan, report); reportService.fileReport(filePlan, report);
} }

View File

@@ -23,15 +23,20 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.action.parameter.ParameterProcessorComponent;
import org.alfresco.repo.admin.SysAdminParams;
import org.alfresco.repo.model.Repository;
import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.TemplateService; import org.alfresco.service.cmr.repository.TemplateService;
import org.alfresco.util.GUID; import org.alfresco.util.UrlUtil;
import org.springframework.extensions.surf.util.I18NUtil;
/** /**
* Declarative report generator. * Declarative report generator.
@@ -41,27 +46,56 @@ import org.alfresco.util.GUID;
*/ */
public class DeclarativeReportGenerator extends BaseReportGenerator public class DeclarativeReportGenerator extends BaseReportGenerator
{ {
/** template lookup root */
protected static final NodeRef TEMPLATE_ROOT = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "rm_report_templates"); protected static final NodeRef TEMPLATE_ROOT = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "rm_report_templates");
/** model keys */
protected static final String KEY_NODE = "node";
protected static final String KEY_CHILDREN = "children";
/** content service */ /** content service */
protected ContentService contentService; protected ContentService contentService;
/** mimetype service */
protected MimetypeService mimetypeService; protected MimetypeService mimetypeService;
/** file folder service */
protected FileFolderService fileFolderService; protected FileFolderService fileFolderService;
/** template service */
protected TemplateService templateService; protected TemplateService templateService;
/** node service */
protected NodeService nodeService;
/** repository helper */
protected Repository repository;
/** parameter processor component */
protected ParameterProcessorComponent parameterProcessorComponent;
/** sys admin params */
protected SysAdminParams sysAdminParams;
/**
* @param mimetypeService mimetype service
*/
public void setMimetypeService(MimetypeService mimetypeService) public void setMimetypeService(MimetypeService mimetypeService)
{ {
this.mimetypeService = mimetypeService; this.mimetypeService = mimetypeService;
} }
/**
* @param fileFolderService file folder service
*/
public void setFileFolderService(FileFolderService fileFolderService) public void setFileFolderService(FileFolderService fileFolderService)
{ {
this.fileFolderService = fileFolderService; this.fileFolderService = fileFolderService;
} }
/**
* @param templateService template service
*/
public void setTemplateService(TemplateService templateService) public void setTemplateService(TemplateService templateService)
{ {
this.templateService = templateService; this.templateService = templateService;
@@ -75,14 +109,47 @@ public class DeclarativeReportGenerator extends BaseReportGenerator
this.contentService = contentService; this.contentService = contentService;
} }
/**
* @param nodeService node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param parameterProcessorComponent parameter processor component
*/
public void setParameterProcessorComponent(ParameterProcessorComponent parameterProcessorComponent)
{
this.parameterProcessorComponent = parameterProcessorComponent;
}
/**
* @param repository repository helper
*/
public void setRepository(Repository repository)
{
this.repository = repository;
}
/**
* @param sysAdminParams sys admin params
*/
public void setSysAdminParams(SysAdminParams sysAdminParams)
{
this.sysAdminParams = sysAdminParams;
}
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.report.generator.BaseReportGenerator#generateReportName(org.alfresco.service.cmr.repository.NodeRef) * @see org.alfresco.module.org_alfresco_module_rm.report.generator.BaseReportGenerator#generateReportName(org.alfresco.service.cmr.repository.NodeRef)
*/ */
@Override @Override
protected String generateReportName(NodeRef reportedUponNodeRef) protected String generateReportName(NodeRef reportedUponNodeRef)
{ {
// TODO Auto-generated method stub String reportTypeName = reportType.getPrefixedQName(namespaceService).getPrefixString().replace(":", "_");
return GUID.generate(); String value = I18NUtil.getMessage("report." + reportTypeName + ".name");
return parameterProcessorComponent.process(value, reportedUponNodeRef);
} }
/** /**
@@ -95,7 +162,7 @@ public class DeclarativeReportGenerator extends BaseReportGenerator
NodeRef reportTemplateNodeRef = getReportTemplate(mimetype); NodeRef reportTemplateNodeRef = getReportTemplate(mimetype);
// get the model // get the model
Map<String, Serializable> model = new HashMap<String, Serializable>(); Map<String, Serializable> model = createTemplateModel(reportTemplateNodeRef, reportedUponNodeRef);
// run the template // run the template
String result = templateService.processTemplate("freemarker", reportTemplateNodeRef.toString(), model); String result = templateService.processTemplate("freemarker", reportTemplateNodeRef.toString(), model);
@@ -106,10 +173,34 @@ public class DeclarativeReportGenerator extends BaseReportGenerator
contentWriter.setMimetype(mimetype); contentWriter.setMimetype(mimetype);
contentWriter.putContent(result); contentWriter.putContent(result);
// return the reader to the temp content
return contentWriter.getReader(); return contentWriter.getReader();
} }
protected Map<String, Serializable> createTemplateModel(NodeRef templateNodeRef, NodeRef reportedUponNodeRef)
{
Map<String, Serializable> model = new HashMap<String, Serializable>();
// build the default model
NodeRef person = repository.getPerson();
templateService.buildDefaultModel(person,
repository.getCompanyHome(),
repository.getUserHome(person),
templateNodeRef,
null);
// put the reported upon node reference in the model
model.put(KEY_NODE, reportedUponNodeRef);
// context url's (handy for images and links)
model.put("url", UrlUtil.getAlfrescoUrl(sysAdminParams));
model.put(TemplateService.KEY_SHARE_URL, UrlUtil.getShareUrl(sysAdminParams));
return model;
}
/** /**
* Get's the report template based on the type and mimetype.
* *
* @param mimetype * @param mimetype
* @return * @return
@@ -137,6 +228,7 @@ public class DeclarativeReportGenerator extends BaseReportGenerator
} }
/** /**
* Gets the template name based on the type and mimetype.
* *
* @param mimetype * @param mimetype
* @return * @return

View File

@@ -25,7 +25,6 @@ import org.alfresco.module.org_alfresco_module_rm.action.impl.DestroyAction;
import org.alfresco.module.org_alfresco_module_rm.report.Report; import org.alfresco.module.org_alfresco_module_rm.report.Report;
import org.alfresco.module.org_alfresco_module_rm.report.ReportModel; import org.alfresco.module.org_alfresco_module_rm.report.ReportModel;
import org.alfresco.module.org_alfresco_module_rm.report.ReportService; import org.alfresco.module.org_alfresco_module_rm.report.ReportService;
import org.alfresco.module.org_alfresco_module_rm.report.action.FileDestructionReport;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
@@ -86,6 +85,7 @@ public class ReportServiceImplTest extends BaseRMTestCase implements ReportModel
{ {
Report report = reportService.generateReport(TYPE_DESTRUCTION_REPORT, rmFolder); Report report = reportService.generateReport(TYPE_DESTRUCTION_REPORT, rmFolder);
System.out.println(report.getReportName());
System.out.println(report.getReportContent().getContentString()); System.out.println(report.getReportContent().getContentString());
return null; return null;
@@ -121,7 +121,7 @@ public class ReportServiceImplTest extends BaseRMTestCase implements ReportModel
public Void run() throws Exception public Void run() throws Exception
{ {
recordsManagementActionService.executeRecordsManagementAction(rmFolder, DestroyAction.NAME); recordsManagementActionService.executeRecordsManagementAction(rmFolder, DestroyAction.NAME);
recordsManagementActionService.executeRecordsManagementAction(rmFolder, FileDestructionReport.NAME); recordsManagementActionService.executeRecordsManagementAction(rmFolder, "fileDestructionReport");
return null; return null;
} }
}); });