Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.

Summit2014 topic 0066 - 10 enhancements that require 10 lines of code

551 vues

Publié le

Alfresco Share customization sample code

Publié dans : Technologie
  • Soyez le premier à commenter

  • Soyez le premier à aimer ceci

Summit2014 topic 0066 - 10 enhancements that require 10 lines of code

  1. 1. Agenda
  2. 2. Introduction http://www.keensoft.es! !!!!!!! http://orderofthebee.org! Addons committee CE EE eSign! LTA! RM!
  3. 3. Preliminary thoughts From a newbie’s point of view
  4. 4. Alfresco is hard to learn
  5. 5. Some new words (for newbies) Aikau! Activiti! AMP! WebScript! Spring Surf! FreeMarker! CMIS! Content Model!
  6. 6. Is there another life? ! "With even a few lines of code, you can easily add useful functionality to Alfresco." ! (April 4, 2014 by Jeff Potts)!
  7. 7. Disclaimer ! Source code based on Alfresco CE 4.2.f ! and available at GitHub ! ! WARNING!! Code for teaching purposes. ! Don’t try to compile it on your head.!
  8. 8. Countdown Real questions from real persons
  9. 9. 10. Add a download button Motivation. "When I get a shared document link by email and click on it, the result may not be accessible: sometimes the preview is not working, sometimes I can only see a simple picture, sometimes my computer has no Flash Player... How can I get the content of a document shared with me?"!
  10. 10. 10. Add a download button Quick Share!
  11. 11. 10. Add a download button 1. 2. <div class="document-download"> <a title="Download" class="simple-link" download="${displayName?html}" href="${url.context}/proxy/alfresco-noauth/api/internal/ shared/node/content/${args.shareId}?a=true">Download</a> </div> web-extension/site-webscripts/org/alfresco/components/quickshare/node-header.get.html.ftl
  12. 12. 10. Add a download button 2 lines! Not all browsers supported *! ! Danger zone! Alfresco default FTL! should not be ! overwritten!! ! web-extension FTL WebScript CE 5.0.a
  13. 13. 9. Site creation ability Motivation. "I don't want all the users creating sites without control, our organization is being directed by our own Process Map and no one should create content out of its limits."!
  14. 14. 9. Site creation ability
  15. 15. 9. Site creation ability (share) 1. 2. 3. var sitesMenu = widgetUtils.findObject(model.jsonModel, "id", "HEADER_SITES_MENU"); if (sitesMenu) { sitesMenu.config.showCreateSite = user.isAdmin; } web-extension/site-webscripts/es/keensoft/share/header/share-header.get.js 4. model.showCreateSite = user.isAdmin; web-extension/site-webscripts/es/keensoft/components/dashlets/my-sites.get.js
  16. 16. 9. Site creation ability (share) <extension> <modules> <module> <id>Hide Create Site</id> <customizations> <customization> <targetPackageRoot>org.alfresco</targetPackageRoot> <sourcePackageRoot>es.keensoft</sourcePackageRoot> </customization> </customizations> </module> </modules> </extension> web-extension/site-data/extensions/hide-create-site-extensions.xml
  17. 17. 9. Site creation ability (share) <!-- Required from 5.0.a --> <customization> <targetPackageRoot>org.alfresco.share.pages </targetPackageRoot> <sourcePackageRoot>es.keensoft.share.header </sourcePackageRoot> <alwaysApply> <webscript>share-header</webscript> </alwaysApply> </customization> web-extension/site-data/extensions/hide-create-site-extensions.xml C E >= 5.0.a (aikau)!
  18. 18. 9. Site creation ability (repo) function main(){ var user = people.getPerson(person.properties.userName); if (!people.isAdmin(user)) { status.setCode(status.STATUS_FORBIDDEN, "error.noPermissions"); return; } config/alfresco/extension/templates/webscripts/org/alfresco/repository/site/ sites.post.json.js 5. 6. 7. 8.
  19. 19. 9. Site creation ability web-extension 8 lines! No Alfresco repository! permissions modified *! but! repo webscript overridden! WebScript aikau Alfresco JS API * http://wiki.alfresco.com/wiki/Site_Service#Controlling_who_can_create_sites Other dashlets could be extended: dynamic-welcome, my-meeting-workspaces, my-workspaces
  20. 20. 8. Changing document extension Motivation. "We are elaborating documents on Microsoft Word, once the document is closed we are uploading a final version in PDF. Surprisingly, final document has the same extension as original (.DOC) although mimetype is right. Users can't open PDF document by downloading or by editing online because local programs are associated by file extension."!
  21. 21. 8. Changing document extension
  22. 22. 8. Changing document extension 1. 2. 3. 4. 5. 6. 7. public class ContentBehaviour implements ContentServicePolicies.OnContentPropertyUpdatePolicy { @Override public void onContentPropertyUpdate(NodeRef nodeRef, QName propertyQName, ContentData beforeValue, ContentData afterValue) { if (beforeValue != null && !beforeValue.getMimetype().equals(afterValue.getMimetype())) { String name = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); String nameNoExt = FilenameUtils.getBaseName(name); String newExt = mimetypeService.getExtension(afterValue.getMimetype()); nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, nameNoExt + "." + newExt); } } } es.keensoft.alfresco.behaviour.ContentBehaviour.java
  23. 23. 8. Changing document extension <beans> <bean id="${project.artifactId}-ContentBehavior" class="es.keensoft.alfresco.behaviour.ContentBehaviour" init-method="init"> <property name="policyComponent" ref="policyComponent" /> <property name="nodeService" ref="NodeService" /> <property name="mimetypeService" ref="MimetypeService" /> </bean> </beans> config/alfresco/module/context/service-context.xml
  24. 24. 8. Changing document extension behavior 7 lines! Alfresco Java API
  25. 25. 7. Setting create missing person Motivation. "I have configured our LDAP for identification because I don't want to take care of passwords, but I don't want everyone on this LDAP to have access to Alfresco.!
  26. 26. 7. Setting create missing person # Some authentication mechanisms may need to create people # in the repository on demand. This enables that feature. # If disabled an error will be generated for missing # people. If enabled then a person will be created and # persisted. create.missing.people=${server.transaction.allow-writes}! ! From 4.2.d! ! From 4.2! CE EE
  27. 27. 7. Setting create missing person 1. 2. 3. 4. public class CustomSpringBeanPostProcessor implements BeanFactoryPostProcessor, ApplicationContextAware { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { BeanDefinition bd = beanFactory.getBeanDefinition(beanName); bd.getPropertyValues().add(propertyName, propertyValue); } } es.keensoft.alfresco.behaviour.ContentBehaviour.java C E < 4.2.d E E < 4.2
  28. 28. 7. Setting create missing person <beans> <bean id="customSpringBeanPostProcessor" class="es.keensoft.repo.CustomSpringBeanPostProcessor"> <property name="beanName" value="personService" /> <property name="propertyName” value="createMissingPeople" /> <property name="propertyValue" value="false" /> </bean> </beans> config/alfresco/module/context/service-context.xml
  29. 29. 7. Setting create missing person Spring bean post-processor 4 lines! ! Updating Alfresco properties after Spring initialization phase!
  30. 30. 6. Custom LDAP identification Motivation. "We have several LDAP branches, one for each mail subdomain, but mail attribute is not bindable. The only attribute bindable is an UID which can be repeated on every branch. How can I identify my users?"!
  31. 31. 6. Custom LDAP identification o=sales! uid=peter peter@mkt.mail.com!o=mkt! uid=peter peter@sales.mail.com!
  32. 32. 6. Custom LDAP identification 1. 2. 3. 4. 5. 6. 7. 8. 9. public class CustomDNLDAPAuthenticationComponentImpl extends LDAPAuthenticationComponentImpl { protected void authenticateImpl(String userName, char[] password) throws AuthenticationException { if (userName.indexOf("@") != -1) { String mailDomain = userName.substring(userName.indexOf("@") + 1); String patchedUserName = userName.substring(0, userName.indexOf("@")); String dnPattern = (mailDomain == null ? null : mailDomainLdapMapping.get(mailDomain)); if (mailDomain != null && dnPattern != null && userNameFormat.indexOf(dnPattern) != -1) { userName = patchedUserName; } } super.authenticateImpl(userName, password); } } es.keensoft.repo.security.authentication.ldap. CustomDNLDAPAuthenticationComponentImpl
  33. 33. 6. Custom LDAP identification <beans> <bean id="authenticationComponent" class="es.keensoft.repo.security.authentication.ldap. CustomDNLDAPAuthenticationComponentImpl" parent="authenticationComponentBase"> ... <!-- mailDomain, targeted DN pattern --> <property name="mailDomainLdapMapping"> <map> <entry key="sales.mail.com" value="o=sales,o=isp"/> <entry key="mkt.mail.com" value="o=mkt,o=isp"/> </map> </property> </bean> </beans> config/alfresco/module/context/service-context.xml
  34. 34. 6. Custom LDAP identification Alfresco bean override 9 lines! ! Danger zone! Alfresco default beans! should not be overridden!!
  35. 35. 5. PDF/A transformation Motivation. "We are required by law to expose all our documents in PDF/A format"!
  36. 36. 5. PDF/A transformation <document-formats> <document-format><name>Portable Document Format</name> <mime-type>application/pdf</mime-type> <file-extension>pdf</file-extension> <export-filters> <entry><family>Presentation</family> <string>impress_pdf_Export</string></entry> <entry><family>Spreadsheet</family><string>calc_pdf_Export</string></entry> <entry><family>Text</family><string>writer_pdf_Export</string></entry> </export-filters> <export-options> <entry><string>SelectPdfVersion</string><int>1</int></entry> </export-options> </document-format> ... </document-formats> config/alfresco/mimetype/openoffice-document-formats.xml
  37. 37. 5. PDF/A transformation Properties override 0 lines! ! Some additional development would be necessary to have both (PDF and PDFA) transformers available!
  38. 38. 4. Importing original dates Motivation. "We have large history before Alfresco, how can I preserve the records of date for every imported document?”!
  39. 39. 4. Importing original dates 1. 2. 3. 4. 5. <model name="ks:custom-model" xmlns="http://www.alfresco.org/model/dictionary/1.0"> <imports> <import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d" /> </imports> <namespaces> <namespace uri="http://www.alfresco.com/model/custom-model/1.0" prefix="ks" /> </namespaces> <aspects> <aspect name="ks:importedDoc"> <properties> <property name="ks:originalCreationDate"> <type>d:date</type> </property> <property name="ks:originalModificationDate"> <type>d:date</type> </property> </properties> </aspect> </aspects> </model> config/alfresco/extension/model/custom-model.xml
  40. 40. 4. Importing original dates <beans> <!-- Office 2007+ --> <bean id="extracter.Poi” class="org.alfresco.repo.content.metadata.PoiMetadataExtracter” parent="baseMetadataExtracter"> <property name="inheritDefaultMapping"> <value>true</value> </property> <property name="mappingProperties"> <props> <prop key="namespace.prefix.ks"> http://www.alfresco.com/model/custom-model/1.0</prop> <prop key="Creation-Date">ks:originalCreationDate</prop> <prop key="Last-Modified">ks:originalModificationDate</prop> </props> </property> </bean> </beans> config/alfresco/extension/custom-model-context.xml
  41. 41. 4. Importing original dates Content Model 5 lines! ! Other formats could be included (PDF, ODF…)! Some other XML config is required for Alfresco Share! Extracter configuration
  42. 42. 3. Custom EML node names Motivation. "I don't understand Alfresco imported mails from IMAP, the names have no sense for me."!
  43. 43. 3. Custom EML node names content autoVersionOnUpdateProps, autoVersion, initialVersion, versionLabel title, author, modified, description 1 Create node! 2 Create content! 3 Create version! 4 Update props! name, node-dbid, store-identifier, node-uuid, modified, locale, created, store-protocol, creator, modifier Properties Properties Properties Properties
  44. 44. 3. Custom EML node names public class ImapContentBehaviour implements NodeServicePolicies.OnUpdatePropertiesPolicy { public void onUpdateProperties(NodeRef nodeRef, Map<QName, Serializable> before, Map<QName, Serializable> after) { if (!before.get(ContentModel.PROP_TITLE).equals( after.get(ContentModel.PROP_TITLE))) { String intendedName = nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE) + ".eml"; try { fileFolderService.rename(nodeRef, intendedName); } catch (Exception e) { // ELM node not renamed... } } } } 1. 2. 3. 4. 5. 6. es.keensoft.alfresco.behaviour.ImapContentBehaviour.java
  45. 45. 3. Custom EML node names <beans> <bean id="${project.artifactId}-ContentBehavior" class="es.keensoft.alfresco.behaviour.ImapContentBehaviour" init-method="init"> <property name="policyComponent" ref="policyComponent" /> <property name="nodeService" ref="NodeService" /> <property name="fileFolderService" ref="FileFolderService"/> </bean> </beans> config/alfresco/module/context/service-context.xml
  46. 46. 3. Custom EML node names behavior 6 lines! ! Custom RFC822 transformer for HTML could be included ! Alfresco Java API
  47. 47. 2. Site custom properties Motivation. "Every site on our company belongs to one entity and it’s identified by an internal ID, it’s required to set this entity on every Alfresco site creation."!
  48. 48. 2. Site custom properties (share) 1. 2. 3. 4. <@markup id="custom-properties" target="fields" action="after"> <div class="yui-gd"> <div class="yui-u first"><label for="${el}-idEntity">Entity:</label></div> <div class="yui-u"><input id="${el}-idEntity" type="text" name="idEntity”/></div> </div> </@markup> config/alfresco/web-extension/site-webscripts/es/keensoft/modules/ create-site.get.html.ftl
  49. 49. 2. Site custom properties (share) <extension> <modules> <module> <id>Custom Site Props</id> <customizations> <customization> <targetPackageRoot>org.alfresco</targetPackageRoot> <sourcePackageRoot>es.keensoft</sourcePackageRoot> </customization> </customizations> </module> </modules> </extension> web-extension/site-data/extensions/custom-site-prop-extensions.xml
  50. 50. 2. Site custom properties (repo) 5. 6. 7. 8. site = siteService.createSite(sitePreset, shortName, title, description, visibility, sitetype); if (json.has("idEntity")) { site.node.properties["stcp:idEntity"] = json.get("idEntity"); site.node.save(); site.save(); } model.site = site; config/alfresco/extension/templates/webscripts/org/alfresco/repository/site/ sites.post.json.js 2 in a row!
  51. 51. 2. Site custom properties web-extension 8 lines! ! Alfresco webscript repo extension not available! Easy to extend this ! sample for site edition! FTL Alfresco JS API
  52. 52. 1. Site templates with folders Motivation. "Someone recently asked how to create Alfresco Share sites with a default folder structure. Currently, out-of-the- box, when you create an Alfresco Share site, the document library is empty. This person instead wanted to define a set of folders that would be created in the document library when a new Alfresco Share site is created."! http://ecmarchitect.com/archives/2014/04/04/3687
  53. 53. 1. Site templates with folders public class ShareDocumentLib implements NodeServicePolicies.OnCreateNodePolicy { public void onCreateNode(ChildAssociationRef childAssocRef) { String sitePreset = nodeService.getProperty(childAssocRef.getChildRef(), PROP_SITE_PRESET); String query = "+PATH:"/app:company_home/app:dictionary/app:space_templates/*" + @cm:name:"" + sitePreset + """; ResultSet rs = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, SearchService.LANGUAGE_LUCENE, query); NodeRef documentLibrary = fileFolderService.copy(rs.getNodeRef(0), childAssocRef.getChildRef(), "documentLibrary").getNodeRef(); Map<QName, Serializable> props = new HashMap<QName, Serializable>(); props.put(ContentModel.PROP_DESCRIPTION, "Document Library"); props.put(PROP_SITE_COMPONENT_ID, "documentLibrary"); nodeService.addAspect(documentLibrary, ASPECT_SITE_CONTAINER, props); } } 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. com.ecmarchitect.share.behavior. ShareDocumentLibraryFromTemplate.java
  54. 54. 1. Site templates with folders <beans> <bean id="${project.artifactId}_siteBehavior” class="com.ecmarchitect.share.behavior.ShareDocumentLib” init-method="init"> <property name="nodeService” ref="NodeService”/> <property name="policyComponent” ref="policyComponent”/> <property name="fileFolderService” ref="FileFolderService”/> <property name="searchService” ref="SearchService”/> </bean> </beans> config/alfresco/module/share-site-space-templates-repo/context/service-context.xml
  55. 55. 1. Site templates with folders behavior 10 lines! ! Jeff Potts article and ! GitHub sample available! Alfresco Java API
  56. 56. What we have learned As Alfresco developers
  57. 57. Badges earned Content Model FTL Alfresco JS API behavior Alfresco Java API Alfresco source aikau web-extension WebScriptoverride
  58. 58. What should I learn? XML! JS! FTL! Java! Source code lines (percentage)
  59. 59. Keep it SSO Extend! Override! Overwrite! ! Alfresco source code to the rescue! .! The less you write, the better you code . Alfresco is full of hooks! .! ! [Open]
  60. 60. Resources And some contact data
  61. 61. Resources ! http://github.com/keensoft/alfresco-summit-2014! [Enhancements 1-9]! !! ! http://ecmarchitect.com/archives/2014/04/04/3687! [Enhancement 10]!
  62. 62. Contact http://www.keensoft.es! ! http://github.com/keensoft! ! @AngelBorroy! ! http://orderofthebee.org! ! http://angelborroy.wordpress.com!

×