From d12effa6d6f1083358d0ed4512f27ebc28e88707 Mon Sep 17 00:00:00 2001 From: Roy Wetherall Date: Tue, 29 Apr 2008 19:41:59 +0000 Subject: [PATCH] Moved web script classes and definitions out of web-client project and into remote-api git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@8956 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .classpath | 24 +- .../avm/applyavmcustomview.get.desc.xml | 8 + .../avm/applyavmcustomview.get.html.ftl | 52 ++ .../avm/applyavmcustomview.post.desc.xml | 8 + .../avm/applyavmcustomview.post.html.ftl | 19 + .../alfresco/avm/applyavmcustomview.post.js | 27 + .../calendar/RetrieveDayEvents.get.desc.xml | 8 + .../calendar/RetrieveDayEvents.get.html.ftl | 1 + .../calendar/RetrieveDayEvents.get.js | 234 +++++ .../RetrieveEventDefaults.get.desc.xml | 8 + .../RetrieveEventDefaults.get.html.ftl | 1 + .../calendar/RetrieveEventDefaults.get.js | 54 ++ .../RetrieveEventDetails.get.desc.xml | 8 + .../RetrieveEventDetails.get.html.ftl | 1 + .../calendar/RetrieveEventDetails.get.js | 35 + .../calendar/RetrieveMonthEvents.get.desc.xml | 8 + .../calendar/RetrieveMonthEvents.get.html.ftl | 41 + .../calendar/RetrieveMonthEvents.get.js | 221 +++++ .../calendar/RetrieveWeekEvents.get.desc.xml | 8 + .../calendar/RetrieveWeekEvents.get.html.ftl | 62 ++ .../calendar/RetrieveWeekEvents.get.js | 263 ++++++ .../calendar/SaveCalendarEvent.get.desc.xml | 8 + .../calendar/SaveCalendarEvent.get.html.ftl | 1 + .../calendar/SaveCalendarEvent.get.js | 103 +++ .../calendar/calendarDelete.post.desc.xml | 6 + .../calendar/calendarDelete.post.html.ftl | 6 + .../alfresco/calendar/calendarDelete.post.js | 33 + .../calendar/calendarEvents.get.desc.xml | 6 + .../calendar/calendarEvents.get.html.ftl | 20 + .../alfresco/calendar/calendarEvents.get.js | 87 ++ .../calendar/calendarEvents.get.json.ftl | 3 + .../calendar/calendarInit.get.desc.xml | 6 + .../calendar/calendarInit.get.html.ftl | 54 ++ .../org/alfresco/calendar/calendarInit.get.js | 56 ++ .../calendar/calendarSub.post.desc.xml | 6 + .../calendar/calendarSub.post.html.ftl | 6 + .../org/alfresco/calendar/calendarSub.post.js | 29 + .../org/alfresco/calendar/color.get.desc.xml | 6 + .../org/alfresco/calendar/color.get.html.ftl | 3 + .../org/alfresco/calendar/color.get.js | 31 + .../org/alfresco/calendar/color.post.desc.xml | 6 + .../org/alfresco/calendar/color.post.html.ftl | 2 + .../org/alfresco/calendar/color.post.js | 27 + .../collaboration/blogSpace.get.desc.xml | 8 + .../collaboration/blogSpace.get.html.ftl | 176 ++++ .../alfresco/collaboration/blogSpace.get.js | 100 +++ .../collaboration/blogSummary.get.desc.xml | 8 + .../collaboration/blogSummary.get.html.ftl | 2 + .../alfresco/collaboration/blogSummary.get.js | 53 ++ .../collaboration/calendar.get.desc.xml | 8 + .../collaboration/calendar.get.html.ftl | 219 +++++ .../calendarSummary.get.desc.xml | 8 + .../calendarSummary.get.html.ftl | 2 + .../collaboration/calendarSummary.get.js | 56 ++ .../colleaguePresence.get.desc.xml | 8 + .../colleaguePresence.get.html.ftl | 119 +++ .../collaboration/colleaguePresence.get.js | 68 ++ .../collaboration/docLibrary.get.desc.xml | 8 + .../collaboration/docLibrary.get.html.ftl | 120 +++ .../collaboration/docSummary.get.desc.xml | 8 + .../collaboration/docSummary.get.html.ftl | 2 + .../alfresco/collaboration/docSummary.get.js | 59 ++ .../collaboration/emailSummary.get.desc.xml | 8 + .../collaboration/emailSummary.get.html.ftl | 2 + .../collaboration/emailSummary.get.js | 54 ++ .../collaboration/forumSummary.get.desc.xml | 8 + .../collaboration/forumSummary.get.html.ftl | 2 + .../collaboration/forumSummary.get.js | 59 ++ .../collaboration/gallery.get.desc.xml | 14 + .../org/alfresco/collaboration/gallery.get.js | 9 + .../collaboration/gallery.get.xml.ftl | 21 + .../collaboration/gallerySummary.get.desc.xml | 8 + .../collaboration/gallerySummary.get.html.ftl | 2 + .../collaboration/gallerySummary.get.js | 50 ++ .../collaboration/projectSpace.get.desc.xml | 8 + .../collaboration/projectSpace.get.html.ftl | 150 ++++ .../collaboration/projectSpace.get.js | 36 + .../collaboration/tagActions.get.desc.xml | 8 + .../collaboration/tagActions.get.html.ftl | 52 ++ .../collaboration/tagActions.post.desc.xml | 8 + .../collaboration/tagActions.post.html.ftl | 5 + .../alfresco/collaboration/tagActions.post.js | 150 ++++ .../collaboration/tagQuery.get.desc.xml | 8 + .../collaboration/tagQuery.get.html.ftl | 13 + .../alfresco/collaboration/tagQuery.get.js | 104 +++ .../collaboration/viewgallery.get.desc.xml | 14 + .../collaboration/viewgallery.get.html.ftl | 28 + .../alfresco/collaboration/viewgallery.get.js | 3 + .../org/alfresco/jsdebugger.get.desc.xml | 6 + .../org/alfresco/jsdebugger.get.html.ftl | 22 + .../org/alfresco/jsdebugger.post.desc.xml | 6 + .../org/alfresco/jsdebugger.post.html.ftl | 22 + .../alfresco/office/docActions.get.desc.xml | 7 + .../alfresco/office/docActions.get.html.ftl | 4 + .../org/alfresco/office/docActions.get.js | 158 ++++ .../office/documentDetails.get.desc.xml | 7 + .../office/documentDetails.get.html.ftl | 263 ++++++ .../org/alfresco/office/getUsers.get.desc.xml | 7 + .../org/alfresco/office/getUsers.get.html.ftl | 7 + .../org/alfresco/office/getUsers.get.js | 18 + .../alfresco/office/myAlfresco.get.desc.xml | 7 + .../alfresco/office/myAlfresco.get.html.ftl | 159 ++++ .../org/alfresco/office/myTasks.get.desc.xml | 7 + .../org/alfresco/office/myTasks.get.html.ftl | 141 +++ .../org/alfresco/office/myTasks.get.js | 5 + .../office/myTasksDetail.get.desc.xml | 7 + .../office/myTasksDetail.get.html.ftl | 94 ++ .../alfresco/office/navigation.get.desc.xml | 7 + .../alfresco/office/navigation.get.html.ftl | 227 +++++ .../org/alfresco/office/navigation.get.js | 37 + .../org/alfresco/office/search.get.desc.xml | 7 + .../org/alfresco/office/search.get.html.ftl | 77 ++ .../office/searchResults.get.desc.xml | 7 + .../office/searchResults.get.html.ftl | 75 ++ .../org/alfresco/office/searchResults.get.js | 23 + .../org/alfresco/office/tags.get.desc.xml | 7 + .../org/alfresco/office/tags.get.html.ftl | 62 ++ .../org/alfresco/office/tags.get.js | 0 .../alfresco/portlets/doclist.get.atom.ftl | 72 ++ .../alfresco/portlets/doclist.get.desc.xml | 8 + .../alfresco/portlets/doclist.get.html.ftl | 445 +++++++++ .../portlets/doclistpanel.get.desc.xml | 7 + .../portlets/doclistpanel.get.html.ftl | 53 ++ .../alfresco/portlets/myspaces.get.desc.xml | 7 + .../alfresco/portlets/myspaces.get.html.ftl | 567 ++++++++++++ .../portlets/myspacespanel.get.desc.xml | 7 + .../portlets/myspacespanel.get.html.ftl | 61 ++ .../alfresco/portlets/mytasks.get.desc.xml | 7 + .../alfresco/portlets/mytasks.get.html.ftl | 483 ++++++++++ .../portlets/mytaskspanel.get.desc.xml | 7 + .../portlets/mytaskspanel.get.html.ftl | 102 +++ .../alfresco/portlets/mywebfiles.get.desc.xml | 7 + .../alfresco/portlets/mywebfiles.get.html.ftl | 271 ++++++ .../alfresco/portlets/mywebforms.get.desc.xml | 7 + .../alfresco/portlets/mywebforms.get.html.ftl | 196 ++++ .../alfresco/repository/login.get.desc.xml | 8 + .../org/alfresco/repository/login.get.xml.ftl | 2 + .../repository/loginticket.delete.desc.xml | 8 + .../repository/loginticket.get.desc.xml | 8 + .../repository/loginticket.get.xml.ftl | 2 + .../search/keywordsearch.get.atom.ftl | 41 + .../search/keywordsearch.get.desc.xml | 12 + .../search/keywordsearch.get.html.ftl | 54 ++ .../search/keywordsearch.get.portlet.ftl | 33 + .../search/keywordsearch.get.query_.ftl | 11 + .../search/keywordsearch.get.rss.ftl | 41 + .../keywordsearchdescription.get.desc.xml | 7 + ...hdescription.get.opensearchdescription.ftl | 11 + .../search/personsearch.get.atom.ftl | 46 + .../search/personsearch.get.desc.xml | 12 + .../search/personsearch.get.html.ftl | 55 ++ .../search/personsearch.get.portlet.ftl | 36 + .../search/personsearch.get.query_.ftl | 11 + .../search/personsearch.get.rss.ftl | 46 + .../personsearchdescription.get.desc.xml | 7 + ...hdescription.get.opensearchdescription.ftl | 11 + .../search/searchengines.get.atom.ftl | 20 + .../search/searchengines.get.desc.xml | 8 + .../search/searchengines.get.html.ftl | 32 + .../search/searchproxy.get.desc.xml | 7 + .../repository/site/sites.get.desc.xml | 8 + .../org/alfresco/repository/site/sites.get.js | 9 + .../repository/site/sites.get.json.ftl | 14 + .../repository/site/sites.post.desc.xml | 8 + .../alfresco/repository/site/sites.post.js | 12 + .../repository/site/sites.post.json.ftl | 8 + .../repository/store/content.get.desc.xml | 9 + .../repository/store/remoteavm.get.desc.xml | 7 + .../repository/store/remoteavm.post.desc.xml | 7 + .../documentlibrary/doclist.get.desc.xml | 7 + .../documentlibrary/doclist.get.html.ftl | 24 + .../slingshot/documentlibrary/doclist.get.js | 76 ++ .../web-scripts-application-context-test.xml | 25 + .../web-scripts-application-context.xml | 225 +++++ config/alfresco/web-scripts-config.xml | 67 ++ .../repo/web/scripts/BaseWebScriptTest.java | 111 +++ .../alfresco/repo/web/scripts/RepoStore.java | 850 ++++++++++++++++++ .../alfresco/repo/web/scripts/Repository.java | 484 ++++++++++ .../repo/web/scripts/RepositoryContainer.java | 393 ++++++++ .../web/scripts/RepositoryImageResolver.java | 79 ++ .../scripts/RepositoryScriptProcessor.java | 189 ++++ .../web/scripts/RepositoryServerModel.java | 122 +++ .../scripts/RepositoryTemplateProcessor.java | 237 +++++ .../web/scripts/TestWebScriptRepoServer.java | 159 ++++ .../repo/web/scripts/bean/AVMRemoteStore.java | 218 +++++ .../web/scripts/bean/BaseRemoteStore.java | 253 ++++++ .../repo/web/scripts/bean/ContentGet.java | 283 ++++++ .../web/scripts/bean/JavascriptDebugger.java | 67 ++ .../scripts/bean/JavascriptDebuggerPost.java | 78 ++ .../repo/web/scripts/bean/KeywordSearch.java | 419 +++++++++ .../alfresco/repo/web/scripts/bean/Login.java | 97 ++ .../repo/web/scripts/bean/LoginTicket.java | 99 ++ .../web/scripts/bean/LoginTicketDelete.java | 114 +++ .../repo/web/scripts/bean/SearchEngines.java | 210 +++++ .../repo/web/scripts/bean/SearchProxy.java | 317 +++++++ .../config/OpenSearchConfigElement.java | 282 ++++++ .../config/OpenSearchElementReader.java | 119 +++ .../FacebookAuthenticatorFactory.java | 150 ++++ .../JSR168PortletAuthenticatorFactory.java | 173 ++++ .../BasicHttpAuthenticatorFactory.java | 214 +++++ .../web/scripts/site/TestSiteService.java | 84 ++ 201 files changed, 14060 insertions(+), 11 deletions(-) create mode 100644 config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.post.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.post.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.post.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveDayEvents.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveDayEvents.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveDayEvents.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDefaults.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDefaults.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDefaults.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDetails.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDetails.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDetails.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveMonthEvents.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveMonthEvents.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveMonthEvents.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveWeekEvents.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveWeekEvents.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveWeekEvents.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/SaveCalendarEvent.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/SaveCalendarEvent.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/SaveCalendarEvent.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/calendarDelete.post.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/calendarDelete.post.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/calendarDelete.post.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/calendarEvents.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/calendarEvents.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/calendarEvents.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/calendarEvents.get.json.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/calendarInit.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/calendarInit.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/calendarInit.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/calendarSub.post.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/calendarSub.post.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/calendarSub.post.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/color.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/color.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/color.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/color.post.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/color.post.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/calendar/color.post.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSpace.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSpace.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSpace.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSummary.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSummary.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSummary.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/calendar.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/calendar.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/calendarSummary.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/calendarSummary.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/calendarSummary.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/colleaguePresence.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/colleaguePresence.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/colleaguePresence.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/docLibrary.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/docLibrary.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/docSummary.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/docSummary.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/docSummary.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/emailSummary.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/emailSummary.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/emailSummary.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/forumSummary.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/forumSummary.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/forumSummary.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/gallery.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/gallery.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/gallery.get.xml.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/gallerySummary.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/gallerySummary.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/gallerySummary.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/projectSpace.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/projectSpace.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/projectSpace.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.post.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.post.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.post.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/tagQuery.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/tagQuery.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/tagQuery.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/viewgallery.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/viewgallery.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/collaboration/viewgallery.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/jsdebugger.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/jsdebugger.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/jsdebugger.post.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/jsdebugger.post.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/docActions.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/docActions.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/docActions.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/documentDetails.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/documentDetails.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/getUsers.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/getUsers.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/getUsers.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/myAlfresco.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/myAlfresco.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/myTasks.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/myTasks.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/myTasks.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/myTasksDetail.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/myTasksDetail.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/navigation.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/navigation.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/navigation.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/search.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/search.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/searchResults.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/searchResults.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/searchResults.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/tags.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/tags.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/office/tags.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/doclist.get.atom.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/doclist.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/doclist.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/doclistpanel.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/doclistpanel.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/myspaces.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/myspaces.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/myspacespanel.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/myspacespanel.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/mytasks.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/mytasks.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/mytaskspanel.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/mytaskspanel.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/mywebfiles.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/mywebfiles.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/mywebforms.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/portlets/mywebforms.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/login.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/login.get.xml.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/loginticket.delete.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/loginticket.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/loginticket.get.xml.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.atom.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.portlet.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.query_.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.rss.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearchdescription.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearchdescription.get.opensearchdescription.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.atom.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.portlet.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.query_.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.rss.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearchdescription.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearchdescription.get.opensearchdescription.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/searchengines.get.atom.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/searchengines.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/searchengines.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/search/searchproxy.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.get.json.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.post.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.post.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.post.json.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/store/content.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteavm.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteavm.post.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/doclist.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/doclist.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/doclist.get.js create mode 100644 config/alfresco/web-scripts-application-context-test.xml create mode 100644 config/alfresco/web-scripts-application-context.xml create mode 100644 config/alfresco/web-scripts-config.xml create mode 100644 source/java/org/alfresco/repo/web/scripts/BaseWebScriptTest.java create mode 100644 source/java/org/alfresco/repo/web/scripts/RepoStore.java create mode 100644 source/java/org/alfresco/repo/web/scripts/Repository.java create mode 100644 source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java create mode 100644 source/java/org/alfresco/repo/web/scripts/RepositoryImageResolver.java create mode 100644 source/java/org/alfresco/repo/web/scripts/RepositoryScriptProcessor.java create mode 100644 source/java/org/alfresco/repo/web/scripts/RepositoryServerModel.java create mode 100644 source/java/org/alfresco/repo/web/scripts/RepositoryTemplateProcessor.java create mode 100644 source/java/org/alfresco/repo/web/scripts/TestWebScriptRepoServer.java create mode 100644 source/java/org/alfresco/repo/web/scripts/bean/AVMRemoteStore.java create mode 100644 source/java/org/alfresco/repo/web/scripts/bean/BaseRemoteStore.java create mode 100644 source/java/org/alfresco/repo/web/scripts/bean/ContentGet.java create mode 100644 source/java/org/alfresco/repo/web/scripts/bean/JavascriptDebugger.java create mode 100644 source/java/org/alfresco/repo/web/scripts/bean/JavascriptDebuggerPost.java create mode 100644 source/java/org/alfresco/repo/web/scripts/bean/KeywordSearch.java create mode 100644 source/java/org/alfresco/repo/web/scripts/bean/Login.java create mode 100644 source/java/org/alfresco/repo/web/scripts/bean/LoginTicket.java create mode 100644 source/java/org/alfresco/repo/web/scripts/bean/LoginTicketDelete.java create mode 100644 source/java/org/alfresco/repo/web/scripts/bean/SearchEngines.java create mode 100644 source/java/org/alfresco/repo/web/scripts/bean/SearchProxy.java create mode 100644 source/java/org/alfresco/repo/web/scripts/config/OpenSearchConfigElement.java create mode 100644 source/java/org/alfresco/repo/web/scripts/config/OpenSearchElementReader.java create mode 100644 source/java/org/alfresco/repo/web/scripts/facebook/FacebookAuthenticatorFactory.java create mode 100644 source/java/org/alfresco/repo/web/scripts/portlet/JSR168PortletAuthenticatorFactory.java create mode 100644 source/java/org/alfresco/repo/web/scripts/servlet/BasicHttpAuthenticatorFactory.java create mode 100644 source/java/org/alfresco/repo/web/scripts/site/TestSiteService.java diff --git a/.classpath b/.classpath index 72481c33fe..5f52aa0f80 100644 --- a/.classpath +++ b/.classpath @@ -1,11 +1,13 @@ - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.get.desc.xml new file mode 100644 index 0000000000..fe995ae216 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.get.desc.xml @@ -0,0 +1,8 @@ + + Apply AVM Custom View + Simple UI to help apply a WebScript based custom view to an AVM folder + /avm/applyavmcustomview + extension + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.get.html.ftl new file mode 100644 index 0000000000..2dcf2f349a --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.get.html.ftl @@ -0,0 +1,52 @@ + + + + + Apply AVM WebScript Custom View + + + + +
+ +
+ Store: +
e.g. website1--admin
+
+ +
+ Folder Path: +
e.g. /ROOT/images
+
+ +
+ WebScript URL: +
e.g. /utils/avmview
A well known token {path} can be used in the url and will be replaced by the current AVM folder path at runtime.
+
+ +
+ +
+ +
+ + + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.post.desc.xml new file mode 100644 index 0000000000..f8b05a54a3 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.post.desc.xml @@ -0,0 +1,8 @@ + + Apply AVM Custom View POST + Simple UI to help apply a WebScript based custom view to an AVM folder + /avm/applyavmcustomview + extension + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.post.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.post.html.ftl new file mode 100644 index 0000000000..94508d81ae --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.post.html.ftl @@ -0,0 +1,19 @@ + + + + Apply AVM WebScript Custom View - Done + + + + <#if success> + Operation Complete. + <#else> + Operation FAILED. Unable to find store or node. + + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.post.js b/config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.post.js new file mode 100644 index 0000000000..24ab94c6bd --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/avm/applyavmcustomview.post.js @@ -0,0 +1,27 @@ +// check that search term has been provided +if (args.store == undefined || args.store.length == 0 || + args.path == undefined || args.path.length == 0 || + args.view == undefined || args.view.length == 0) +{ + status.code = 400; + status.message = "Mandatory arguments not set - please complete all form fields."; + status.redirect = true; +} +else +{ + // lookup the root on the store + var storeRootNode = avm.lookupStoreRoot(args.store); + if (storeRootNode != null) + { + var path = storeRootNode.path + args.path; + var node = avm.lookupNode(path); + if (node != null) + { + // add the custom view aspect + node.addAspect("cm:webscriptable"); + node.properties["cm:webscript"] = "/wcs" + args.view; + node.save(); + model.success = true; + } + } +} \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveDayEvents.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveDayEvents.get.desc.xml new file mode 100644 index 0000000000..be8e60e95f --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveDayEvents.get.desc.xml @@ -0,0 +1,8 @@ + + Retrieve Day Events + Retrieve Day Events + /calendar/RetrieveDayEvents?d={requiredDate}&s={currentSpace} + extension + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveDayEvents.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveDayEvents.get.html.ftl new file mode 100644 index 0000000000..ffd02ee697 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveDayEvents.get.html.ftl @@ -0,0 +1 @@ +${result} diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveDayEvents.get.js b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveDayEvents.get.js new file mode 100644 index 0000000000..62d30fdcfb --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveDayEvents.get.js @@ -0,0 +1,234 @@ +// +// Modified to include events from subscribed calendars. +// +// Author: simon@webteq.eu +// + +var dateString = args.d; +var requiredDate = new Date(dateString); + +var spaceRef = args.s; +var currentBaseSpace = findNodeByNodeRef(spaceRef); + +var calendarSpaceArray = function() { + var c = null; + var x = new Array(); + var y = currentBaseSpace.assocs["ia:subscribedCalendarList"]; + if (y != null) + { + for (i=0; i event.tabs) { + event.tabs = tabs; + } + // Add spacer tabs if necessary + if (event.tabs - tabs > 0) { + html += addPadding(event.tabs - tabs); + } + var style = new Array(); + style[0] = "border-left: 6px solid " + event.color; + var content = " "; + if (interval.start.getTime() == event_interval.start.getTime()) { + style[1] = "border-top: 1px solid black"; + style[2] = "padding-top: 0px"; + content = event.name; + } else if (interval.end.getTime() == event_interval.end.getTime()) { + style[1] = "border-bottom: 1px solid black"; + style[2] = "padding-top: 0px"; + } + // Add the event + html += "
" + content + "
"; + tabs = event.tabs + 1; + } + } + html += ""; + return html; +} + +function addPadding(amount) { + var spacertext = ""; + for(z=0; z "; + } + return spacertext; +} + +String.prototype.pad = function(l, s, t) { + return s || (s = " "), (l -= this.length) > 0 ? (s = new Array(Math.ceil(l / s.length) + + 1).join(s)).substr(0, t = !t ? l : t == 1 ? 0 : Math.ceil(l / 2)) + + this + s.substr(0, l - t) : this; +}; + +function getGUIDFromNodeRef(nodeRef) { + var str = "" + nodeRef; + if (str.length > 24) { + return str.substring(24); + } + else { + return "Not a NodeRef"; + } +} + +function findNodeByNodeRef(nodeRef) { + var resultsArray = search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef)); + + if (resultsArray != null && resultsArray.length > 0) { + return resultsArray[0]; + } + else { + return null; + } +} + +var response = ""; + +var _arr = HoursArray(); +for (i=0; i<_arr.length; i++) +{ + var tdclass = ""; + if (i % 2 == 0) + tdclass = "alternateRow"; + else + tdclass = ""; + response += ""; + response += ""; + response += ""; + response += ""; +} + +response += "
" + _arr[i] + "" + getIntervalEvents(intervals[i]) + "
"; + +model.result = response; + +model.intervals = intervals; +model.eventList = events; \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDefaults.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDefaults.get.desc.xml new file mode 100644 index 0000000000..c9a7b70ebc --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDefaults.get.desc.xml @@ -0,0 +1,8 @@ + + Retrieve Event Defaults + Retrieve Event Defaults + /calendar/RetrieveEventDefaults?s={spaceRef} + extension + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDefaults.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDefaults.get.html.ftl new file mode 100644 index 0000000000..967faeb995 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDefaults.get.html.ftl @@ -0,0 +1 @@ +${result} \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDefaults.get.js b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDefaults.get.js new file mode 100644 index 0000000000..cf98f3b678 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDefaults.get.js @@ -0,0 +1,54 @@ +function getGUIDFromNodeRef(nodeRef) +{ + var str = "" + nodeRef; + return str.substring(str.lastIndexOf("/")+1); +} + +function findNodeByNodeRef(nodeRef) +{ + var resultsArray= search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef)); + + if (resultsArray != null && resultsArray.length > 0) + { + return resultsArray[0]; + } + else + { + return null; + } +} + +var spaceRef = args.s; +var currentBaseSpace = findNodeByNodeRef(spaceRef); +var response = "" +var _today = new Date(); + +if (currentBaseSpace != null) +{ + if (currentBaseSpace.properties["ia:whatEventDefault"] != null) + response += currentBaseSpace.properties["ia:whatEventDefault"] + "^"; + else + response += "" + "^"; + + if (currentBaseSpace.properties["ia:fromDateDefault"] != null) + response += currentBaseSpace.properties["ia:fromDateDefault"] + "^"; + else + response += _today.toString() + "^"; + + if (currentBaseSpace.properties["ia:toDateDefault"] != null) + response += currentBaseSpace.properties["ia:toDateDefault"] + "^"; + else + response += _today.toString() + "^"; + + if (currentBaseSpace.properties["ia:whereEventDefault"] != null) + response += currentBaseSpace.properties["ia:whereEventDefault"] + "^"; + else + response += "" + "^"; + + if (currentBaseSpace.properties["ia:colorEventDefault"] != null) + response += currentBaseSpace.properties["ia:colorEventDefault"]; + else + response += ""; +} +logger.log("RESPONSE: " + response); +model.result = response; diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDetails.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDetails.get.desc.xml new file mode 100644 index 0000000000..08fca008ca --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDetails.get.desc.xml @@ -0,0 +1,8 @@ + + Retrieve Event Details + Retrieve Event Details + /calendar/RetrieveEventDetails?e={eventId} + extension + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDetails.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDetails.get.html.ftl new file mode 100644 index 0000000000..967faeb995 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDetails.get.html.ftl @@ -0,0 +1 @@ +${result} \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDetails.get.js b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDetails.get.js new file mode 100644 index 0000000000..1215dae1f9 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveEventDetails.get.js @@ -0,0 +1,35 @@ +var eventId = args.e; +var eventNode = search.findNode(eventId); + +if (eventNode == null) +{ + model.result = "Event not Found"; +} + +else +{ + var response = ""; + var _fromDate = eventNode.properties["ia:fromDate"]; + var _toDate = eventNode.properties["ia:toDate"]; + var _fromMonth = _fromDate.getMonth() + 1; + var _toMonth = _toDate.getMonth() + 1; + + response += eventNode.properties["ia:whatEvent"] + "^"; + response += _fromMonth + "/" + _fromDate.getDate() + "/" + _fromDate.getFullYear() + "^"; + var frmHour = _fromDate.getHours(); + if (frmHour == 0) frmHour += "0"; + var frmMin = _fromDate.getMinutes(); + if (frmMin == 0) frmMin += "0"; + response += frmHour + ":" + frmMin + "^"; + response += _toMonth + "/" + _toDate.getDate() + "/" + _toDate.getFullYear() + "^"; + var toHour = _toDate.getHours(); + if (toHour == 0) toHour += "0"; + var toMin = _toDate.getMinutes(); + if (toMin == 0) toMin += "0"; + response += toHour + ":" + toMin + "^"; + response += eventNode.properties["ia:whereEvent"] + "^"; + response += eventNode.properties["ia:descriptionEvent"] + "^"; + response += eventNode.properties["ia:colorEvent"]; + + model.result=response; +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveMonthEvents.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveMonthEvents.get.desc.xml new file mode 100644 index 0000000000..d577ccdb31 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveMonthEvents.get.desc.xml @@ -0,0 +1,8 @@ + + Retrieve Month Events + Retrieve Month Events + /calendar/RetrieveMonthEvents?d={requiredDate}&s={currentSpace} + extension + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveMonthEvents.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveMonthEvents.get.html.ftl new file mode 100644 index 0000000000..1a5002efa2 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveMonthEvents.get.html.ftl @@ -0,0 +1,41 @@ +<#assign days = DaysArray> + + + + <#list days as item> + + + + + <#assign i=0> + <#list eventList?chunk(7, '-') as row> + <#if i % 2 == 0> + <#assign tdclass = "alternateRow"> + <#else> + <#assign tdclass = ""> + + <#assign i = i+1> + + <#list row as cell> + <#if cell?exists> + + <#else> + + + + + +
${item}
+ + <#if cell.object?exists> + <#list cell.object as eachEvent> + <#if eachEvent.isEditable == 1> +
${eachEvent.object.properties["ia:whatEvent"]}
+ <#else> +
${eachEvent.object.properties["ia:whatEvent"]}
+ + + +
 
diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveMonthEvents.get.js b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveMonthEvents.get.js new file mode 100644 index 0000000000..3b2589999b --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveMonthEvents.get.js @@ -0,0 +1,221 @@ +var dateString = args.d; +var _currentDateForMonthView= new Date(dateString); + +var spaceRef = args.s; +var currentBaseSpace = findNodeByNodeRef(spaceRef); + +var eventList = new Array(); + +function editableObject(obj, iseditable, color) { + this.object = obj; + this.isEditable = iseditable; + this.color = color; +} + +function eventType(datepart, obj) { + this.datePart = datepart; + this.object = obj; +} + +var DaysArray = function() { + var _arr = new Array(); + _arr[0] = "Sunday"; + _arr[1] = "Monday"; + _arr[2] = "Tuesday"; + _arr[3] = "Wednesday"; + _arr[4] = "Thursday"; + _arr[5] = "Friday"; + _arr[6] = "Saturday"; + + return _arr; +} + +var MonthsArray = function() { + var _arr = new Array(); + _arr[0] = "January"; + _arr[1] = "February"; + _arr[2] = "March"; + _arr[3] = "April"; + _arr[4] = "May"; + _arr[5] = "June"; + _arr[6] = "July"; + _arr[7] = "August"; + _arr[8] = "September"; + _arr[9] = "October"; + _arr[10] = "November"; + _arr[11] = "December"; + + return _arr; +} + +String.prototype.pad = function(l, s, t) { + return s || (s = " "), (l -= this.length) > 0 ? (s = new Array(Math.ceil(l / s.length) + + 1).join(s)).substr(0, t = !t ? l : t == 1 ? 0 : Math.ceil(l / 2)) + + this + s.substr(0, l - t) : this; +}; + +var calendarSpaceArray = function() { + var color; + var defaultColor = "#FF0000"; + + var c = null; + var x = new Array(); + var y = currentBaseSpace.assocs["ia:subscribedCalendarList"]; + if (y != null) { + for (i=0; i= requiredDate) + { + eventsArr.push(new editableObject(child, calendarSpaces[j].isEditable, calendarSpaces[j].color)); + } + } + } + } + + eventsArr.sort(SortCalendarEvents); + var tempEvents = new Array(); + + for (var j=0; j 0) + { + return resultsArray[0]; + } + else + { + return null; + } +} + +var response; + +if (currentBaseSpace == null) +{ + response = "Parameters passed:
"; + response += "Current Date: " + dateString + "
"; + response += "Current Space: " + spaceRef + "
"; + response += "
Error: No Space found by this Ref"; +} +else +{ + calendarSpaces = calendarSpaceArray(); + + var _arrDay = DaysArray(); + var tmpDate; + var i, j; + + + // Start with the first day of the month and go back if necessary to the previous Sunday. + tmpDate = new Date(Date.parse(_currentDateForMonthView)); + tmpDate.setDate(1); + tmpDate.setHours(0,0,0,0); + while (tmpDate.getDay() != 0) + { + tmpDate.setDate(tmpDate.getDate() - 1); + } + + for (i = 2; i <= 7; i++) + { + // Loop through a week. + for (j = 0; j < _arrDay.length; j++) + { + if (tmpDate.getMonth() == _currentDateForMonthView.getMonth()) + { + eventList.push(new eventType(tmpDate.getDate(), getDayEvents(tmpDate))); + } + else + { + eventList.push(null); + } + + // Go to the next day. + tmpDate.setDate(tmpDate.getDate() + 1); + } + } + +} + +model.DaysArray = DaysArray(); +model.eventList = eventList; diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveWeekEvents.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveWeekEvents.get.desc.xml new file mode 100644 index 0000000000..7c9ec1fb20 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveWeekEvents.get.desc.xml @@ -0,0 +1,8 @@ + + Retrieve Week Events + Retrieve Week Events + /calendar/RetrieveWeekEvents?d={requiredDate}&s={currentSpace} + extension + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveWeekEvents.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveWeekEvents.get.html.ftl new file mode 100644 index 0000000000..241e4519e2 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveWeekEvents.get.html.ftl @@ -0,0 +1,62 @@ + + +
${dayCaption}
+
+ + + + + <#list daysArray as item> + + + + + + + <#list eventListAllDay as item> + + + + + <#assign i=0> + <#list eventList as item> + <#if i % 2 == 0> + <#assign tdclass = "alternateRow"> + <#else> + <#assign tdclass = ""> + + <#assign i = i+1> + + + <#list item.object as hourEvents> + + + + + +
 ${item}
All Day + <#if item?exists> + <#list item as eachEvent> + <#if eachEvent.isEditable == 1> +
${eachEvent.object.properties["ia:whatEvent"]}
+ <#else> +
${eachEvent.object.properties["ia:whatEvent"]}
+ + + <#else> +   + +
${item.timeSlot} + <#if hourEvents.object?exists> + <#list hourEvents.object as eachEvent> + <#if eachEvent.isEditable == 1> +
${eachEvent.object.properties["ia:whatEvent"]}
+ <#else> +
${eachEvent.object.properties["ia:whatEvent"]}
+ + + + <#else> +   + +
diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveWeekEvents.get.js b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveWeekEvents.get.js new file mode 100644 index 0000000000..aa007d0c07 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/RetrieveWeekEvents.get.js @@ -0,0 +1,263 @@ +var dateString = args.d; +var _currentDateForWeekView= new Date(dateString); + +var spaceRef = args.s; +var currentBaseSpace = findNodeByNodeRef(spaceRef); + +var eventList = new Array(); +var eventListAllDay = new Array(); +var days = new Array(); + +function editableObject(obj, iseditable, color) { + this.object = obj; + this.isEditable = iseditable; + this.color = color; +} + +function eventType(obj, timeslot) { + this.object = obj; + this.timeSlot = timeslot; +} + +var HoursArray = function() { + var _arr = new Array(); + _arr[0] = "00:00"; + _arr[1] = "00:30"; + for (i=1; i<24; i++) { + _arr[i*2] = i + ":00"; + _arr[i*2+1] = i + ":30"; + } + return _arr; +} + +var DaysArray = function() { + var _arr = new Array(); + _arr[0] = "Sunday"; + _arr[1] = "Monday"; + _arr[2] = "Tuesday"; + _arr[3] = "Wednesday"; + _arr[4] = "Thursday"; + _arr[5] = "Friday"; + _arr[6] = "Saturday"; + + return _arr; +} + +var MonthsArray = function() { + var _arr = new Array(); + _arr[0] = "Jan"; + _arr[1] = "Feb"; + _arr[2] = "Mar"; + _arr[3] = "Apr"; + _arr[4] = "May"; + _arr[5] = "Jun"; + _arr[6] = "Jul"; + _arr[7] = "Aug"; + _arr[8] = "Sep"; + _arr[9] = "Oct"; + _arr[10] = "Nov"; + _arr[11] = "Dec"; + + return _arr; +} + +String.prototype.pad = function(l, s, t) { + return s || (s = " "), (l -= this.length) > 0 ? (s = new Array(Math.ceil(l / s.length) + + 1).join(s)).substr(0, t = !t ? l : t == 1 ? 0 : Math.ceil(l / 2)) + + this + s.substr(0, l - t) : this; +}; + +var calendarSpaceArray = function() { + var color; + var defaultColor = "#FF0000"; + + var c = null; + var x = new Array(); + var y = currentBaseSpace.assocs["ia:subscribedCalendarList"]; + if (y != null) { + for (i=0; i requiredDate) + showTimeLine = child.properties["ia:fromDate"].getDate() + " " + _months[child.properties["ia:fromDate"].getMonth()] + ", " + child.properties["ia:fromDate"].getHours() + ":" + child.properties["ia:fromDate"].getMinutes().toString().pad(2, "0", 1) + " - " + child.properties["ia:toDate"].getDate() + " " + _months[child.properties["ia:toDate"].getMonth()] + ", " + child.properties["ia:toDate"].getHours() + ":" + child.properties["ia:toDate"].getMinutes().toString().pad(2, "0", 1); + else + showTimeLine = child.properties["ia:fromDate"].getHours() + ":" + child.properties["ia:fromDate"].getMinutes().toString().pad(2, "0", 1) + " - " + child.properties["ia:toDate"].getHours() + ":" + child.properties["ia:toDate"].getMinutes().toString().pad(2, "0", 1); + + + eventArr.push(new editableObject(child, calendarSpaces[j].isEditable, calendarSpaces[j].color)); + } + } + } + } + if (eventArr.length == 0) { eventArr = null; } + return eventArr; +} + +function getAllDayEvents(requiredDate) +{ + var eventArr = new Array(); + var _months = MonthsArray(); + + if (currentBaseSpace == null) + return null; + + for (var j=0; j= requiredDate) + { + eventArr.push(new editableObject(child, calendarSpaces[j].isEditable, calendarSpaces[j].color)); + } + } + } + } + if (eventArr.length == 0) { eventArr = null; } + return eventArr; +} + +function SortCalendarEvents(child1, child2) +{ + return (child1.properties["ia:fromDate"] - child2.properties["ia:fromDate"]); +} + +function AddWeekDayRow() +{ + var _currDay = _currentDateForWeekView.getDay(); + + var _arr = DaysArray(); + for (i=0; i<_arr.length; i++) + { + var _newDate = new Date(_currentDateForWeekView); + _newDate.setDate(_currentDateForWeekView.getDate() - _currDay + i); + days.push(_newDate.toDateString()); + if (i == 0) _startDateForWeekView = _newDate; + } +} + +function AddAllDayEventsRow() +{ + var _arr = DaysArray(); + var tempDate = new Date(_startDateForWeekView); + for (i=0; i<_arr.length; i++) + { + if (i != 0) tempDate.setDate(tempDate.getDate() + 1); + eventListAllDay.push(getAllDayEvents(tempDate)); + } +} + +function getGUIDFromNodeRef(nodeRef) +{ + var str = "" + nodeRef; + return str.substring(str.lastIndexOf("/")+1); +} + +function findNodeByNodeRef(nodeRef) +{ + var resultsArray = search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef)); + + if (resultsArray != null && resultsArray.length > 0) + { + return resultsArray[0]; + } + else + { + return null; + } +} + +var response; + +if (currentBaseSpace == null) { + response = "Parameters passed:
"; + response += "Current Date: " + dateString + "
"; + response += "Current Space: " + spaceRef + "
"; + response += "
Error: No Space found by this Ref"; +} else { + AddWeekDayRow(); + AddAllDayEventsRow(); + + var _arr = HoursArray(); + var _arrDay = DaysArray(); + var eventDays = new Array(); + for (i=0; i<_arr.length; i++) + { + eventDays = new Array(); + var tempDate = new Date(_startDateForWeekView); + for (j=0; j<_arrDay.length; j++) + { + if (j != 0) tempDate.setDate(tempDate.getDate() + 1); + + var _date = tempDate.getDate(); + var _month = tempDate.getMonth(); + var _year = tempDate.getFullYear(); + + eventDays.push(new eventType(getDayEvents(tempDate, _arr[i]), new Date(tempDate))); + } + eventList.push(new eventType(eventDays, _arr[i])); + } + + var _lastDate = new Date(_startDateForWeekView); + _lastDate.setDate(_lastDate.getDate() + 6); + model.dayCaption = _startDateForWeekView.toDateString() + " to " + _lastDate.toDateString(); +} + +//model.result = response; +model.daysArray = days; +model.eventList = eventList; +model.eventListAllDay = eventListAllDay; diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/SaveCalendarEvent.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/calendar/SaveCalendarEvent.get.desc.xml new file mode 100644 index 0000000000..54cce6a8f2 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/SaveCalendarEvent.get.desc.xml @@ -0,0 +1,8 @@ + + Save Calendar Event + Save Calendar Event + /calendar/SaveCalendarEvent?what={whatEvent}&where={whereEvent}&desc={descriptionEvent}&color={colorEvent}&fd={fromDate}&ft={fromTime}&td={toDate}&tt={toTime}&e={eventId}&d={toDelete}&s={spaceRef} + extension + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/SaveCalendarEvent.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/calendar/SaveCalendarEvent.get.html.ftl new file mode 100644 index 0000000000..967faeb995 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/SaveCalendarEvent.get.html.ftl @@ -0,0 +1 @@ +${result} \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/SaveCalendarEvent.get.js b/config/alfresco/templates/webscripts/org/alfresco/calendar/SaveCalendarEvent.get.js new file mode 100644 index 0000000000..2f16b21a4e --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/SaveCalendarEvent.get.js @@ -0,0 +1,103 @@ +var now = new Date(); +var day = now.getDay(); +var month = now.getMonth(); +var year = now.getYear(); +var hour = now.getHours(); +var minute = now.getMinutes(); +var second = now.getSeconds(); + +var stamp = day + month + year + hour.toString() + minute + second; +logger.log("DATE: " + args.fd + " " + args.ft); +var fromDateString = args.fd + " " + args.ft; +var fromDateDate = new Date(fromDateString); + +var toDateString = args.td + " " + args.tt; +var toDateDate = new Date(toDateString); + +var content = "What: " + args.what + "
"; +content += "When: " + args.fd + " " + args.ft + " to " + args.td + " " + args.tt + "
"; +content += "Where: " + args.where + "
"; +content += "Description: " + args.desc + "
"; +content += "Color: " + args.color; + +var fileNode = null; +var eventId = args.e; +var toDelete = args.d; + +var spaceRef = args.s; +var nodeWhereToCreate = findNodeByNodeRef(spaceRef); + +var response; + +if (nodeWhereToCreate != null) +{ + var newFolder = nodeWhereToCreate.childByNamePath("CalEvents"); + if (newFolder == null) + nodeWhereToCreate = nodeWhereToCreate.createFolder("CalEvents"); + else + nodeWhereToCreate = newFolder; + + if (eventId == null) + { + fileNode = nodeWhereToCreate.createNode(stamp + ".ics", "ia:calendarEvent"); + saveNodeDetails(); + } + else + { + fileNode = search.findNode(eventId); + if (toDelete == 'true') + { + var status = fileNode.remove(); + if (status) + response = "DELETED"; + else + response = "NOT DELETED"; + } + else + { + saveNodeDetails(); + } + } +} +else +{ + response = "SPACE not found with Ref " + spaceRef; +} + +model.result = response; + + +function saveNodeDetails() +{ + fileNode.properties["ia:whatEvent"] = args.what; + fileNode.properties["ia:fromDate"] = fromDateDate; + fileNode.properties["ia:toDate"] = toDateDate; + fileNode.properties["ia:whereEvent"] = args.where; + fileNode.properties["ia:descriptionEvent"] = args.desc; + fileNode.properties["ia:colorEvent"] = args.color; + + fileNode.save(); + fileNode.content = content; + + response = fileNode.content; +} + +function getGUIDFromNodeRef(nodeRef) +{ + var str = "" + nodeRef; + return str.substring(str.lastIndexOf("/")+1); +} + +function findNodeByNodeRef(nodeRef) +{ + var resultsArray = search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef)); + + if (resultsArray != null && resultsArray.length > 0) + { + return resultsArray[0]; + } + else + { + return null; + } +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarDelete.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarDelete.post.desc.xml new file mode 100644 index 0000000000..8a57a054e1 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarDelete.post.desc.xml @@ -0,0 +1,6 @@ + +Calendar Subscriptions +Calendar Subscriptions +/calendar/calendarRemove +user + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarDelete.post.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarDelete.post.html.ftl new file mode 100644 index 0000000000..27c7e90446 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarDelete.post.html.ftl @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarDelete.post.js b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarDelete.post.js new file mode 100644 index 0000000000..88401a3577 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarDelete.post.js @@ -0,0 +1,33 @@ +function getGUIDFromNodeRef(nodeRef) { + var str = "" + nodeRef; + if (str.length > 24) { + return str.substring(24); + } else { + return ""; + } +} + +function findNodeByNodeRef(nodeRef) { + var resultsArray = search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef)); + if (resultsArray != null && resultsArray.length > 0) { + return resultsArray[0]; + } else { + return null; + } +} + +var spaceRef = args.ref; +var space = findNodeByNodeRef(spaceRef); + +// Resolve the calendar reference +var calendar = findNodeByNodeRef(args.calendar); +if (calendar != null) { + space.removeAssociation(calendar, "ia:subscribedCalendarList"); + space.save(); +} + +var calendars = space.assocs["ia:subscribedCalendarList"]; +if (calendars == null) { + calendars = new Array(); +} +model.resultset = calendars; diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarEvents.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarEvents.get.desc.xml new file mode 100644 index 0000000000..85b642e0b3 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarEvents.get.desc.xml @@ -0,0 +1,6 @@ + +Calendar Events +Calendar Events +/calendar/getCalendarEvents +user + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarEvents.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarEvents.get.html.ftl new file mode 100644 index 0000000000..d123309079 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarEvents.get.html.ftl @@ -0,0 +1,20 @@ + + + + + + + + +
diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarEvents.get.js b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarEvents.get.js new file mode 100644 index 0000000000..faf4165081 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarEvents.get.js @@ -0,0 +1,87 @@ +function getGUIDFromNodeRef(nodeRef) { + var str = "" + nodeRef; + if (str.length > 24) { + return str.substring(24); + } else { + return ""; + } +} + +function findNodeByNodeRef(nodeRef) { + var resultsArray = search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef)); + if (resultsArray != null && resultsArray.length > 0) { + return resultsArray[0]; + } else { + return null; + } +} + +var spaceRef = args.ref; +var calendar = findNodeByNodeRef(spaceRef); + +function formatANSI(datestr) { + var tmp = datestr.split("/"); + var d = new Date(); + d.setFullYear(tmp[0]); + d.setMonth(tmp[1]-1); + d.setDate(tmp[2]); + return d; +} + +function Interval(start, end) { + this.start = start; + this.end = end; +}; + +Interval.prototype.overlaps = function(interval) { + // take the interval with the early start time as the one to compare against + var x, y; + if (this.start.getTime() < interval.start.getTime()) { + x = this; y = interval; + } else { + x = interval; y = this; + } + var time = y.start.getTime(); + return (x.start.getTime() <= time) && (time < this.end.getTime()); +}; + +function isLeap(year) { + return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)); +} + +var monthToDays = [31,28,31,30,31,30,31,31,30,31,30,31]; + +if (isLeap(args.year)) { + monthToDays[1] = 29; // one extra day in February +} + +var fromDate = args.year + "/0" + args.month + "/01"; +var from = formatANSI(fromDate); +var toDate = args.year + "/0" + args.month + "/" + monthToDays[args.month - 1]; +var to = formatANSI(toDate); +var time = new Interval(from, to); + +var selectedDates = new Array(); +var events = calendar.children; + +for(var i=0; i < events.length; i++) { + var event = events[i]; + var startdate = new Date(event.properties["ia:fromDate"]); + var enddate = new Date(event.properties["ia:toDate"]); + var interval = new Interval(startdate, enddate); + if (interval.overlaps(time)) { + var key = (interval.start.getMonth()+1) + "/" + interval.start.getDate(); + if (selectedDates.indexOf(key) < 0) { + selectedDates.push(key); + } + } +} + +model.dates = selectedDates; + +// These are only used for the html view +model.month = args.month; +model.year = args.year; + + + diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarEvents.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarEvents.get.json.ftl new file mode 100644 index 0000000000..a154d98d27 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarEvents.get.json.ftl @@ -0,0 +1,3 @@ +{ +results: [<#list dates as d>"${d}"<#if d_has_next>,] +} \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarInit.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarInit.get.desc.xml new file mode 100644 index 0000000000..9762a9d908 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarInit.get.desc.xml @@ -0,0 +1,6 @@ + +Calendar Subscriptions +Calendar Subscriptions +/calendar/calendarInit +user + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarInit.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarInit.get.html.ftl new file mode 100644 index 0000000000..0d9925de4e --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarInit.get.html.ftl @@ -0,0 +1,54 @@ +
+ + + + + +
+
 
+
+Select a color +
+
+<#-- This MUST be present --> +
+ + + + + + + + + + + + + + + +
Available Calendars Subscribed Calendars
+ + + + +
+<#-- Display the list of available calendars--> + +
+
+ + + +<#-- Display the list of subscribed calendars--> + +
 
+ \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarInit.get.js b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarInit.get.js new file mode 100644 index 0000000000..af5893c02a --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarInit.get.js @@ -0,0 +1,56 @@ +function getGUIDFromNodeRef(nodeRef) { + var str = "" + nodeRef; + if (str.length > 24) { + return str.substring(24); + } else { + return ""; + } +} + +function findNodeByNodeRef(nodeRef) { + var resultsArray = search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef)); + if (resultsArray != null && resultsArray.length > 0) { + return resultsArray[0]; + } else { + return null; + } +} + +var spaceRef = args.ref; +var calendar = findNodeByNodeRef(spaceRef); + +var color = calendar.properties["ia:colorEventDefault"]; +if (color == null || color.length == 0) { + color = "#FF0000"; // default +} +model.color = color; + +// Get the list of calendars the user is subscribed to +var subscriptions = calendar.assocs["ia:subscribedCalendarList"] +if (subscriptions == null) { + subscriptions = new Array(); +} +model.subscriptions = subscriptions; + +// perform search +var nodes = search.luceneSearch('TYPE:\"{com.infoaxon.alfresco.calendar}calendar\"'); + +/** +var filtered = new Array(); + if (nodes.length > 0) { + var re = new RegExp(args.q,"i"); + var j = 0; + for(i=0; i < nodes.length; i++) { + var n = nodes[i]; + if (re.test(n.parent.name)) { + filtered[j] = n; + ++j; + } + } + } +**/ + +model.available = nodes; + + + diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarSub.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarSub.post.desc.xml new file mode 100644 index 0000000000..dce79e311d --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarSub.post.desc.xml @@ -0,0 +1,6 @@ + +Calendar Subscriptions +Calendar Subscriptions +/calendar/calendarSubscriptions +user + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarSub.post.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarSub.post.html.ftl new file mode 100644 index 0000000000..27c7e90446 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarSub.post.html.ftl @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarSub.post.js b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarSub.post.js new file mode 100644 index 0000000000..9633572aa5 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/calendarSub.post.js @@ -0,0 +1,29 @@ +function getGUIDFromNodeRef(nodeRef) { + var str = "" + nodeRef; + if (str.length > 24) { + return str.substring(24); + } else { + return ""; + } +} + +function findNodeByNodeRef(nodeRef) { + var resultsArray = search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef)); + if (resultsArray != null && resultsArray.length > 0) { + return resultsArray[0]; + } else { + return null; + } +} + +var spaceRef = args.ref; +var space = findNodeByNodeRef(spaceRef); +// Resolve the calendar reference +var calendar = findNodeByNodeRef(args.calendar); +if (calendar != null) { + space.createAssociation(calendar, "ia:subscribedCalendarList"); + space.save(); +} + +var calendars = space.assocs["ia:subscribedCalendarList"]; +model.resultset = calendars; diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/color.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/calendar/color.get.desc.xml new file mode 100644 index 0000000000..441ebf473b --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/color.get.desc.xml @@ -0,0 +1,6 @@ + +Calendar Subscriptions +Calendar Subscriptions +/calendar/getColor +user + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/color.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/calendar/color.get.html.ftl new file mode 100644 index 0000000000..58e0854d3b --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/color.get.html.ftl @@ -0,0 +1,3 @@ +${color} + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/color.get.js b/config/alfresco/templates/webscripts/org/alfresco/calendar/color.get.js new file mode 100644 index 0000000000..8348a686fe --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/color.get.js @@ -0,0 +1,31 @@ +function getGUIDFromNodeRef(nodeRef) { + var str = "" + nodeRef; + if (str.length > 24) { + return str.substring(24); + } else { + return ""; + } +} + +function findNodeByNodeRef(nodeRef) { + var resultsArray = search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef)); + if (resultsArray != null && resultsArray.length > 0) { + return resultsArray[0]; + } else { + return null; + } +} + +var spaceRef = args.ref; +var color = null; +var calendar = findNodeByNodeRef(spaceRef); + +if (calendar != null) { + color = calendar.properties["ia:colorEventDefault"]; +} + +if (color == null || color.length == 0) { + color = "#FF0000"; // red +} + +model.color = color; diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/color.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/calendar/color.post.desc.xml new file mode 100644 index 0000000000..d4c79a020d --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/color.post.desc.xml @@ -0,0 +1,6 @@ + +Calendar Subscriptions +Calendar Subscriptions +/calendar/setColor +user + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/color.post.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/calendar/color.post.html.ftl new file mode 100644 index 0000000000..7014099827 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/color.post.html.ftl @@ -0,0 +1,2 @@ +Done. + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/calendar/color.post.js b/config/alfresco/templates/webscripts/org/alfresco/calendar/color.post.js new file mode 100644 index 0000000000..0f01b724b6 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/calendar/color.post.js @@ -0,0 +1,27 @@ +function getGUIDFromNodeRef(nodeRef) { + var str = "" + nodeRef; + if (str.length > 24) { + return str.substring(24); + } else { + return ""; + } +} + +function findNodeByNodeRef(nodeRef) { + var resultsArray = search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef)); + if (resultsArray != null && resultsArray.length > 0) { + return resultsArray[0]; + } else { + return null; + } +} +logger.log("COLOR: " + args.color + " REF: " + args.ref); +var spaceRef = args.ref; +var calendar = findNodeByNodeRef(spaceRef); + +if (calendar != null) { + calendar.properties["ia:colorEventDefault"] = args.color; + calendar.save(); +} + + diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSpace.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSpace.get.desc.xml new file mode 100644 index 0000000000..622d5666ea --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSpace.get.desc.xml @@ -0,0 +1,8 @@ + + Blog Custom View + Collaboration Blog Space view + /collaboration/blogSpace?nodeRef={noderef} + + user + required + diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSpace.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSpace.get.html.ftl new file mode 100644 index 0000000000..5a5e1d80c3 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSpace.get.html.ftl @@ -0,0 +1,176 @@ +
+ +<#if blogSpace.actionResult != ""> +
${blogSpace.actionResult}
+ + +
+ Articles pending publishing (${blogSpace.pending?size}) +
+ +
+ + + + + + + +
+ + + + + +
+ + + + + + + + + +<#assign rowNum = 0> +<#list blogSpace.pending as article> + <#assign n = article.node> + <#assign p = article.person> + <#assign rowNum = rowNum + 1> + + + + + + + + +
 NameCreated onCreated byActions
${n.name}${n.properties["cm:created"]?datetime}${p.properties["cm:firstName"]} ${p.properties["cm:lastName"]} + details + details +
+
+
+ +
+
+   +
+ +
+ Articles to be updated (${blogSpace.updates?size}) +
+ +
+ + + + + + + +
+ + + + +
+ + + + + + + + + +<#assign rowNum = 0> +<#list blogSpace.updates as article> + <#assign n = article.node> + <#assign p = article.person> + <#assign rowNum = rowNum + 1> + + + + + + + + +
 NamePublished onModified onActions
${n.name}${n.properties["blg:lastUpdate"]?datetime}${n.properties["cm:modified"]?datetime} + + + details +
+
+
+ +
+
+   +
+ +
+ + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSpace.get.js b/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSpace.get.js new file mode 100644 index 0000000000..4e88ccf4e9 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSpace.get.js @@ -0,0 +1,100 @@ +/* + * blogSpace + * + * Inputs: + * mandatory: nodeRef = parent space nodeRef + * optional: n = nodeId for document to action against + * a = action + * "p" = publish + * "u" = update + * "r" = remove + * + * Outputs: blogSpace - object containing node arrays of articles pending and to be updated + */ +var actionResult = parseArgs(args["n"], args["a"]); +model.blogSpace = main(args["nodeRef"], actionResult); + +function parseArgs(nodeId, action) +{ + var result = ""; + if ((nodeId != null) && (action != null)) + { + var blog = actions.create("blog-post"); + + var node = search.findNode(nodeId); + if (node != null) + { + var blogAction = ""; + var isPublished = false; + if ((node.hasAspect("blg:blogPost")) && (node.properties["blg:published"] == true)) + { + isPublished = true; + } + + switch (action) + { + case "p": + blogAction = (isPublished ? "" : "post"); + break; + case "u": + blogAction = (isPublished ? "update" : ""); + break; + case "r": + blogAction = (isPublished ? "remove" : ""); + break; + } + + if (blogAction != "") + { + blog.parameters.action = blogAction; + blog.execute(node); + result = blog.parameters["result"]; + } + } + } + return result; +} + +function main(nodeRef, actionResult) +{ + var pending = new Array(), + updates = new Array(); + + var article = {}; + var person; + + var space = search.findNode(nodeRef); + + if (space != null) + { + for each(node in space.children) + { + person = people.getPerson(node.properties["cm:creator"]); + article = + { + "node": node, + "person": person + }; + + if ((node.hasAspect("blg:blogPost")) && (node.properties["blg:published"] == true)) + { + if (node.properties["cm:modified"] - node.properties["blg:lastUpdate"] > 5000) + { + updates.push(article); + } + } + else + { + pending.push(article); + } + } + } + + var blogSpace = + { + "actionResult": actionResult, + "pending": pending, + "updates": updates + }; + return blogSpace; +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSummary.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSummary.get.desc.xml new file mode 100644 index 0000000000..a7e8d792ee --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSummary.get.desc.xml @@ -0,0 +1,8 @@ + + Blog Summary + Collaboration Blog Summary + /collaboration/blogSummary?nodeRef={noderef} + + user + required + diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSummary.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSummary.get.html.ftl new file mode 100644 index 0000000000..910fb2f711 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSummary.get.html.ftl @@ -0,0 +1,2 @@ +${blogSummary.numUpdates} articles need updating
+${blogSummary.numPending} articles pending \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSummary.get.js b/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSummary.get.js new file mode 100644 index 0000000000..399f7772b9 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/blogSummary.get.js @@ -0,0 +1,53 @@ +/* + * blogSummary + * + * Inputs: + * nodeRef = blog space nodeRef + * + * Outputs: + * blogSummary - object containing + * numUpdates - number of articles updated since being published + * numPending - number of unpublished articles + */ +model.blogSummary = main(args["nodeRef"]); + +function main(nodeRef) +{ + var numUpdates = 0, + numPending = 0; + + if (nodeRef != null) + { + var space = search.findNode(nodeRef); + + if (space != null) + { + // generate lucene PATH to get all child documents + var path = space.qnamePath + "//*"; + var nodes = search.luceneSearch("+PATH:\"" + path + "\"" + + " +(@cm\\:content.mimetype:\"text/plain\" OR @cm\\:content.mimetype:\"text/html\")"); + + for each(node in nodes) + { + if ((node.hasAspect("blg:blogPost")) && (node.properties["blg:published"] == true)) + { + if (node.properties["cm:modified"] - node.properties["blg:lastUpdate"] > 5000) + { + ++numUpdates; + } + } + else + { + ++numPending; + } + } + } + } + + var blogSummary = + { + "numUpdates": numUpdates, + "numPending": numPending + }; + return blogSummary; +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/calendar.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/collaboration/calendar.get.desc.xml new file mode 100644 index 0000000000..341f5ddf3a --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/calendar.get.desc.xml @@ -0,0 +1,8 @@ + + Calendar View + Collaboration Calendar Space view + /collaboration/calendar?nodeRef={noderef} + + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/calendar.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/collaboration/calendar.get.html.ftl new file mode 100644 index 0000000000..8b94be7426 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/calendar.get.html.ftl @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+
+
+ + + + + + +
+ + + + + + + + +
+ +
+
+
+ +
+ + + +
+
+
+ + + + +
+ + + + + + + +
+ +
+
+
+
+
+ + + +
+
+
+ + + + +
+ + + + + + + +
+ +
+
+
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Enter Event Information
What *
When * + + + to + + +
Where
Description
Color
+
+ + +
+ + +
+
+
diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/calendarSummary.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/collaboration/calendarSummary.get.desc.xml new file mode 100644 index 0000000000..b8b56c5786 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/calendarSummary.get.desc.xml @@ -0,0 +1,8 @@ + + Calendar Summary + Collaboration Calendar Summary + /collaboration/calendarSummary?nodeRef={noderef} + + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/calendarSummary.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/collaboration/calendarSummary.get.html.ftl new file mode 100644 index 0000000000..c84ec9782f --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/calendarSummary.get.html.ftl @@ -0,0 +1,2 @@ +${calendarSummary.thisWeek} events this week
+${calendarSummary.nextWeek} events next week \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/calendarSummary.get.js b/config/alfresco/templates/webscripts/org/alfresco/collaboration/calendarSummary.get.js new file mode 100644 index 0000000000..9c769b1346 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/calendarSummary.get.js @@ -0,0 +1,56 @@ +/* + * calendarSummary + * + * Inputs: + * nodeRef = Calendar space nodeRef + * + * Outputs: + * calendarSummary - object containing + * eventsthis - Number of events occuring this + * eventsTomorrow - Number of events occuring tomorrow + */ +model.calendarSummary = main(args["nodeRef"]); + +function main(nodeRef) +{ + var thisWeek = 0, + nextWeek = 0; + + if (nodeRef != null) + { + var calSpace = search.findNode(nodeRef); + if (calSpace != null) + { + // generate lucene PATH to calendar events + var path = calSpace.qnamePath + "/cm:CalEvents/*"; + + // find the events scheduled for this week + var fromDate = new Date(); + // go back to previous Sunday + fromDate.setDate(fromDate.getDate() - fromDate.getDay()); + var fromQuery = fromDate.getFullYear() + "\\-" + (fromDate.getMonth()+1) + "\\-" + fromDate.getDate(); + var toDate = new Date(); + toDate.setDate(fromDate.getDate() + 7); + var toQuery = toDate.getFullYear() + "\\-" + (toDate.getMonth()+1) + "\\-" + toDate.getDate(); + var events = search.luceneSearch("+PATH:\"" + path + '"' + + " +@ia\\:fromDate:[" + fromQuery + "T00\\:00\\:00 TO " + toQuery + "T23\\:59\\:59]"); + thisWeek = events.length; + + // increment to and from dates to cover next week + fromDate.setDate(toDate.getDate()); + fromQuery = fromDate.getFullYear() + "\\-" + (fromDate.getMonth()+1) + "\\-" + fromDate.getDate(); + toDate.setDate(toDate.getDate() + 7); + toQuery = toDate.getFullYear() + "\\-" + (toDate.getMonth()+1) + "\\-" + toDate.getDate(); + events = search.luceneSearch("+PATH:\"" + path + '"' + + " +@ia\\:fromDate:[" + fromQuery + "T00\\:00\\:00 TO " + toQuery + "T23\\:59\\:59]"); + nextWeek = events.length; + } + } + + var calendarSummary = + { + "thisWeek": thisWeek, + "nextWeek": nextWeek + }; + return calendarSummary +} \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/colleaguePresence.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/collaboration/colleaguePresence.get.desc.xml new file mode 100644 index 0000000000..685d01ae97 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/colleaguePresence.get.desc.xml @@ -0,0 +1,8 @@ + + Colleague Presence Custom View + Collaboration Colleague Presence view + /collaboration/colleaguePresence?nodeRef={noderef} + + user + required + diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/colleaguePresence.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/collaboration/colleaguePresence.get.html.ftl new file mode 100644 index 0000000000..d02da61253 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/colleaguePresence.get.html.ftl @@ -0,0 +1,119 @@ + + +
+ + Refresh + Colleagues Online + +
+
+
+
+
+<#list colleaguePresence.colleagues?keys as key> + <#assign c = colleaguePresence.colleagues[key]> +
rel="self"> +
+ <#if (c.assocs["cm:avatar"]?exists)> + <#assign avatarURL = c.assocs["cm:avatar"][0].url> + <#else> + <#assign avatarURL = "images/icons/default_avatar.png"> + + avatar +
+
+
+
+
${c.properties["firstName"]!""} ${c.properties["lastName"]!""}
+
${c.properties["jobtitle"]!""}
+
${c.properties["location"]!""}
+
+
+ +
+
+
+   +
+ + diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/colleaguePresence.get.js b/config/alfresco/templates/webscripts/org/alfresco/collaboration/colleaguePresence.get.js new file mode 100644 index 0000000000..9099aceec3 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/colleaguePresence.get.js @@ -0,0 +1,68 @@ +/* + * colleaguePresence + * + * Inputs: + * mandatory: nodeRef = parent space nodeRef + * + * Outputs: colleaguePresence - object containing presence data model + */ +model.colleaguePresence = main(args["nodeRef"]); + +function main(nodeRef) +{ + var space = search.findNode(nodeRef); + var colleagues = {}; + + if (space != null) + { + colleagues = parsePermissions(space); + } + + var colleaguePresence = + { + "colleagues": colleagues, + "self": person + }; + return colleaguePresence; +} + +function parsePermissions(space) +{ + var tokens, user, group; + var userHash = {}; + + try + { + for each(perm in space.permissions) + { + tokens = perm.split(";"); + if (tokens[0] == "ALLOWED") + { + if (("AllCollaboratorContributorCoordinatorEditor").indexOf(tokens[2]) != -1) + { + user = people.getPerson(tokens[1]); + if (user != null) + { + userHash[user.name] = user; + } + else + { + group = people.getGroup(tokens[1]); + if (group != null) + { + for each(user in people.getMembers(group)) + { + userHash[user.name] = user; + } + } + } + } + } + } + } + catch (e) + { + } + + return userHash; +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/docLibrary.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/collaboration/docLibrary.get.desc.xml new file mode 100644 index 0000000000..da096d7054 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/docLibrary.get.desc.xml @@ -0,0 +1,8 @@ + + DocLib Custom View + Collaboration Document Library view + /collaboration/docLibrary?nodeRef={noderef} + + user + required + diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/docLibrary.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/collaboration/docLibrary.get.html.ftl new file mode 100644 index 0000000000..1d8ba8a148 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/docLibrary.get.html.ftl @@ -0,0 +1,120 @@ +<#assign doclib = companyhome.nodeByReference[args["nodeRef"]]> +<#assign datetimeformat="EEE, dd MMM yyyy HH:mm"> +
+ +
+ Recent Changes +
+ + + + + + + +
+ +
+ + <#assign count=0> + <#list doclib.childrenByXPath[".//*[subtypeOf('cm:content')]"] as c> + <#assign count=count+1> + <#assign curl=url.serviceContext + c.serviceUrl> +
+
+ ${c.name?html} +
+
+
+
+ +
+ ${c.name?html} +
+
+ +
+
+ Modified:   + Modified By:  + Size:  +
+
+
+ + +
+ +
+ +
+   +
+
+ + diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/docSummary.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/collaboration/docSummary.get.desc.xml new file mode 100644 index 0000000000..ea534b598a --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/docSummary.get.desc.xml @@ -0,0 +1,8 @@ + + Doc Summary + Collaboration Doc Summary + /collaboration/docSummary?nodeRef={noderef} + + user + required + diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/docSummary.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/collaboration/docSummary.get.html.ftl new file mode 100644 index 0000000000..7f86a7021c --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/docSummary.get.html.ftl @@ -0,0 +1,2 @@ +${docSummary.numNew} added in the last 7 days
+${docSummary.numModified} modified in the last 7 days \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/docSummary.get.js b/config/alfresco/templates/webscripts/org/alfresco/collaboration/docSummary.get.js new file mode 100644 index 0000000000..a2b2aa2778 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/docSummary.get.js @@ -0,0 +1,59 @@ +/* + * docSummary + * + * Inputs: + * nodeRef = doc space nodeRef + * + * Outputs: + * docSummary - object containing + * numNew - number new documents added in the last 7 days + * numModified - number of documents modified in the last 7 days + */ +model.docSummary = main(args["nodeRef"]); + +function main(nodeRef) +{ + var numNew = 0, + numModified = 0; + + if (nodeRef != null) + { + var space = search.findNode(nodeRef); + + if (space != null) + { + // generate lucene PATH to get all child documents + var path = space.qnamePath + "//*"; + + var date = new Date(); + var toQuery = date.getFullYear() + "\\-" + (date.getMonth()+1) + "\\-" + date.getDate(); + date.setDate(date.getDate() - 7); + var fromQuery = date.getFullYear() + "\\-" + (date.getMonth()+1) + "\\-" + date.getDate(); + + // documents created in the last 7 days + var docs = search.luceneSearch("+PATH:\"" + path + "\"" + + " +@cm\\:created:[" + fromQuery + "T00\\:00\\:00 TO " + toQuery + "T23\\:59\\:59]"); + numNew = docs.length; + + // documents modified in the last 7 days + docs = search.luceneSearch("+PATH:\"" + path + "\"" + + " +@cm\\:modified:[" + fromQuery + "T00\\:00\\:00 TO " + toQuery + "T23\\:59\\:59]"); + + numModified = 0; + for each(doc in docs) + { + if (doc.properties["cm:modified"] - doc.properties["cm:created"] > 1000) + { + ++numModified; + } + } + } + } + + var docSummary = + { + "numNew": numNew, + "numModified": numModified + }; + return docSummary; +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/emailSummary.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/collaboration/emailSummary.get.desc.xml new file mode 100644 index 0000000000..63aeca28ea --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/emailSummary.get.desc.xml @@ -0,0 +1,8 @@ + + Email Summary + Collaboration Email Summary + /collaboration/emailSummary?nodeRef={noderef} + + user + required + diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/emailSummary.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/collaboration/emailSummary.get.html.ftl new file mode 100644 index 0000000000..66b7e731f0 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/emailSummary.get.html.ftl @@ -0,0 +1,2 @@ +${emailSummary.numToday} e-mails have arrived today
+${emailSummary.numWeek} e-mails in the last 7 days \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/emailSummary.get.js b/config/alfresco/templates/webscripts/org/alfresco/collaboration/emailSummary.get.js new file mode 100644 index 0000000000..be3008fa9e --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/emailSummary.get.js @@ -0,0 +1,54 @@ +/* + * emailSummary + * + * Inputs: + * nodeRef = email space nodeRef + * + * Outputs: + * emailSummary - object containing + * numToday - number of articles updated since being published + * numWeek - number of unpublished articles + */ +model.emailSummary = main(args["nodeRef"]); + +function main(nodeRef) +{ + var numToday = 0, + numWeek = 0; + + if (nodeRef != null) + { + var space = search.findNode(nodeRef); + + if (space != null) + { + // generate lucene PATH to get all child documents + var path = space.qnamePath + "//*"; + + var date = new Date(); + var toQuery = date.getFullYear() + "\\-" + (date.getMonth()+1) + "\\-" + date.getDate(); + var fromQuery = toQuery; + + // emails today + var docs = search.luceneSearch("+PATH:\"" + path + "\"" + + " +@cm\\:created:[" + fromQuery + "T00\\:00\\:00 TO " + toQuery + "T23\\:59\\:59]"); + numToday = docs.length; + + date.setDate(date.getDate() - 7); + fromQuery = date.getFullYear() + "\\-" + (date.getMonth()+1) + "\\-" + date.getDate(); + + // documents modified in the last 7 days + docs = search.luceneSearch("+PATH:\"" + path + "\"" + + " +@cm\\:modified:[" + fromQuery + "T00\\:00\\:00 TO " + toQuery + "T23\\:59\\:59]"); + + numWeek = docs.length; + } + } + + var emailSummary = + { + "numToday": numToday, + "numWeek": numWeek + }; + return emailSummary; +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/forumSummary.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/collaboration/forumSummary.get.desc.xml new file mode 100644 index 0000000000..ac1de5ae78 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/forumSummary.get.desc.xml @@ -0,0 +1,8 @@ + + Forum Summary + Collaboration Forum Summary + /collaboration/forumSummary?nodeRef={noderef} + + user + required + diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/forumSummary.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/collaboration/forumSummary.get.html.ftl new file mode 100644 index 0000000000..f95d1fa96c --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/forumSummary.get.html.ftl @@ -0,0 +1,2 @@ +${forumSummary.numPosts} posts in the last 7 days
+${forumSummary.numTopics} new topics in the last 7 days \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/forumSummary.get.js b/config/alfresco/templates/webscripts/org/alfresco/collaboration/forumSummary.get.js new file mode 100644 index 0000000000..2adf332711 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/forumSummary.get.js @@ -0,0 +1,59 @@ +/* + * forumSummary + * + * Inputs: + * nodeRef = forum space nodeRef + * + * Outputs: + * forumSummary - object containing + * numPosts - posts in last 7 days + * numTopics - new topics in last 7 days + */ +model.forumSummary = main(args["nodeRef"]); + +function main(nodeRef) +{ + var numPosts = 0, + numTopics = 0; + + if (nodeRef != null) + { + var space = search.findNode(nodeRef); + + if (space != null) + { + // generate lucene PATH to get forums + var path = space.qnamePath + "//*"; + + var date = new Date(); + var toQuery = date.getFullYear() + "\\-" + (date.getMonth()+1) + "\\-" + date.getDate(); + date.setDate(date.getDate() - 7); + var fromQuery = date.getFullYear() + "\\-" + (date.getMonth()+1) + "\\-" + date.getDate(); + + // posts created in the last 7 days + var docs = search.luceneSearch("+PATH:\"" + path + "\"" + + " +TYPE:\"{http://www.alfresco.org/model/forum/1.0}post\"" + + " +@cm\\:created:[" + fromQuery + "T00\\:00\\:00 TO " + toQuery + "T23\\:59\\:59]"); + numPosts = docs.length; + + // topics created in the last 7 days + docs = search.luceneSearch("+PATH:\"" + path + "\"" + + " +TYPE:\"{http://www.alfresco.org/model/forum/1.0}topic\"" + + " +@cm\\:created:[" + fromQuery + "T00\\:00\\:00 TO " + toQuery + "T23\\:59\\:59]"); + numTopics = docs.length; + } + } + + var forumSummary = + { + "numPosts": numPosts, + "numTopics": numTopics + }; + return forumSummary; +} + +// var query = "TYPE:\"{http://www.alfresco.org/model/content/1.0}person\""; + + +// {http://www.alfresco.org/model/forum/1.0}topic +// {http://www.alfresco.org/model/forum/1.0}post \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallery.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallery.get.desc.xml new file mode 100644 index 0000000000..b181918020 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallery.get.desc.xml @@ -0,0 +1,14 @@ + + + + Gallery Sample Data + Returns data used to populate the Flex gallery sample. + + + /collaboration/gallery/{noderef} + + extension + user + required + + diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallery.get.js b/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallery.get.js new file mode 100644 index 0000000000..f3f51e67ff --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallery.get.js @@ -0,0 +1,9 @@ + +var gallery = search.findNode(url.extension); +if (gallery == undefined || gallery.isContainer == false) +{ + status.code = 404; + status.message = "Gallery " + url.extension + " not found."; + status.redirect = true; + } + model.gallery = gallery; \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallery.get.xml.ftl b/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallery.get.xml.ftl new file mode 100644 index 0000000000..587bce0468 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallery.get.xml.ftl @@ -0,0 +1,21 @@ + + + ${gallery.name} + <#list gallery.children as image> + <#if image.isDocument> + + ${absurl(url.context)}${image.url} + <#if image.properties["cm:title"]?exists> + ${image.properties["cm:title"]} + <#else> + + </#if> + <#if image.properties["cm:description"]?exists> + <description>${image.properties["cm:description"]}</description> + <#else> + <description/> + </#if> + </image> + </#if> + </#list> +</gallery> diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallerySummary.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallerySummary.get.desc.xml new file mode 100644 index 0000000000..d54f89017f --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallerySummary.get.desc.xml @@ -0,0 +1,8 @@ +<webscript> + <shortname>Gallery Summary</shortname> + <description>Collaboration Gallery Summary</description> + <url>/collaboration/gallerySummary?nodeRef={noderef}</url> + <format default="html"/> + <authentication>user</authentication> + <transaction>required</transaction> +</webscript> diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallerySummary.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallerySummary.get.html.ftl new file mode 100644 index 0000000000..bfdecc2224 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallerySummary.get.html.ftl @@ -0,0 +1,2 @@ +${gallerySummary.numNew} added in the last 7 days<br> +${gallerySummary.numTotal} images in this gallery \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallerySummary.get.js b/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallerySummary.get.js new file mode 100644 index 0000000000..dfef6f491b --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/gallerySummary.get.js @@ -0,0 +1,50 @@ +/* + * gallerySummary + * + * Inputs: + * nodeRef = gallery space nodeRef + * + * Outputs: + * gallerySummary - object containing + * numNew - number of new images in the last 7 days + * numTotal - total number of images + */ +model.gallerySummary = main(args["nodeRef"]); + +function main(nodeRef) +{ + var numNew = 0, + numTotal = 0; + + if (nodeRef != null) + { + var space = search.findNode(nodeRef); + + if (space != null) + { + // generate lucene PATH to all gallery images + var path = space.qnamePath + "//*"; + + var date = new Date(); + var toQuery = date.getFullYear() + "\\-" + (date.getMonth()+1) + "\\-" + date.getDate(); + date.setDate(date.getDate() - 7); + var fromQuery = date.getFullYear() + "\\-" + (date.getMonth()+1) + "\\-" + date.getDate(); + + // images added in the last 7 days + var images = search.luceneSearch("+PATH:\"" + path + "\"" + + " +@cm\\:created:[" + fromQuery + "T00\\:00\\:00 TO " + toQuery + "T23\\:59\\:59]"); + numNew = images.length; + + // total images + images = search.luceneSearch("+PATH:\"" + path + "\""); + numTotal = images.length; + } + } + + var gallerySummary = + { + "numNew": numNew, + "numTotal": numTotal + }; + return gallerySummary; +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/projectSpace.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/collaboration/projectSpace.get.desc.xml new file mode 100644 index 0000000000..2414bdd56f --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/projectSpace.get.desc.xml @@ -0,0 +1,8 @@ +<webscript> + <shortname>Project Space Custom View</shortname> + <description>Collaboration Project Space Space view</description> + <url>/collaboration/projectSpace?nodeRef={noderef}</url> + <format default="html"/> + <authentication>user</authentication> + <transaction>required</transaction> +</webscript> diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/projectSpace.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/collaboration/projectSpace.get.html.ftl new file mode 100644 index 0000000000..26c3967838 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/projectSpace.get.html.ftl @@ -0,0 +1,150 @@ +<script type="text/javascript" src="${url.context}/scripts/ajax/project_space.js"></script> + +<div class="collabHeader"> + <span> + <img id="refreshProjectSpace" src="${url.context}/images/icons/reset.gif" align="top" alt="Refresh"> + ${projectSpace.title} Summary + </span> +</div> +<div class="collabContainer"> + +<table width="100%" cellpadding="0" cellspacing="0"> + <tr valign="top"> + <td width="1" style="background-color:#cacfd3;"></td> + <td> + <table width="100%" cellpadding="8" cellspacing="0"> + <tr valign="top"> + <td> +<#assign panelCount = 0> +<#list projectSpace.subSpaces?keys?sort as key> + <#assign node = projectSpace.subSpaces[key]> + <#assign summary = node.properties["cm:summaryWebscript"]!""> + <div class="projectSpace"> + <span> + <a class="projectSpaceArrow" href="${url.context}${node.url}"><img src="${url.context}/images/parts/collab_arrow.png" height="16" width="16" alt=">"></a> + <div class="projectSpaceIcon"> + <a href="${url.context}${node.url}"><img src="${url.context}${node.icon64}" height="64" width="64"></a> + </div> + <div><a class="projectSpaceTitle" href="${url.context}${node.url}">${node.name}</a></div> + <div class="projectSpaceSummary" rel="<#if summary != "">${url.context}${summary}?nodeRef=${node.nodeRef}</#if>"></div> + </span> + </div> + <#assign panelCount = panelCount + 1> + <#if (panelCount % 2 = 0)> + <div style="clear:left;"></div> + </#if> +</#list> + </td> + </tr> + </table> + </td> + <td width="1" style="background-color:#cacfd3;"></td> + </tr> +</table> + +</div> +<div class="collabFooter"> + <span> </span> +</div> + +<style> +/* Main Container elements */ +#projectContainer { + width: 100%; +} + +#projectContainer a img { + border: none; +} + +#projectSummary { + vertical-align: top; +} + +#projectColleagues { + vertical-align: top; + width: 240px; +} + +/* Project Summary */ +.projectTitle { + font-family: "Trebuchet MS", Verdana, Helvetica, sans-serif; + font-size: medium; + font-weight: bold; + margin: -8px 0px 4px; + float: left; +} + +.collabHeader { + background: url(${url.context}/images/parts/collab_topleft.png) no-repeat left top; + margin: 0px; + padding: 0px 0px 0px 2px; +} +.collabHeader span { + background: url(${url.context}/images/parts/collab_topright.png) no-repeat right top; + display: block; + float: none; + padding: 5px 15px 4px 6px; + font-weight: bold; + font-size: 10pt; +} + +#refreshProjectSpace { + cursor: pointer; +} + +.collabContainer { + min-height: 289px; +} + +.projectSpace { + background: url(${url.context}/images/parts/collab_gradleft.png) no-repeat left top; + float: left; + margin: 1em 0px; + padding: 0px; + width: 50%; +} +.projectSpace span { + background: url(${url.context}/images/parts/collab_gradright.png) no-repeat right top; + display: block; + float: none; + margin: 0px 0px 0px 16px; + padding: 8px 0px 0px; +} + +.projectSpaceArrow { + float: right; + margin: 0px 16px 0px 0px; +} + +.projectSpaceIcon { + float: left; + padding-right: 8px; +} +a.projectSpaceTitle:link, a.projectSpaceTitle:visited { + font-weight: bold; + font-size: 10pt; +} + +a.projectSpaceTitle:hover { + font-weight: bold; + font-size: 10pt; + text-decoration: underline; +} + +.projectSpaceSummary { + margin: 0px 8px; +} + +.collabFooter { + background: url(${url.context}/images/parts/collab_bottomleft.png) no-repeat left top; + margin: 0px; + padding: 0px 0px 0px 4px; +} +.collabFooter span { + background: url(${url.context}/images/parts/collab_bottomright.png) no-repeat right top; + display: block; + float: none; + padding: 5px 15px 4px 6px; +} +</style> diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/projectSpace.get.js b/config/alfresco/templates/webscripts/org/alfresco/collaboration/projectSpace.get.js new file mode 100644 index 0000000000..c9b9631726 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/projectSpace.get.js @@ -0,0 +1,36 @@ +/* + * projectSpace + * + * Inputs: + * mandatory: nodeRef = parent space nodeRef + * + * Outputs: projectSpace - object containing pproject space details + */ +model.projectSpace = main(args["nodeRef"]); + +function main(nodeRef) +{ + var title = ""; + var subSpaces = {}; + var space = search.findNode(nodeRef); + + if (space != null) + { + title = space.name; + // Discover the nodeRef of each project subspace + for each(node in space.children) + { + if (node.hasAspect("{http://www.alfresco.org/model/content/1.0}projectsummary")) + { + subSpaces[node.name] = node; + } + } + } + + var projectSpace = + { + "title": title, + "subSpaces": subSpaces + }; + return projectSpace; +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.get.desc.xml new file mode 100644 index 0000000000..9927a2cb60 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.get.desc.xml @@ -0,0 +1,8 @@ +<webscript> + <shortname>Tagging Actions</shortname> + <description>Add and remove tags to nodes</description> + <url>/collaboration/tagActions</url> + <format default="html"/> + <authentication>user</authentication> + <transaction>required</transaction> +</webscript> diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.get.html.ftl new file mode 100644 index 0000000000..7ff46f8e78 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.get.html.ftl @@ -0,0 +1,52 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html> +<head> + <title>Tagging Test UI + + + +

Tagging Test UI

+
+ +
+ Space nodeRef: +
e.g. "e3741425-35cf-11dc-9762-4b73d0280543"
+
+ +
+ Tag: + +
+ +
+ + +
+ +
+ + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.post.desc.xml new file mode 100644 index 0000000000..9927a2cb60 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.post.desc.xml @@ -0,0 +1,8 @@ + + Tagging Actions + Add and remove tags to nodes + /collaboration/tagActions + + user + required + diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.post.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.post.html.ftl new file mode 100644 index 0000000000..e2a6dff774 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.post.html.ftl @@ -0,0 +1,5 @@ +{ + "statusString":"${tagActions.resultString}", + "statusCode":${tagActions.resultCode?string}, + "newTag":"${tagActions.newTag?string}" +} \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.post.js b/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.post.js new file mode 100644 index 0000000000..ec5d6d6c40 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagActions.post.js @@ -0,0 +1,150 @@ +model.tagActions = tagActions(args.a, args.n, args.t); + +function tagActions(action, nodeId, tagName) +{ + var resultString = "Action failed"; + var resultCode = false; + var node = null; + var newTag = null; + var newTagNodeRef = ""; + + if ((tagName != "") && (tagName != null)) + { + tagName = tagName.toLowerCase(); + if (action == "add") + { + // Make sure the tag is in the repo + newTag = createTag(tagName); + if (newTag != null) + { + resultString = "Tag added"; + resultCode = true; + newTagNodeRef = newTag.nodeRef.toString(); + } + else + { + resultString = "Tag '" + tagName + "' not indexed"; + } + } + + // Adding/removing the tag to/from a node? + if ((nodeId != "") && (nodeId != null)) + { + var node = search.findNode("workspace://SpacesStore/" + nodeId); + + if (node != null) + { + try + { + var tags; + + if (action == "add") + { + // Must have newTag node + if (newTag != null) + { + resultString = "Already tagged with '" + tagName + "'"; + tags = node.properties["cm:taggable"]; + if (tags == null) + { + tags = new Array(); + } + // Check node doesn't already have this tag + var hasTag = false; + for each (tag in tags) + { + if (tag != null) + { + if (tag.name == tagName) + { + hasTag = true; + break; + } + } + } + if (!hasTag) + { + // Add it to our node + tags.push(newTag); + tagsArray = new Array(); + tagsArray["cm:taggable"] = tags; + node.addAspect("cm:taggable", tagsArray); + + resultString = "Document tagged"; + resultCode = true; + } + } + } + else if (action == "remove") + { + resultString = "Could not remove tag"; + var oldTags = node.properties["cm:taggable"]; + if (oldTags == null) + { + oldTags = new Array(); + } + tags = new Array(); + // Find this tag + for each (tag in oldTags) + { + if (tag != null) + { + if (tag.name != tagName) + { + tags.push(tag); + } + } + } + // Removed tag? + if (oldTags.length > tags.length) + { + tagsArray = new Array(); + tagsArray["cm:taggable"] = tags; + node.addAspect("cm:taggable", tagsArray); + resultString = "Tag removed"; + resultCode = true; + } + else + { + resultString = "Not tagged with '" + tagName + "'"; + } + } + else + { + resultString = "Unknown action"; + } + } + catch(e) + { + resultString = "Action failed due to exception [" + e.toString() + "]"; + } + } + } + } + + var result = + { + "resultString": resultString, + "resultCode": resultCode, + "newTag": newTagNodeRef + }; + return result; +} + +/* + * Create a new tag if the passed-in one doesn't exist + */ +function createTag(tagName) +{ + var existingTags = classification.getRootCategories("cm:taggable"); + for each (existingTag in existingTags) + { + if (existingTag.name == tagName) + { + return existingTag; + } + } + + var tagNode = classification.createRootCategory("cm:taggable", tagName); + return tagNode; +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagQuery.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagQuery.get.desc.xml new file mode 100644 index 0000000000..11631c4af1 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagQuery.get.desc.xml @@ -0,0 +1,8 @@ + + Tagging Query + Query tag usage + /collaboration/tagQuery + + user + required + diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagQuery.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagQuery.get.html.ftl new file mode 100644 index 0000000000..986676c7c8 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagQuery.get.html.ftl @@ -0,0 +1,13 @@ +{ +"countMin": "${tagQuery.countMin}", +"countMax": "${tagQuery.countMax}", +"tags": +<#assign n=0> +[ +<#list tagQuery.tags as tag> + <#if (n > 0)>, +{"name": "${tag.name}", "count": "${tag.count}"} + <#assign n=n+1> + +] +} \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagQuery.get.js b/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagQuery.get.js new file mode 100644 index 0000000000..991b0a4623 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/tagQuery.get.js @@ -0,0 +1,104 @@ +model.tagQuery = tagQuery(args["n"], args["m"]); + +function tagQuery(nodeRef, maxResults) +{ + var tags = new Array(); + var countMin = Number.MAX_VALUE, + countMax = 0; + + /* nodeRef input */ + var node = null; + if ((nodeRef != null) && (nodeRef != "")) + { + node = search.findNode(nodeRef); + } + if (node == null) + { + node = companyhome; + } + + /* maxResults input */ + if ((maxResults == null) || (maxResults == "")) + { + maxResults = -1; + } + + /* Query for tagged node(s) */ + var query = "PATH:\"" + node.qnamePath; + if (node.isContainer) + { + query += "//*"; + } + query += "\" AND ASPECT:\"{http://www.alfresco.org/model/content/1.0}taggable\""; + + var taggedNodes = search.luceneSearch(query); + + if (taggedNodes.length == 0) + { + countMin = 0; + } + else + { + /* Build a hashtable of tags and tag count */ + var tagHash = {}; + var count; + for each (taggedNode in taggedNodes) + { + for each(tag in taggedNode.properties["cm:taggable"]) + { + if (tag != null) + { + count = tagHash[tag.name]; + tagHash[tag.name] = count ? count+1 : 1; + } + } + } + + /* Convert the hashtable into an array of objects */ + for (key in tagHash) + { + tag = + { + name: key, + count: tagHash[key], + toString: function() + { + return this.name; + } + }; + tags.push(tag); + } + + /* Sort the results by count (descending) */ + tags.sort(sortByCountDesc); + + /* Trim the results to maxResults if specified */ + if (maxResults > -1) + { + tags = tags.slice(0, maxResults); + } + + /* Calculate the min and max tag count values */ + for each(tag in tags) + { + countMin = Math.min(countMin, tag.count); + countMax = Math.max(countMax, tag.count); + } + + /* Sort the results by tag name (ascending) */ + tags.sort(); + } + + var results = + { + "countMin": countMin, + "countMax": countMax, + "tags": tags + }; + return results; +} + +function sortByCountDesc(a, b) +{ + return (b.count - a.count); +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/viewgallery.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/collaboration/viewgallery.get.desc.xml new file mode 100644 index 0000000000..9187718ad3 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/viewgallery.get.desc.xml @@ -0,0 +1,14 @@ + + + + Views the specified gallery + Views the specified gallery. + + + /collaboration/gallery/view/{noderef} + + extension + user + required + + diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/viewgallery.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/collaboration/viewgallery.get.html.ftl new file mode 100644 index 0000000000..eba238644b --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/viewgallery.get.html.ftl @@ -0,0 +1,28 @@ + +<#assign dataURL=absurl(url.context) + "/wcs/collaboration/gallery/" + path> + + + + + + + + + + + + + + + + + diff --git a/config/alfresco/templates/webscripts/org/alfresco/collaboration/viewgallery.get.js b/config/alfresco/templates/webscripts/org/alfresco/collaboration/viewgallery.get.js new file mode 100644 index 0000000000..e7e637bc7d --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/collaboration/viewgallery.get.js @@ -0,0 +1,3 @@ + +model.ticket = session.ticket; +model.path = url.extension; \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/jsdebugger.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/jsdebugger.get.desc.xml new file mode 100644 index 0000000000..f83874aaa6 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/jsdebugger.get.desc.xml @@ -0,0 +1,6 @@ + + Javascript Debugger + Javascript Debugger + /api/javascript/debugger + admin + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/jsdebugger.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/jsdebugger.get.html.ftl new file mode 100644 index 0000000000..5e70fac3c4 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/jsdebugger.get.html.ftl @@ -0,0 +1,22 @@ + + + + + Alfresco Javascript Debugger + + + +
+ + + + + + +
AlfrescoAlfresco Javascript Debugger
Alfresco ${server.edition} v${server.version} +
Currently <#if visible>enabled<#else>disabled. + +
+
+ + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/jsdebugger.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/jsdebugger.post.desc.xml new file mode 100644 index 0000000000..be8dffd065 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/jsdebugger.post.desc.xml @@ -0,0 +1,6 @@ + + Javascript Debugger Maintenance + Javascript Debugger Maintenance + /api/javascript/debugger?active={active?} + admin + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/jsdebugger.post.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/jsdebugger.post.html.ftl new file mode 100644 index 0000000000..5e70fac3c4 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/jsdebugger.post.html.ftl @@ -0,0 +1,22 @@ + + + + + Alfresco Javascript Debugger + + + +
+ + + + + + +
AlfrescoAlfresco Javascript Debugger
Alfresco ${server.edition} v${server.version} +
Currently <#if visible>enabled<#else>disabled. + +
+
+ + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/docActions.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/office/docActions.get.desc.xml new file mode 100644 index 0000000000..a2aa0c797b --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/docActions.get.desc.xml @@ -0,0 +1,7 @@ + + Document Actions (Office Add-In) + Used by the Office Add-In to perform actions on managed documents + /office/docActions + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/docActions.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/office/docActions.get.html.ftl new file mode 100644 index 0000000000..6d48b83dcf --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/docActions.get.html.ftl @@ -0,0 +1,4 @@ +{ + "statusString":"${resultString}", + "statusCode":${resultCode?string} +} \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/docActions.get.js b/config/alfresco/templates/webscripts/org/alfresco/office/docActions.get.js new file mode 100644 index 0000000000..fd2c99cdf1 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/docActions.get.js @@ -0,0 +1,158 @@ +// Client has requested server-side action + +/* Inputs */ +var runAction = args.a; + +/* Outputs */ +var resultString = "Action failed", + resultCode = false; + +// Is this action targetting a document? +var docNodeId = args.n; +if ((docNodeId != "") && (docNodeId != null)) +{ + var docNode = search.findNode("workspace://SpacesStore/" + docNodeId); + + if (docNode != null && docNode.isDocument) + { + try + { + if (runAction == "makepdf") + { + resultString = "Could not convert document"; + var nodeTrans = docNode.transformDocument("application/pdf"); + if (nodeTrans != null) + { + resultString = "Document converted"; + resultCode = true; + } + } + else if (runAction == "delete") + { + resultString = "Could not delete document"; + if (docNode.remove()) + { + resultString = "Document deleted"; + resultCode = true; + } + } + else if (runAction == "checkout") + { + var workingCopy = docNode.checkout(); + if (workingCopy != null) + { + resultString = "Document checked out"; + resultCode = true; + } + } + else if (runAction == "checkin") + { + var originalDoc = docNode.checkin(); + if (originalDoc != null) + { + resultString = "Document checked in"; + resultCode = true; + } + } + else if (runAction == "makeversion") + { + resultString = "Could not version document"; + if (docNode.addAspect("cm:versionable")) + { + resultString = "Document versioned"; + resultCode = true; + } + } + else if (runAction == "workflow") + { + var workflowType = "jbpm$wf:" + args.wt; + var assignTo = people.getPerson(args.at); + var dueDate = new Date(args.dd); + var description = args.desc; + + var workflow = actions.create("start-workflow"); + workflow.parameters.workflowName = workflowType; + workflow.parameters["bpm:workflowDescription"] = description; + workflow.parameters["bpm:assignee"] = assignTo; + if ((args.dd) && (args.dd != "")) + { + workflow.parameters["bpm:workflowDueDate"] = dueDate; + } + workflow.execute(docNode); + resultString = "New workflow started"; + resultCode = true; + } + else if (runAction == "test") + { + resultString = "Tested ok."; + resultCode = true; + } + else + { + resultString = "Unknown action"; + } + } + catch(e) + { + resultString = "Action failed due to exception"; + } + } +} +else // Non document-based actions +{ + try + { + if (runAction == "newspace") + { + resultString = "Could not create space"; + var parentNodeId = args.p, + spaceName = args.sn, + spaceTitle = (args.st == "undefined") ? "" : args.st, + spaceDescription = (args.sd == "undefined") ? "" : args.sd, + templateId = args.t; + var nodeNew; + + if ((spaceName == null) || (spaceName == "")) + { + resultString = "Space must have a Name"; + } + else + { + var nodeParent = search.findNode("workspace://SpacesStore/" + parentNodeId); + // Copy from template? + if ((templateId != null) && (templateId != "")) + { + nodeTemplate = search.findNode("workspace://SpacesStore/" + templateId); + nodeNew = nodeTemplate.copy(nodeParent, true); + nodeNew.name = spaceName; + } + else + { + nodeNew = nodeParent.createFolder(spaceName); + } + // Always add title & description, default icon + nodeNew.properties["cm:title"] = spaceTitle; + nodeNew.properties["cm:description"] = spaceDescription; + nodeNew.properties["app:icon"] = "space-icon-default"; + nodeNew.save(); + // Add uifacets aspect for the web client + nodeNew.addAspect("app:uifacets"); + if (nodeNew != null) + { + resultString = "New space created"; + resultCode = true; + } + } + } + else + { + resultString = "Unknown action"; + } + } + catch(e) + { + resultString = "Action failed due to exception"; + } +} +model.resultString = resultString; +model.resultCode = resultCode; \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/documentDetails.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/office/documentDetails.get.desc.xml new file mode 100644 index 0000000000..25198cab30 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/documentDetails.get.desc.xml @@ -0,0 +1,7 @@ + + Document Details (Office Add-In) + Generate the Office Add-In Document Details page + /office/documentDetails?p={path?} + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/documentDetails.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/office/documentDetails.get.html.ftl new file mode 100644 index 0000000000..f3a0979b5e --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/documentDetails.get.html.ftl @@ -0,0 +1,263 @@ +<#assign doc_actions="${url.serviceContext}/office/docActions"> + +<#if args.p?exists><#assign path=args.p><#else><#assign path=""> +<#if args.e?exists><#assign extn=args.e><#else><#assign extn="doc"><#assign extnx=extn+"x"> +<#if args.n?exists><#assign nav=args.n><#else><#assign nav=""> +<#-- resolve the path (from Company Home) into a node --> +<#if companyhome.childByNamePath[path]?exists> + <#assign d=companyhome.childByNamePath[path]> +<#else> + <#assign d=companyhome> + +<#assign defaultQuery="?p=" + path?url + "&e=" + extn + "&n=" + nav> + + + + ${message("office.title.document_details")} + + + + + + + + + +
+
    +
  • ${message(
  • +
  • ${message(
  • +
  • ${message(
  • +
  • ${message(
  • +
  • ${message(
  • +
  • ${message(
  • +
+
+ +
Current Document Details
+ +
+
+ + + + + + + +
+<#if d.isDocument> + ${d.name} + + + <#if d.isLocked > + Locked + + ${d.name} + +
+ + <#if d.properties.title?exists> + + <#else> + + + <#if d.properties.description?exists> + + <#else> + + + + + + + + + + +
Title:${d.properties.title}
Title: 
Description:${d.properties.description}
Description: 
Creator:${d.properties.creator}
Created:${d.properties.created?datetime}
Modifier:${d.properties.modifier}
Modified:${d.properties.modified?datetime}
Size:${d.size / 1024} Kb
Categories: + <#if d.properties.categories?exists> + <#list d.properties.categories as category> + ${category.name}<#if category != d.properties.categories?last>, + + <#else> + None. + +
+<#else> + The current document is not managed by Alfresco. + +
+
+
+
+ +
+
    +
  • Document Tags
  • +
  • Version History
  • +
+
+ +
+
Tags<#if d.isDocument> for ${d.name}
+
+ <#if d.isDocument > +
+ +
+
+
+ + + +
+
+
+ <#if d.hasAspect("cm:taggable")> + <#if (d.properties["cm:taggable"]?size > 0)> + <#list d.properties["cm:taggable"]?sort_by("name") as tag> + <#if tag?exists> + + + + + + <#else> + + + + +
+ The current document is not managed by Alfresco. +
+ +
+
+ +
+
Version History<#if d.isDocument> for ${d.name}
+
+ + <#if d.isDocument > + <#if d.hasAspect("cm:versionable")> + <#assign versionRow=0> + <#list d.versionHistory?sort_by("versionLabel")?reverse as record> + <#assign versionRow=versionRow+1> + + + + + + <#else> + + + + + <#else> + + + + +
+ Open ${record.versionLabel} + + ${record.versionLabel}
+ Author: ${record.creator}
+ Date: ${record.createdDate?datetime}
+ <#if record.description?exists> + Notes: ${record.description}
+ + <#-- Only Word supports document compare --> + <#if extn = "doc"> + Compare with current
+ +
+ The current document is not versioned.
+
+ +
+ The current document is not managed by Alfresco. +
+
+
+ +
Document Actions
+ +
+
    +<#if d.isDocument> + <#if d.isLocked > + <#elseif d.hasAspect("cm:workingcopy")> +
  • + + Check In + Check In + +
    Check in the current document. +
  • + <#else> +
  • + + Check Out + Check Out + +
    Check out the current document to a working copy. +
  • + +
  • + + Start Workflow + Start Workflow + +
    Start Advanced Workflow for the current document. +
  • + <#if d.name?ends_with(extn) || d.name?ends_with(extnx)> +
  • + + Transform to PDF + Transform to PDF + +
    Transform the current document to Adobe PDF format. +
  • + +
  • + + Open Full Details + Open Full Details + +
    Open the document details in the Alfresco Web Client. +
  • +<#else> +
  • + + Save to Alfresco + Save to Alfresco + +
    Allows you to place the current document under Alfresco management. +
  • + +
+
+ +<#if args.version?exists> + + + + + diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/getUsers.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/office/getUsers.get.desc.xml new file mode 100644 index 0000000000..9c77b25cc1 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/getUsers.get.desc.xml @@ -0,0 +1,7 @@ + + Get Users (Office Add-In) + Used by the Office Add-In to query for users + /office/getUsers?s={searchTerm} + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/getUsers.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/office/getUsers.get.html.ftl new file mode 100644 index 0000000000..983440d2f0 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/getUsers.get.html.ftl @@ -0,0 +1,7 @@ +<#assign n=0> +<#list searchResults as result> + <#if (n > 0)>,<#else>[ +"${"${result.properties.firstName} ${result.properties.lastName}"?trim} (${result.properties.userName})" + <#assign n=n+1> + +] \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/getUsers.get.js b/config/alfresco/templates/webscripts/org/alfresco/office/getUsers.get.js new file mode 100644 index 0000000000..cc3ab9ae05 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/getUsers.get.js @@ -0,0 +1,18 @@ +var query = "TYPE:\"{http://www.alfresco.org/model/content/1.0}person\""; + +if ((args.s) && (args.s != "")) +{ + query += " AND ("; + var terms = args.s.split(" "); + for (i = 0; i < terms.length; i++) + { + term = terms[i]; + query += "((@\\{http\\://www.alfresco.org/model/content/1.0\\}firstName:*" + term; + query += "*) OR (@\\{http\\://www.alfresco.org/model/content/1.0\\}lastName:*" + term; + query += "*) OR (@\\{http\\://www.alfresco.org/model/content/1.0\\}userName:" + term; + query += "*)) "; // final space here is important as default OR separator + } + query += ")"; +} + +model.searchResults = search.luceneSearch(query); diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/myAlfresco.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/office/myAlfresco.get.desc.xml new file mode 100644 index 0000000000..f2000610ec --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/myAlfresco.get.desc.xml @@ -0,0 +1,7 @@ + + My Alfresco (Office Add-In) + Generate the Office Add-In My Alfresco page + /office/myAlfresco?p={path?} + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/myAlfresco.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/office/myAlfresco.get.html.ftl new file mode 100644 index 0000000000..aa26ca1812 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/myAlfresco.get.html.ftl @@ -0,0 +1,159 @@ +<#assign doc_actions="${url.serviceContext}/office/docActions"> +<#if args.p?exists><#assign path=args.p><#else><#assign path=""> +<#if args.e?exists><#assign extn=args.e><#else><#assign extn="doc"><#assign extnx=extn+"x"> +<#if args.n?exists><#assign nav=args.n><#else><#assign nav=""> +<#-- resolve the path (from Company Home) into a node --> +<#if companyhome.childByNamePath[path]?exists> + <#assign d=companyhome.childByNamePath[path]> +<#else> + <#assign d=companyhome> + +<#assign defaultQuery="?p=" + path?url + "&e=" + extn + "&n=" + nav> + + + + My Alfresco + + + + + + + + + +
+
    +
  • My Alfresco
  • +
  • Browse Spaces and Documents
  • +
  • Search Alfresco
  • +
  • View Details
  • +
  • My Tasks
  • +
  • ${message(
  • +
+
+ +
My Checked Out Documents 
+ +
+<#assign rowNum=0> +<#assign query="@cm\\:workingCopyOwner:${person.properties.userName}"> + <#list companyhome.childrenByLuceneSearch[query] as child> + <#if child.isDocument> + <#assign rowNum=rowNum+1> + <#assign relativePath = (child.displayPath?substring(companyhome.name?length+1) + '/' + child.name)?url?replace('%2F', '/')?replace('\'', '\\\'') /> +
+ + ${child.name} + + + <#if child.name?ends_with(extn) || child.name?ends_with(extnx)> + ${child.name}
+ <#else> + ${child.name}
+ + <#if child.properties.description?exists> + <#if (child.properties.description?length > 0)> + ${child.properties.description}
+ + + Modified: ${child.properties.modified?datetime} (${(child.size / 1024)?int}Kb)
+ Check In + Create Workflow... + Insert File into Current Document + <#if !child.name?ends_with(".pdf")> + Make PDF... + +
+
+ + + <#if rowNum = 0> +
+ (No documents) +
+ +
+ +
My Tasksoverdue=overdue, due today=due today 
+ +
+<#assign taskNum=0> +<#list workflow.assignedTasks as t> + <#assign taskNum=taskNum+1> + <#assign hasDue=t.properties["bpm:dueDate"]?exists> + <#if hasDue> + <#assign due=t.properties["bpm:dueDate"]> + +
99999999999999"> + + <#if hasDue> + <#-- items due today? --> + <#if (dateCompare(date?date, due?date, 0, "==") == 1)> + due today + <#-- items overdue? --> + <#elseif (dateCompare(date?date, due?date) == 1)> + overdue + + <#else> +   + + + + ${t.description!""?html} (${t.type?html}) + <#if hasDue> +
Due date: ${due?date} + <#else> +
(No due date) + +
+
+ +<#if taskNum = 0> +
+ (No tasks) +
+ +
+ +
Actions
+ +
+
+ +
+ +
+ +
+ + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/myTasks.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/office/myTasks.get.desc.xml new file mode 100644 index 0000000000..385f9f7d32 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/myTasks.get.desc.xml @@ -0,0 +1,7 @@ + + My Tasks (Office Add-In) + Generate the Office Add-In My Tasks page + /office/myTasks?p={path} + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/myTasks.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/office/myTasks.get.html.ftl new file mode 100644 index 0000000000..6992930113 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/myTasks.get.html.ftl @@ -0,0 +1,141 @@ +<#assign doc_actions="${url.serviceContext}/office/docActions"> +<#if args.p?exists><#assign path=args.p><#else><#assign path=""> +<#if args.e?exists><#assign extn=args.e><#else><#assign extn="doc"><#assign extnx=extn+"x"> +<#if args.n?exists><#assign nav=args.n><#else><#assign nav=""> +<#if docWorkflow?exists> + <#assign d=docWorkflow> +<#else> + <#-- resolve the path (from Company Home) into a node --> + <#if companyhome.childByNamePath[path]?exists> + <#assign d=companyhome.childByNamePath[path]> + <#else> + <#assign d=companyhome> + + +<#assign defaultQuery="?p=" + path?url + "&e=" + extn + "&n=" + nav> + + + + My Tasks + + + + + + + + + + + +
+
    +
  • My Alfresco
  • +
  • Browse Spaces and Documents
  • +
  • Search Alfresco
  • +
  • View Details
  • +
  • My Tasks
  • +
  • ${message(
  • +
+
+ +
My Tasksoverdue=overdue, due today=due today
+ +
+<#assign taskNum=0> +<#list workflow.assignedTasks as t> + <#assign taskNum=taskNum+1> + <#assign hasDue=t.properties["bpm:dueDate"]?exists> + <#if hasDue> + <#assign due=t.properties["bpm:dueDate"]> + +
99999999999999"> + + <#if hasDue> + <#-- items due today? --> + <#if (dateCompare(date?date, due?date, 0, "==") == 1)> + due today + <#-- items overdue? --> + <#elseif (dateCompare(date?date, due?date) == 1)> + overdue + + <#else> +   + + + + ${t.description!""?html} (${t.type?html}) + <#if hasDue> +
Due date: ${due?date} + <#else> +
(No due date) + +
+
+ +<#if taskNum = 0> +
+ (No tasks) +
+ +
+ +
Task Details
+ +
+
+<#if args.w?exists && d.isDocument> +
+ + + + + +
Start workflow + Start workflow on:
${d.name?html} +
+ +
Enter new workflow details below
+
+
Workflow:
+
+ +
+
Assign to:
+
+ + +
+
Due on:
+
+ + date +
+
Description:
+
+
 
+
+ Submit + Cancel +
+ +
+
+<#else> +
+ +
+ +
+ +
+ + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/myTasks.get.js b/config/alfresco/templates/webscripts/org/alfresco/office/myTasks.get.js new file mode 100644 index 0000000000..b6d7a40376 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/myTasks.get.js @@ -0,0 +1,5 @@ +// Was a document passed-in for New Workflow? +if ((args.wd) && (args.wd != "")) +{ + model.docWorkflow = search.findNode("workspace://SpacesStore/" + args.wd); +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/myTasksDetail.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/office/myTasksDetail.get.desc.xml new file mode 100644 index 0000000000..2ee8920464 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/myTasksDetail.get.desc.xml @@ -0,0 +1,7 @@ + + My Tasks Detail (Office Add-In) + Generate the Office Add-In Task Detail page + /office/myTasksDetail?t={taskId} + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/myTasksDetail.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/office/myTasksDetail.get.html.ftl new file mode 100644 index 0000000000..4b277f2ecb --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/myTasksDetail.get.html.ftl @@ -0,0 +1,94 @@ +<#assign doc_actions="${url.serviceContext}/office/docActions"> +<#if args.e?exists><#assign extn=args.e><#else><#assign extn="doc"><#assign extnx=extn+"x"> +<#if args.t?exists> + <#assign taskid = args.t> + <#if taskid != ""> + <#assign task = workflow.getTaskById(taskid)> + + + +<#if task?exists> + + + + + +
Task item + ${task.description!""?html} +
+ + + + + + + + + + + + + + + + + + + + + +
Status:${task.properties["bpm:status"]}
Priority:${task.properties["bpm:priority"]}
Start Date:${task.startDate?date}
Type:${task.type?html}
Complete:${task.properties["bpm:percentComplete"]}%
+
+ +
${task.name?html}:
+
+ + <#list task.packageResources as res> + + <#if res.isDocument> + <#assign relativePath = (res.displayPath?substring(companyhome.name?length+1) + '/' + res.name)?url?replace('%2F', '/')?replace('\'', '\\\'') /> + <#if res.name?ends_with(extn) || res.name?ends_with(extnx)> + + + + <#else> + + + + + +
${res.name} + ${res.name} + <#else> + ${res.name} + ${res.name} + +
+ Modified: ${res.properties.modified?datetime} (${(res.size / 1024)?int}Kb)
+ <#if res.isLocked > + Locked + <#elseif hasAspect(res, "cm:workingcopy") == 1> + Check In + <#else> + Check Out + + Insert File into Current Document + <#if !res.name?ends_with(".pdf")> + Make PDF... + +
${res.name} + ${res.name} +
+
+ +
+ + <#list task.transitions as wt> + ${wt.label?html} + + + + Manage... + +
+ diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/navigation.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/office/navigation.get.desc.xml new file mode 100644 index 0000000000..5119b2295a --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/navigation.get.desc.xml @@ -0,0 +1,7 @@ + + Navigation (Office Add-In) + Generate the Office Add-In Navigation page + /office/navigation?p={path?} + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/navigation.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/office/navigation.get.html.ftl new file mode 100644 index 0000000000..2bcabd2d4d --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/navigation.get.html.ftl @@ -0,0 +1,227 @@ +<#assign doc_actions="${url.serviceContext}/office/docActions"> +<#if args.e?exists><#assign extn=args.e><#else><#assign extn="doc"><#assign extnx=extn+"x"> +<#if args.n?exists><#assign nav=args.n><#else><#assign nav=""> +<#assign chLen=companyhome.name?length> +<#if node.isDocument> + <#assign thisSpace = node.parent> +<#else> + <#assign thisSpace = node> + +<#assign defaultQuery="?p=" + path?url + "&e=" + extn + "&n=" + nav> + + + + Browse Spaces and Documents + + + + + + + + +
+
+
    +
  • My Alfresco
  • +
  • Browse Spaces and Documents
  • +
  • Search Alfresco
  • +
  • View Details
  • +
  • My Tasks
  • +
  • ${message(
  • +
+
+ +
Current Space
+ +
+ + + ${thisSpace.name} + + + ${thisSpace.name}
+<#if thisSpace.properties.description?exists> + ${thisSpace.properties.description} + +
+
+<#if thisSpace=companyhome> +<#else> + + + To UserHome Space + + + Up to Parent Space + + + +
+ +
Spaces in ${thisSpace.name} 
+ +
+
+
+ Create new space + Create New <#if args.cc?exists>Collaboration Space... +
+
+
+
Name:
+
+ +
+
Title:
+
+ +
+
Description:
+
+ +
+<#assign xpath="app:dictionary/app:space_templates/*"> +<#assign templates = companyhome.childrenByXPath[xpath]> +<#if (templates?size > 0)> +
Template:
+
+ +
+ +
 
+ +
+
+
+<#assign spacesFound = 0> +<#list thisSpace.children?sort_by('name') as child> + <#if child.isContainer> + <#assign spacesFound = spacesFound + 1> +
+ + Open ${child.name} + + + + ${child.name} + + <#if child.properties.description?exists> +
${child.properties.description} + +
+
+ + +<#if spacesFound = 0> +
(No subspaces)
+ +
+ +
Documents in ${thisSpace.name} 
+ +
+<#assign documentsFound = 0> +<#list thisSpace.children?sort_by('name') as child> + <#if child.isDocument> + <#assign isVersionable = (hasAspect(child, "cm:versionable") == 1)> + <#assign documentsFound = documentsFound + 1> + <#assign relativePath = (child.displayPath?substring(chLen+1) + '/' + child.name)?url?replace('%2F', '/')?replace('\'', '\\\'') /> +
+ + <#if child.name?ends_with(extn) || child.name?ends_with(extnx)> + Open ${child.name} + <#else> + Open ${child.name} + + + + <#if child.name?ends_with(extn) || child.name?ends_with(extnx)> + ${child.name} + <#else> + ${child.name} + +
+ <#if child.properties.description?exists> + <#if (child.properties.description?length > 0)> + ${child.properties.description}
+ + + Modified: ${child.properties.modified?datetime}, Size: ${(child.size / 1024)?int}Kb
+ <#if child.isLocked > + Locked + <#elseif hasAspect(child, "cm:workingcopy") == 1> + Check In + <#else> + Check Out + + Create Workflow... + Insert File into Current Document + <#if !child.name?ends_with(".pdf")> + Make PDF... + + <#if !child.isLocked> + Delete... + +
+
+ + +<#if documentsFound = 0> +
(No documents)
+ +
+ +
Actions
+ +<#assign currentPath = thisSpace.displayPath + '/' + thisSpace.name /> +<#assign currentPath = currentPath?substring(chLen+1)?url?replace('%2F', '/')?replace('\'', '\\\'') /> + + + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/navigation.get.js b/config/alfresco/templates/webscripts/org/alfresco/office/navigation.get.js new file mode 100644 index 0000000000..301fa95118 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/navigation.get.js @@ -0,0 +1,37 @@ + +if ((args.n) && (args.n != "")) +{ + model.node = search.findNode("workspace://SpacesStore/" + args.n); +} + +// Check here in case invalid nodeRef passed-in +if (model.node == null) +{ + if ((args.p) && (args.p != "")) + { + var path = args.p; + if (path == "/" + companyhome.name) + { + model.node = companyhome; + } + else + { + var node = companyhome.childByNamePath(path.substring(companyhome.name.length)); + if (node != null) + { + model.node = node; + } + else + { + model.node = userhome; + } + } + } +} + +// Last chance - default to userhome +if (model.node == null) +{ + model.node = userhome; +} +model.path = args.p; diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/search.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/office/search.get.desc.xml new file mode 100644 index 0000000000..3fb3f797db --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/search.get.desc.xml @@ -0,0 +1,7 @@ + + Search (Office Add-In) + Generate the Office Add-In Search page + /office/search?p={path?} + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/search.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/office/search.get.html.ftl new file mode 100644 index 0000000000..968ecd66be --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/search.get.html.ftl @@ -0,0 +1,77 @@ +<#if args.p?exists><#assign path=args.p><#else><#assign path=""> +<#if args.n?exists><#assign node=args.n><#else><#assign node=companyhome> +<#if args.e?exists><#assign extn=args.e><#else><#assign extn="doc"><#assign extnx=extn+"x"> +<#if args.n?exists><#assign nav=args.n><#else><#assign nav=""> +<#if (args.searchagain?exists)><#assign searchText=args.searchagain><#else><#assign searchText=""> +<#if (args.maxresults?exists)><#assign maxResults=args.maxresults><#else><#assign maxResults="5"> +<#assign defaultQuery="?p=" + path?url + "&e=" + extn + "&n=" + nav> +<#assign searchCommand="OfficeSearch.runSearch('${url.serviceContext}/office/searchResults', '${defaultQuery}')" > + + + + Browse Spaces and Documents + + + + + + + + +
+
    +
  • My Alfresco
  • +
  • Browse Spaces and Documents
  • +
  • Search Alfresco
  • +
  • View Details
  • +
  • My Tasks
  • +
  • ${message(
  • +
+
+ +
Search
+ +
+
+ +
+ +
+ +
+ +
 
+ +
+
+
+ +<#if (args.searchagain?exists)> + + + + diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/searchResults.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/office/searchResults.get.desc.xml new file mode 100644 index 0000000000..b0abc57e6b --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/searchResults.get.desc.xml @@ -0,0 +1,7 @@ + + Search Results (Office Add-In) + Generate the Office Add-In Search Results page + /office/searchResults?search={searchString?}&maxresults={maxresults?} + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/searchResults.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/office/searchResults.get.html.ftl new file mode 100644 index 0000000000..d3daa14d24 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/searchResults.get.html.ftl @@ -0,0 +1,75 @@ +<#assign doc_actions="${url.serviceContext}/office/docActions"> +<#if args.p?exists><#assign path=args.p><#else><#assign path=""> +<#if args.n?exists><#assign nav=args.n><#else><#assign nav=""> +<#if args.e?exists><#assign extn=args.e><#else><#assign extn="doc"><#assign extnx=extn+"x"> +<#if args.search?exists><#assign searchString = args.search><#else><#assign searchString=""> +<#assign defaultQuery="?p=" + path?url + "&e=" + extn + "&n=" + nav> + +<#if args.maxresults?exists> + <#assign maxresults=args.maxresults?number> +<#else> + <#assign maxresults=10> + +<#assign resCount=0> +<#assign totalResults=0> +<#if results?size = 0> +
+ (No results found) +
+<#else> + <#assign totalResults = results?size> + <#list results?sort_by(["properties","cm:modified"])?reverse as child> + <#assign resCount=resCount + 1> + <#if child.isDocument> + <#assign relativePath = (child.displayPath?substring(companyhome.name?length+1) + '/' + child.name)?url?replace('%2F', '/')?replace('\'', '\\\'') /> + <#if child.name?ends_with(extn) || child.name?ends_with(extnx)> + <#assign openURL = "#"> + <#assign hrefExtra = " onClick=\"window.external.openDocument('${relativePath}')\""> + <#else> + <#assign openURL = "${url.context}${child.url}?ticket=${session.ticket}"> + <#assign hrefExtra = " target=\"_blank\""> + + <#else> + <#assign openURL = "${url.serviceContext}/office/navigation?p=${path?url}&e=${extn}&n=${child.id}&search=${searchString?url}&maxresults=${maxresults}"> + <#assign hrefExtra = ""> + +
+ + Open ${child.name} + + + ${child.name}
+ <#if child.properties.description?exists> + <#if (child.properties.description?length > 0)> + ${child.properties.description}
+ + + <#if child.isDocument> + Modified: ${child.properties.modified?datetime} (${(child.size / 1024)?int}Kb)
+ <#if child.isLocked > + Locked + <#elseif hasAspect(child, "cm:workingcopy") == 1> + Check In + <#else> + Check Out + + Create Workflow... + Insert File into Current Document + <#if !child.name?ends_with(".pdf")> + Make PDF... + + <#if !child.isLocked> + Delete... + + +
+
+ <#if resCount = maxresults> + <#break> + + + + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/searchResults.get.js b/config/alfresco/templates/webscripts/org/alfresco/office/searchResults.get.js new file mode 100644 index 0000000000..20b5388a6c --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/searchResults.get.js @@ -0,0 +1,23 @@ +var searchString = args.search; +var searchType = args.type; +var queryString; + +if ((searchString != null) && (searchString != "")) +{ + if (searchType == "tag") + { + queryString = "PATH:\"/cm:categoryRoot/cm:taggable/cm:" + searchString + "/member\""; + } + else + { + queryString = "(TEXT:\"" + searchString + "\") OR (@cm\\:name:*" + searchString + "*)"; + } +} +else +{ + searchString = ""; + queryString = ""; +} + +model.results = search.luceneSearch(queryString); + diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/tags.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/office/tags.get.desc.xml new file mode 100644 index 0000000000..f9f6a3ba49 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/tags.get.desc.xml @@ -0,0 +1,7 @@ + + Document Tags (Office Add-In) + Generate the Office Add-In Tags page + /office/tags?p={path?} + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/tags.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/office/tags.get.html.ftl new file mode 100644 index 0000000000..533dff2165 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/office/tags.get.html.ftl @@ -0,0 +1,62 @@ +<#if args.p?exists><#assign path=args.p><#else><#assign path=""> +<#if args.e?exists><#assign extn=args.e><#else><#assign extn="doc"><#assign extnx=extn+"x"> +<#if args.n?exists><#assign nav=args.n><#else><#assign nav=""> +<#if args.tag?exists><#assign tag=args.tag><#else><#assign tag=""> +<#-- resolve the path (from Company Home) into a node --> +<#if companyhome.childByNamePath[path]?exists> + <#assign d=companyhome.childByNamePath[path]> +<#else> + <#assign d=companyhome> + +<#assign defaultQuery="?p=" + path?url + "&e=" + extn + "&n=" + nav> + + + + ${message("office.title.document_tags")} + + + + + + + + + +
+
    +
  • ${message(
  • +
  • ${message(
  • +
  • ${message(
  • +
  • ${message(
  • +
  • ${message(
  • +
  • ${message(
  • +
+
+ +
Tag Cloud
+ +
+
+
+
+
+
+ +
Tagged Documents
+ +
+
+
+
+ +<#if (args.tag?exists)> + + + + diff --git a/config/alfresco/templates/webscripts/org/alfresco/office/tags.get.js b/config/alfresco/templates/webscripts/org/alfresco/office/tags.get.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/doclist.get.atom.ftl b/config/alfresco/templates/webscripts/org/alfresco/portlets/doclist.get.atom.ftl new file mode 100644 index 0000000000..91d341b23b --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/doclist.get.atom.ftl @@ -0,0 +1,72 @@ +<#-- get the path location from the passed in args --> +<#if args.p?exists><#assign path=args.p><#else><#assign path=""> +<#-- see if lucene query specified - this overrides any path argument --> +<#if !args.q?exists || args.q?length=0> + <#assign query=""> + <#-- resolve the path (from Company Home) into a node or fall back to userhome--> + <#if path?starts_with("/Company Home")> + <#if path?length=13> + <#assign home=companyhome> + <#elseif companyhome.childByNamePath[args.p[14..]]?exists> + <#assign home=companyhome.childByNamePath[args.p[14..]]> + <#else> + <#assign home=userhome> + + <#else> + <#assign home=userhome> + +<#else> + <#assign query=args.q> + + + + + Alfresco - My Documents + ${absurl(url.context)}/ + Alfresco - My Documents + ${xmldate(date)} + ${xmldate(date)} + Alfresco ${server.edition} v${server.version} + + Alfresco - My Documents + ${absurl(url.context)}/images/logo/AlfrescoLogo200.png + +<#assign weekms=1000*60*60*24*7> +<#assign count=0> +<#-- get the filter mode from the passed in args --> +<#-- filters: 0=all, 1=word, 2=html, 3=pdf, 4=recent --> +<#if args.f?exists && args.f?length!=0><#assign filter=args.f?number><#else><#assign filter=0> +<#if home?exists> + <#assign docs=home.children?reverse> +<#else> + <#assign docs=companyhome.childrenByLuceneSearch[query]?sort_by('name')> + +<#list docs as d> + <#if d.isDocument> + <#assign isImage=(d.mimetype="image/gif" || d.mimetype="image/jpeg" || d.mimetype="image/png")> + <#assign isMP3=(d.mimetype="audio/x-mpeg" || d.mimetype="audio/mpeg")> + <#if (filter=0) || + (filter=1 && d.mimetype="application/msword") || + (filter=2 && d.mimetype="text/html") || + (filter=3 && d.mimetype="application/pdf") || + (filter=4 && (dateCompare(d.properties["cm:modified"],date,weekms) == 1 || dateCompare(d.properties["cm:created"], date, weekms) == 1))> + <#assign count=count+1> + + ${d.name?html} + <#assign navurl='/navigate/showDocDetails/' + d.nodeRef.storeRef.protocol + '/' + d.nodeRef.storeRef.identifier + '/' + d.nodeRef.id> + ${absurl(url.context)}${navurl}?ticket=${session.ticket} + <#if isMP3> + + + + <#if isImage><img src="${absurl(url.context)}${d.url}?ticket=${session.ticket}"><br> + <#if d.properties.description?exists>${d.properties.description?html} + + ${xmldate(d.properties.modified)} + ${d.id} + + + + + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/doclist.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/portlets/doclist.get.desc.xml new file mode 100644 index 0000000000..20c1dc0c2f --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/doclist.get.desc.xml @@ -0,0 +1,8 @@ + + Document List + Generate the Document list portlet page + /ui/doclist?f={filter?}&p={path?}&q={query?} + /ui/doclist.atom?f={filter?}&p={path?}&q={query?} + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/doclist.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/portlets/doclist.get.html.ftl new file mode 100644 index 0000000000..166e9237bb --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/doclist.get.html.ftl @@ -0,0 +1,445 @@ + + + + + + + + + + + + +<#-- get the filter mode from the passed in args --> +<#-- filters: 0=all, 1=word, 2=html, 3=pdf, 4=recent --> +<#if args.f?exists && args.f?length!=0><#assign filter=args.f?number><#else><#assign filter=0> + +<#-- get the path location from the passed in args --> +<#if args.p?exists><#assign path=args.p><#else><#assign path=""> + +<#-- see if lucene query specified - this overrides any path argument --> +<#if !args.q?exists || args.q?length=0> + <#assign query=""> + <#-- resolve the path (from Company Home) into a node or fall back to userhome--> + <#assign chLen=companyhome.name?length> + <#if path?starts_with("/" + companyhome.name)> + <#if path?length=chLen+1> + <#assign home=companyhome> + <#elseif companyhome.childByNamePath[path[(chLen+2)..]]?exists> + <#assign home=companyhome.childByNamePath[path[(chLen+2)..]]> + <#else> + <#assign home=userhome> + + <#else> + <#assign home=userhome> + +<#else> + <#assign query=args.q> + + + + + + + + + + + + +
+ + + + + + + + + +
All ItemsWord DocumentsHTML DocumentsPDF DocumentsRecently Modified + Refresh +
+
+
+ + +
+
+
+
+ <#-- populated via an AJAX call to 'doclistpanel' webscript --> + <#-- resolved path, filter and home.noderef required as arguments --> + +
+
+
+
+
+
+
+ Showing 0 items(s) +
+
+ + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/doclistpanel.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/portlets/doclistpanel.get.desc.xml new file mode 100644 index 0000000000..957e30b2bd --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/doclistpanel.get.desc.xml @@ -0,0 +1,7 @@ + + Document List Panel + Generate the inner panel for the Document List portlet page + /ui/doclistpanel?f={filter}&p={path}&h={home};q={query?} + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/doclistpanel.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/portlets/doclistpanel.get.html.ftl new file mode 100644 index 0000000000..ad36b534b2 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/doclistpanel.get.html.ftl @@ -0,0 +1,53 @@ +<#assign weekms=1000*60*60*24*7> +<#assign count=0> +<#-- get the filter mode from the passed in args --> +<#-- filters: 0=all, 1=word, 2=html, 3=pdf, 4=recent --> +<#if args.f?exists && args.f?length!=0><#assign filter=args.f?number><#else><#assign filter=0> +<#if args.h?exists> + <#assign docs=companyhome.nodeByReference[args.h].children?sort_by('name')> +<#else> + <#assign docs=companyhome.childrenByLuceneSearch[args.q]?sort_by('name')> + +<#list docs as d> + <#if d.isDocument> + <#if (filter=0) || + (filter=1 && d.mimetype="application/msword") || + (filter=2 && d.mimetype="text/html") || + (filter=3 && d.mimetype="application/pdf") || + (filter=4 && (dateCompare(d.properties["cm:modified"],date,weekms) == 1 || dateCompare(d.properties["cm:created"], date, weekms) == 1))> + <#assign count=count+1> +
+
+ +
+
+
+ ${d.name?html} + + + +
+
+ + + + + + +
+ Description: 
+ Modified: 
+ Modified By:  +
  + Created: 
+ Created By: 
+ Size:  +
+
+
+
+ + + +<#-- hidden div with the count value for the page --> + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/myspaces.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/portlets/myspaces.get.desc.xml new file mode 100644 index 0000000000..7883bca178 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/myspaces.get.desc.xml @@ -0,0 +1,7 @@ + + My Spaces + Generate the My Spaces portlet page + /ui/myspaces?f={filter?}&p={path?} + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/myspaces.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/portlets/myspaces.get.html.ftl new file mode 100644 index 0000000000..7714e9125e --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/myspaces.get.html.ftl @@ -0,0 +1,567 @@ + + + + + + + + + + + + +<#-- get the filter mode from the passed in args --> +<#-- filters: 0=all, 1=spaces, 2=docs, 3=mine, 4=recent --> +<#if args.f?exists && args.f?length!=0><#assign filter=args.f?number><#else><#assign filter=0> + +<#-- get the path location from the passed in args, remove trailing slash --> +<#if args.p?exists><#assign path=args.p><#else><#assign path=""> +<#if path?ends_with("/")><#assign path=path[0..path?length-2]> +<#-- resolve the path (from Company Home) into a node or fall back to userhome--> +<#assign chLen=companyhome.name?length> +<#if path?starts_with("/" + companyhome.name)> + <#if path?length=chLen+1> + <#assign home=companyhome> + <#elseif companyhome.childByNamePath[path[(chLen+2)..]]?exists> + <#assign home=companyhome.childByNamePath[path[(chLen+2)..]]> + <#else> + <#assign home=userhome> + +<#else> + <#assign home=userhome> + +<#assign path=home.displayPath + "/" + home.name> + +
+
+ <#-- construct breadcrumb elements as links --> + <#assign bcpath="/"> + <#assign crumbs=path?split("/")> + <#list crumbs as c> + <#if c?length != 0> + <#assign bcpath=bcpath+c+"/"> + ${c} + <#if c_index < (crumbs?size - 1)> >  + + +
+
+ <#-- TODO: permission checks on the actions! --> + <#-- Upload File action --> +
onclick="MySpaces.upload(this);">Upload
+
+ <#-- Url encode the path value, and encode any single quotes to generate valid string --> + + +
+
+ + +
+ <#-- Create Space action --> +
onclick="MySpaces.createSpace(this);">Create Space
+
+ + + + +
Name:
Title:
Description:
+ + +
+
+ +
+
+
+ <#-- populated via an AJAX call to 'myspacespanel' webscript --> + <#-- resolved path, filter and home.noderef required as arguments --> + +
+
+
+
+
+
+ <#-- the count value is retrieved and set dynamically from the AJAX webscript output above --> + Showing 0 items(s) +
+
+ + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/myspacespanel.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/portlets/myspacespanel.get.desc.xml new file mode 100644 index 0000000000..7f8f42e2f9 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/myspacespanel.get.desc.xml @@ -0,0 +1,7 @@ + + My Spaces Panel + Generate the inner panel for the My Spaces portlet page + /ui/myspacespanel?f={filter}&p={path}&h={home} + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/myspacespanel.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/portlets/myspacespanel.get.html.ftl new file mode 100644 index 0000000000..3edff59fd7 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/myspacespanel.get.html.ftl @@ -0,0 +1,61 @@ +<#assign user=person.properties.userName> +<#assign count=0> +<#assign weekms=1000*60*60*24*7> +<#function encodepath node> +<#if node.parent?exists><#return encodepath(node.parent) + "/" + node.name?url><#else><#return ""> + +<#list companyhome.nodeByReference[args.h].children?sort_by('name') as d> + <#if (d.isDocument || + (d.type != "{http://www.alfresco.org/model/forum/1.0}forums" && + d.type != "{http://www.alfresco.org/model/wcmappmodel/1.0}webfolder" && + d.type != "{http://www.alfresco.org/model/content/1.0}systemfolder")) && + ((args.f="0") || + (args.f="1" && !d.isDocument) || + (args.f="2" && d.isDocument) || + (args.f="3" && (d.properties.creator == user || d.properties.modifier == user)) || + (args.f="4" && (dateCompare(d.properties["cm:modified"],date,weekms) == 1 || dateCompare(d.properties["cm:created"], date, weekms) == 1)))> + <#assign count=count+1> +
+
+ <#if d.isDocument> + + <#elseif d.type="{http://www.alfresco.org/model/application/1.0}folderlink"> + <#-- the component parts need to build up an encoded url to the outer webscript --> + <#-- the client-side url encoder method of the outer webscript runtime will be used --> + ${url.serviceContext}/ui/myspaces?f=${args.f}&p=${encodepath(d.properties.destination)} + + <#else> + ${url.serviceContext}/ui/myspaces?f=${args.f}&p=${args.p?url}%2F${d.name?url} + + +
+
+
+ ${d.name?html} + + + +
+
+ + + + + + +
+ Description: 
+ Modified: 
+ Modified By:  +
  + Created: 
+ Created By: 
+ Size:  +
+
+
+
+ + +<#-- hidden div with the count value for the page --> + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/mytasks.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/portlets/mytasks.get.desc.xml new file mode 100644 index 0000000000..248b09b1af --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/mytasks.get.desc.xml @@ -0,0 +1,7 @@ + + My Tasks + Generate the My Tasks portlet page + /ui/mytasks?f={filter?} + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/mytasks.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/portlets/mytasks.get.html.ftl new file mode 100644 index 0000000000..47143de0ec --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/mytasks.get.html.ftl @@ -0,0 +1,483 @@ + + + + + + + + + + + + +<#-- get the filter mode from the passed in args --> +<#-- filters: 0=all, 1=today, 2=next week, 3=no due date, 4=overdue --> +<#if args.f?exists && args.f?length!=0><#assign filter=args.f?number><#else><#assign filter=0> + + + + + + + +
  + + + + + + + + + + +
+ + + + + +
+
+ +
+
+ Refresh +
+
+
+
+ <#-- populated via an AJAX call to 'mytaskspanel' webscript --> + <#-- resolved filter required as argument --> + +
+
+
+ <#-- the count value is retrieved and set dynamically from the AJAX webscript output above --> + Showing 0 <#if filter=4>overdue task(s)<#if filter=1> due today<#if filter=2> due next week<#if filter=3> with no due date set +
+
+
 
+
+
+
+
+
+ + + +
+ + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/mytaskspanel.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/portlets/mytaskspanel.get.desc.xml new file mode 100644 index 0000000000..dc838f5668 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/mytaskspanel.get.desc.xml @@ -0,0 +1,7 @@ + + My Tasks Panel + Generate the Generate the inner panel for the My Tasks portlet page + /ui/mytaskspanel?f={filter?} + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/mytaskspanel.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/portlets/mytaskspanel.get.html.ftl new file mode 100644 index 0000000000..4d7c01ec54 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/mytaskspanel.get.html.ftl @@ -0,0 +1,102 @@ +<#assign weekms=1000*60*60*24*7> +<#assign count=0> +<#list workflow.assignedTasks as t> + <#-- TODO: is it better to use a js script to pre-filter the list? --> + <#assign hasDue=t.properties["bpm:dueDate"]?exists> + <#if hasDue> + <#assign due=t.properties["bpm:dueDate"]> + + <#-- filters: 0=all, 1=today, 2=next week, 3=no due date, 4=overdue --> + <#if (args.f="0") || + (args.f="3" && !hasDue) || + (args.f="1" && hasDue && (dateCompare(date?date, due?date, 0, "==") == 1)) || + (args.f="2" && hasDue && (dateCompare(due?date, date?date) == 1 && dateCompare(date?date, due?date, weekms) == 1)) || + (args.f="4" && hasDue && (dateCompare(date?date, due?date) == 1))> + <#assign count=count+1> +
99999999999999"> +
+
+ <#if hasDue> + <#-- items due today? --> + <#if (args.f="0" || args.f="1") && (dateCompare(date?date, due?date, 0, "==") == 1)> +
+ <#-- items overdue? --> + <#elseif (args.f="0" || args.f="4") && (dateCompare(date?date, due?date) == 1)> +
+ <#else> +
+ + <#else> +
+ + <#if t.description?exists> + ${t.description?html} (${t.type?html}) + <#else> + ${t.type?html} (${t.type?html}) + + <#if hasDue> + (Due: ${due?date}) + + + + +
+
+
+
+ + + + + + + + + + + + + +
+ + + + + +
Status:
Priority:
Start Date:
Complete:
+
  +
${t.name?html}:
+
+
  + + + + +
+
+ +
+
+
  + + + + +
+
+ +
+
+
 
+
+
+ + +<#-- hidden div with the count value for the page --> + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/mywebfiles.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/portlets/mywebfiles.get.desc.xml new file mode 100644 index 0000000000..d4fde54292 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/mywebfiles.get.desc.xml @@ -0,0 +1,7 @@ + + My Web Modified Files + Generate the My Web Modified Files portlet page + /ui/mywebfiles + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/mywebfiles.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/portlets/mywebfiles.get.html.ftl new file mode 100644 index 0000000000..7011d4cd23 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/mywebfiles.get.html.ftl @@ -0,0 +1,271 @@ + + + + + + + + + + + + +<#-- List the user modified files in all web projects the user is assigned to --> + + + + + + +
+
+ <#assign filecount=0> + <#assign projectcount=0> + <#assign search="TYPE:\"{http://www.alfresco.org/model/wcmappmodel/1.0}webfolder\""> + <#list companyhome.childrenByLuceneSearch[search]?sort_by('name') as wp> + <#list wp.childAssocs["wca:webuser"] as user> + <#if user.properties["wca:username"] = person.properties.userName> + <#assign projectcount=projectcount+1> + <#-- construct the sandbox name based on the webproject and current username --> + <#assign storeId=wp.properties["wca:avmstore"]> + <#assign username=person.properties.userName> + <#assign sandbox=avm.userSandboxStore(storeId, username)> + <#if avm.lookupStore(sandbox)?exists> +
+
+ ${wp.name} + + + + View Web Project + <#if wp.properties.description?exists && wp.properties.description?length!=0> +
+ ${wp.properties.description} + +
+
<#-- marker class for dynamic click script --> + <#assign moditems = avm.getModifiedItems(storeId, username, wp.properties["wca:defaultwebapp"])> +
My Modified Items
+
+ <#if moditems?size != 0> + <#assign lcount=0> + <#list moditems as t> + <#assign filecount=filecount+1> +
+ <#if t.isDocument> + ${t.name?html} + <#else> + ${t.name?html} + + + <#if t.isDocument> + <#if t.isLocked> + + + <#if t.hasAspect("wca:forminstancedata") && !t.hasAspect("wcmwf:submitted") && t.hasLockAccess> + Edit + + + <#assign lcount=lcount+1> +
+ + <#else> +
No items modified
+ +
+
+
+ + + + +
+
+
+ Showing ${filecount} files(s) in ${projectcount} web project(s) +
+
+ + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/mywebforms.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/portlets/mywebforms.get.desc.xml new file mode 100644 index 0000000000..bc22ee7820 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/mywebforms.get.desc.xml @@ -0,0 +1,7 @@ + + My Web Forms + Generate the My Web Forms portlet page + /ui/mywebforms + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/mywebforms.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/portlets/mywebforms.get.html.ftl new file mode 100644 index 0000000000..f5624471fd --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/mywebforms.get.html.ftl @@ -0,0 +1,196 @@ + + + + + + + + + + + + +<#-- List the available web form objects in all web projects the user is assigned to --> + + + + + + +
+
+ <#assign formcount=0> + <#assign projectcount=0> + <#assign search="TYPE:\"{http://www.alfresco.org/model/wcmappmodel/1.0}webfolder\""> + <#list companyhome.childrenByLuceneSearch[search]?sort_by('name') as wp> + <#list wp.childAssocs["wca:webuser"] as user> + <#if user.properties["wca:username"] = person.properties.userName> + <#assign projectcount=projectcount+1> + <#-- construct the sandbox name based on the webproject and current username --> + <#assign storeId=wp.properties["wca:avmstore"]> + <#assign username=person.properties.userName> + <#assign sandbox=avm.userSandboxStore(storeId, username)> + <#if avm.lookupStore(sandbox)?exists> +
+
+ ${wp.name} + + + + View Web Project + <#if wp.properties.description?exists && wp.properties.description?length!=0> +
+ ${wp.properties.description} + +
+
<#-- marker class for rollover script --> + <#if wp.childAssocs["wca:webform"]?exists> +
+ <#list wp.childAssocs["wca:webform"] as form> + <#assign formcount=formcount+1> +
+ + ${form.properties.title} + <#if (form.properties.description?exists) && (form.properties.description?length!=0)> + (${form.properties.description}) + +
+ + +
+
+ + + + +
+
+
+ Showing ${formcount} form(s) in ${projectcount} web project(s) +
+
+ + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/login.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/login.get.desc.xml new file mode 100644 index 0000000000..ba0dd31b19 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/login.get.desc.xml @@ -0,0 +1,8 @@ + + Login + Establish a ticket + /api/login?u={username}&pw={password?} + + none + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/login.get.xml.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/login.get.xml.ftl new file mode 100644 index 0000000000..d311e170fd --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/login.get.xml.ftl @@ -0,0 +1,2 @@ + +${ticket} diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/loginticket.delete.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/loginticket.delete.desc.xml new file mode 100644 index 0000000000..ec244e7a39 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/loginticket.delete.desc.xml @@ -0,0 +1,8 @@ + + Delete Login Ticket + Delete Login Ticket + /api/login/ticket/{ticket} + + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/loginticket.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/loginticket.get.desc.xml new file mode 100644 index 0000000000..7329ba1f4e --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/loginticket.get.desc.xml @@ -0,0 +1,8 @@ + + Get Login Ticket + Get Login Ticket + /api/login/ticket/{ticket} + + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/loginticket.get.xml.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/loginticket.get.xml.ftl new file mode 100644 index 0000000000..d311e170fd --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/loginticket.get.xml.ftl @@ -0,0 +1,2 @@ + +${ticket} diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.atom.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.atom.ftl new file mode 100644 index 0000000000..0bddfbcdca --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.atom.ftl @@ -0,0 +1,41 @@ + + + Alfresco (${server.edition}) + Alfresco Keyword Search: ${search.searchTerms} + ${xmldate(date)} + ${absurl(url.context)}/images/logo/AlfrescoLogo16.ico + + <#if person??>${person.properties.userName}<#else>unknown + + urn:uuid:${search.id} + ${search.totalResults} + ${search.startIndex} + ${search.itemsPerPage} + + + +<#if search.startPage > 1> + + + +<#if search.startPage < search.totalPages> + + + + +<#list search.results as row> + + ${row.name} + + ${absurl(url.context)}${row.icon16} <#comment>TODO: What's the standard for entry icons? + urn:uuid:${row.id} + ${row.nodeRef} + ${xmldate(row.properties.modified)} + ${row.properties.description!""} + + ${row.properties.creator} + + ${row.score} + + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.desc.xml new file mode 100644 index 0000000000..3e76e68de9 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.desc.xml @@ -0,0 +1,12 @@ + + Alfresco Keyword Search (OpenSearch Enabled) + Execute Keyword Search against Alfresco Repository (Company Home and below) + /api/search/keyword.html?q={searchTerms}&p={startPage?}&c={count?}&l={language?} + /search/keyword.html?q={searchTerms}&p={startPage?}&c={count?}&l={language?} + /api/search/keyword.atom?q={searchTerms}&p={startPage?}&c={count?}&l={language?} + /search/keyword.atom?q={searchTerms}&p={startPage?}&c={count?}&l={language?} + /api/search/keyword.rss?q={searchTerms}&p={startPage?}&c={count?}&l={language?} + /search/keyword.rss?q={searchTerms}&p={startPage?}&c={count?}&l={language?} + /api/search/keyword.portlet?q={searchTerms}&p={startPage?}&c={count?}&l={language?} + guest + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.html.ftl new file mode 100644 index 0000000000..f2a7c0acac --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.html.ftl @@ -0,0 +1,54 @@ + + + + + Alfresco Keyword Search: ${search.searchTerms} + + + + + + + + + + + + +
AlfrescoAlfresco Keyword Search
+
+ + + + +
Results ${search.startIndex} - <#if search.startIndex == 0>0<#else>${search.startIndex + search.totalPageItems - 1} of ${search.totalResults} for ${search.searchTerms} visible to user <#if person??>${person.properties.userName}<#else>unknown.
+
+ +<#list search.results as row> + + + + <#if row.properties.description?? == true> + + + + + + +
${row.name}
${row.properties.description}
+
+ + + +<#if search.startPage > 1> + + + +<#if search.startPage < search.totalPages> + + + + +
firstprevious${search.startPage}nextlast
+ + diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.portlet.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.portlet.ftl new file mode 100644 index 0000000000..7ef3004391 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.portlet.ftl @@ -0,0 +1,33 @@ + + + + +
Results ${search.startIndex} - ${search.startIndex + search.totalPageItems - 1} of ${search.totalResults} for ${search.searchTerms} visible to user <#if person??>${person.properties.userName}<#else>unknown.
+
+ +<#list search.results as row> + + + + <#if row.properties.description?? == true> + + + + + + +
${row.name}
${row.properties.description}
+
+ + + +<#if search.startPage > 1> + + + +<#if search.startPage < search.totalPages> + + + + +
firstprevious${search.startPage}nextlast
\ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.query_.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.query_.ftl new file mode 100644 index 0000000000..f86c337d17 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.query_.ftl @@ -0,0 +1,11 @@ +( + TYPE:"{http://www.alfresco.org/model/content/1.0}content" AND + ( +<#list 1..terms?size as i> + @\{http\://www.alfresco.org/model/content/1.0\}name:${terms[i - 1]} + +<#list 1..terms?size as i> + TEXT:${terms[i - 1]} + + ) +) \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.rss.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.rss.ftl new file mode 100644 index 0000000000..25d1c2e585 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearch.get.rss.ftl @@ -0,0 +1,41 @@ + + + + Alfresco Keyword Search: ${search.searchTerms} + ${absurl(scripturl("?q=${search.searchTerms?url}&p=${search.startPage}&c=${search.itemsPerPage}&l=${search.localeId}")?xml)}" + Alfresco Keyword Search: ${search.searchTerms} + ${search.localeId} + ${xmldate(date)} + ${xmldate(date)} + Alfresco ${server.edition} v${server.version} + + Alfresco Search: ${search.searchTerms} + 16 + 16 + ${absurl(url.context)}/images/logo/AlfrescoLogo16.ico)} + + ${search.totalResults} + ${search.startIndex} + ${search.itemsPerPage} + + +<#if search.startPage > 1> + + + +<#if search.startPage < search.totalPages> + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearchdescription.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearchdescription.get.desc.xml new file mode 100644 index 0000000000..24cb2de83b --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearchdescription.get.desc.xml @@ -0,0 +1,7 @@ + + Keyword Search Description + OpenSearch description document for Alfresco Repository keyword search + /api/search/keyword/description.xml + /search/keyword/description.xml + argument + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearchdescription.get.opensearchdescription.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearchdescription.get.opensearchdescription.ftl new file mode 100644 index 0000000000..6033f249a8 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/keywordsearchdescription.get.opensearchdescription.ftl @@ -0,0 +1,11 @@ + + + Alfresco Keyword Search + Alfresco ${server.edition} Keyword Search ${server.version} + Search Alfresco "company home" using keywords + <#comment>IE takes first template from list, thus html response is listed first + + + + ${absurl(url.context)}/images/logo/AlfrescoLogo16.ico + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.atom.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.atom.ftl new file mode 100644 index 0000000000..daaae03e6f --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.atom.ftl @@ -0,0 +1,46 @@ + + + Alfresco (${server.edition}) + Alfresco Person Search: ${search.searchTerms} + ${xmldate(date)} + ${absurl(url.context)}/images/logo/AlfrescoLogo16.ico + + <#if person??>${person.properties.userName}<#else>unknown + + urn:uuid:${search.id} + ${search.totalResults} + ${search.startIndex} + ${search.itemsPerPage} + + + +<#if search.startPage > 1> + + + +<#if search.startPage < search.totalPages> + + + + +<#list search.results as row> + + ${row.properties.firstName} ${row.properties.lastName} + +<#if row.assocs["cm:avatar"]?exists> + ${absurl(url.context)}${row.assocs["cm:avatar"][0].url} +<#else> + ${absurl(url.context)}/images/icons/user_large.gif + + urn:uuid:${row.id} + ${xmldate(row.properties.modified)} + + <#if row.properties.jobtitle??>${row.properties.jobtitle}, + <#if row.properties.organization??>${row.properties.organization}, + <#if row.properties.location??>${row.properties.location}, + <#if row.properties.persondescription??>${row.properties.persondescription.content} + + ${row.score} + + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.desc.xml new file mode 100644 index 0000000000..ad18288e88 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.desc.xml @@ -0,0 +1,12 @@ + + Alfresco Person Search (OpenSearch Enabled) + Execute Person Search against Alfresco Repository + /api/search/person.html?q={searchTerms}&p={startPage?}&c={count?}&l={language?} + /search/person.html?q={searchTerms}&p={startPage?}&c={count?}&l={language?} + /api/search/person.atom?q={searchTerms}&p={startPage?}&c={count?}&l={language?} + /search/person.atom?q={searchTerms}&p={startPage?}&c={count?}&l={language?} + /api/search/person.rss?q={searchTerms}&p={startPage?}&c={count?}&l={language?} + /search/person.rss?q={searchTerms}&p={startPage?}&c={count?}&l={language?} + /api/search/person.portlet?q={searchTerms}&p={startPage?}&c={count?}&l={language?} + guest + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.html.ftl new file mode 100644 index 0000000000..4bc6803cfd --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.html.ftl @@ -0,0 +1,55 @@ + + + Alfresco Person Search: ${search.searchTerms} + + + + + + + + + + + + +
AlfrescoAlfresco Person Search
+
+ + + + +
Results ${search.startIndex} - <#if search.startIndex == 0>0<#else>${search.startIndex + search.totalPageItems - 1} of ${search.totalResults} for ${search.searchTerms} visible to user <#if person??>${person.properties.userName}<#else>unknown.
+
+ +<#list search.results as row> + + + + + + + + +
${row.firstName} ${row.lastName}
+ <#if row.properties.jobtitle??>${row.properties.jobtitle}, + <#if row.properties.organization??>${row.properties.organization}, + <#if row.properties.location??>${row.properties.location}, + <#if row.properties.persondescription??>${row.properties.persondescription.content} +
+
+ + + +<#if search.startPage > 1> + + + +<#if search.startPage < search.totalPages> + + + + +
firstprevious${search.startPage}nextlast
+ + diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.portlet.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.portlet.ftl new file mode 100644 index 0000000000..5ef6ccd3c5 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.portlet.ftl @@ -0,0 +1,36 @@ + + + + +
Results ${search.startIndex} - ${search.startIndex + search.totalPageItems - 1} of ${search.totalResults} for ${search.searchTerms} visible to user <#if person??>${person.properties.userName}<#else>unknown.
+
+ +<#list search.results as row> + + + + + + + + +
${row.firstName} ${row.lastName}
+ <#if row.properties.jobtitle??>${row.properties.jobtitle}, + <#if row.properties.organization??>${row.properties.organization}, + <#if row.properties.location??>${row.properties.location}, + <#if row.properties.persondescription??>${row.properties.persondescription.content} +
+
+ + + +<#if search.startPage > 1> + + + +<#if search.startPage < search.totalPages> + + + + +
firstprevious${search.startPage}nextlast
\ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.query_.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.query_.ftl new file mode 100644 index 0000000000..c5874458e9 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.query_.ftl @@ -0,0 +1,11 @@ +( + TYPE:"{http://www.alfresco.org/model/content/1.0}person" AND + ( +<#list 1..terms?size as i> + d\:content:${terms[i - 1]} + +<#list 1..terms?size as i> + d\:text:${terms[i - 1]} + + ) +) \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.rss.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.rss.ftl new file mode 100644 index 0000000000..729c7aa9b5 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearch.get.rss.ftl @@ -0,0 +1,46 @@ + + + + Alfresco Person Search: ${search.searchTerms} + ${absurl(scripturl("?q=${search.searchTerms?url}&p=${search.startPage}&c=${search.itemsPerPage}&l=${search.localeId}")?xml)}" + Alfresco Person Search: ${search.searchTerms} + ${search.localeId} + ${xmldate(date)} + ${xmldate(date)} + Alfresco ${server.edition} v${server.version} + + Alfresco Search: ${search.searchTerms} + 16 + 16 + ${absurl(url.context)}/images/logo/AlfrescoLogo16.ico)} + + ${search.totalResults} + ${search.startIndex} + ${search.itemsPerPage} + + +<#if search.startPage > 1> + + + +<#if search.startPage < search.totalPages> + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearchdescription.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearchdescription.get.desc.xml new file mode 100644 index 0000000000..a94cb0b62a --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearchdescription.get.desc.xml @@ -0,0 +1,7 @@ + + Person Search Description + OpenSearch description document for Alfresco Repository person search + /api/search/person/description.xml + /search/person/description.xml + argument + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearchdescription.get.opensearchdescription.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearchdescription.get.opensearchdescription.ftl new file mode 100644 index 0000000000..68da921b5a --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/personsearchdescription.get.opensearchdescription.ftl @@ -0,0 +1,11 @@ + + + Alfresco Person Search + Alfresco ${server.edition} Person Search ${server.version} + Search Alfresco People using keywords + <#comment>IE takes first template from list, thus html response is listed first + + + + ${absurl(url.context)}/images/logo/AlfrescoLogo16.ico + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/searchengines.get.atom.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/search/searchengines.get.atom.ftl new file mode 100644 index 0000000000..b5844d80d6 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/searchengines.get.atom.ftl @@ -0,0 +1,20 @@ + + + Alfresco (${server.edition}) + Registered Search Engines + ${xmldate(date)} + ${absurl(url.context)}/images/logo/AlfrescoLogo16.ico + + <#if person??>${person.properties.userName}<#else>unknown + + ${absurl(url.full)?xml} +<#list engines as engine> + + ${engine.label} + + <#if engine.urlType == "description">OpenSearch Description<#else>Template URL - ${engine.type} + ${absurl(url.serviceContext)}${engine.url?xml} + ${xmldate(date)} + + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/searchengines.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/search/searchengines.get.desc.xml new file mode 100644 index 0000000000..8cb46a5e5e --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/searchengines.get.desc.xml @@ -0,0 +1,8 @@ + + Search Engines + Lists "search engines" registered with this Alfresco Repository + /api/search/engines?type={type?} + /search/engines?type={type?} + /api/search/engines.atom?type={type?} + /search/engines.atom?type={type?} + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/searchengines.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/search/searchengines.get.html.ftl new file mode 100644 index 0000000000..6272df1394 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/searchengines.get.html.ftl @@ -0,0 +1,32 @@ + + + + + + Alfresco Registered Search Engines +<#list engines as engine> +<#if engine.urlType == "description"> + + + + + + + + + + +
AlfrescoAlfresco Registered Search Engines
+
+ + +<#list engines as engine> + + + +
EngineURL TypeResponse Format
${engine.label} + <#if engine.urlType == "description">OpenSearch Description<#else>Template URL + ${engine.type} +
+ + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/search/searchproxy.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/search/searchproxy.get.desc.xml new file mode 100644 index 0000000000..8db1f02538 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/search/searchproxy.get.desc.xml @@ -0,0 +1,7 @@ + + Proxied (OpenSearch) Search + Search engine proxy for issuing a search against a remote search engine + /api/search/engine/{engine}/{format} + /search/engine/{engine}/{format} + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.get.desc.xml new file mode 100644 index 0000000000..ebf171a777 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.get.desc.xml @@ -0,0 +1,8 @@ + + Sites + Get a colleciton of the sites in the repository. The collection can be filtered by name and/or site preset. + /api/sites?nf={namefilter?}&spf={sitepresetfilter?} + + guest + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.get.js new file mode 100644 index 0000000000..5a7f273ce6 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.get.js @@ -0,0 +1,9 @@ +// Get the filter parameters +var nameFilter = args["namefilter"]; +var sitePreset = args["sitepresetfilter"]; + +// Get the list of sites +var sites = siteService.listSites(nameFilter, sitePreset); + +// Pass the queried sites to the template +model.sites = sites; \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.get.json.ftl new file mode 100644 index 0000000000..77a270c2ad --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.get.json.ftl @@ -0,0 +1,14 @@ +<#assign first = true/> +[ + <#list sites as site> + <#if first == true><#assign first = false/><#else>, + { + "url" : "${url.serviceContext}/api/sites/${site.shortName}", + "sitePreset" : "${site.sitePreset}", + "shortName" : "${site.shortName}", + "title" : "${site.title}", + "description" : "${site.description}", + "isPublic" : ${site.isPublic?string("true", "false")} + } + +] \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.post.desc.xml new file mode 100644 index 0000000000..e91bf752a4 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.post.desc.xml @@ -0,0 +1,8 @@ + + Sites + Creates a new site based on the site preset and details provided. + /api/sites + + guest + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.post.js b/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.post.js new file mode 100644 index 0000000000..9f3cd4a594 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.post.js @@ -0,0 +1,12 @@ +// Get the details of the site +var shortName = json.get("shortName"); +var sitePreset = json.get("sitePreset"); +var title = json.get("title"); +var description = json.get("description"); +var isPublic = json.getBoolean("isPublic"); + +// Create the site +var site = siteService.createSite(sitePreset, shortName, title, description, isPublic); + +// Put the created site into the model +model["site"] = site; \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.post.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.post.json.ftl new file mode 100644 index 0000000000..428223ce33 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/site/sites.post.json.ftl @@ -0,0 +1,8 @@ +{ + "url" : "${url.serviceContext}/api/sites/${site.shortName}", + "sitePreset" : "${site.sitePreset}", + "shortName" : "${site.shortName}", + "title" : "${site.title}", + "description" : "${site.description}", + "isPublic" : ${site.isPublic?string("true", "false")} +} \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/content.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/store/content.get.desc.xml new file mode 100644 index 0000000000..3eae36fdaf --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/content.get.desc.xml @@ -0,0 +1,9 @@ + + Content Retrieval + Stream a content property from the Repository + /api/node/content{property}/{store_type}/{store_id}/{node_id}?a={attach?} + /api/path/content{property}/{store_type}/{store_id}/{path}?a={attach?} + /api/avmpath/content{property}/{store_id}/{path}?a={attach?} + guest + argument + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteavm.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteavm.get.desc.xml new file mode 100644 index 0000000000..c07506f5b0 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteavm.get.desc.xml @@ -0,0 +1,7 @@ + + Remote AVM Store + Remote service mirroring the Store interface - to an AVM store + /remotestore/{method}/{path} + none + argument + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteavm.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteavm.post.desc.xml new file mode 100644 index 0000000000..c07506f5b0 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteavm.post.desc.xml @@ -0,0 +1,7 @@ + + Remote AVM Store + Remote service mirroring the Store interface - to an AVM store + /remotestore/{method}/{path} + none + argument + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/doclist.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/doclist.get.desc.xml new file mode 100644 index 0000000000..8e5520e096 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/doclist.get.desc.xml @@ -0,0 +1,7 @@ + + doclist + Document List Component - doclist data webscript + /slingshot/doclib/doclist?nodeRef={nodeRef?}&path={path?} + guest + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/doclist.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/doclist.get.html.ftl new file mode 100644 index 0000000000..d425124312 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/doclist.get.html.ftl @@ -0,0 +1,24 @@ +{ + "doclist": + { +<#if doclist.error?exists> + "error": "${doclist.error}" +<#else> + "items": + [ + <#list doclist.items as d> + { + "nodeRef": "${d.nodeRef}", + "type": "<#if d.isContainer>folder<#else>document", + "icon16": "${d.icon16}", + "icon32": "${d.icon32}", + "name": "${d.name}", + "status": "", + "description": "${d.description!""}" + } + <#if d_has_next>, + + ] + + } +} \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/doclist.get.js b/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/doclist.get.js new file mode 100644 index 0000000000..09d8283040 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/doclist.get.js @@ -0,0 +1,76 @@ +/* + * doclist + * + * Inputs: + * mandatory: nodeRef = parent space nodeRef + * + * Outputs: + * doclist - object containing list of child folders and documents in the parent space + */ +model.doclist = getDoclist(args["nodeRef"], args["path"], args["type"]); + +/* Create collection of documents and folders in the given space */ +function getDoclist(nodeRef, path, type) +{ + var items = new Array(); + + /* nodeRef input */ + var parentSpace = null; + if ((nodeRef != null) && (nodeRef != "")) + { + parentSpace = search.findNode(nodeRef); + } + else if ((path != null) && path != "") + { + parentSpace = companyhome.childByNamePath(path); + } + if (parentSpace == null) + { + // return jsonError("Parent space nodeRef not supplied"); + parentSpace = companyhome; + } + + var showDocs = true, + showFolders = true; + + if ((type != null) && (type != "")) + { + showDocs = (type == "documents"); + showFolders = (type == "folders"); + } + + for each(item in parentSpace.children) + { + if ((item.isContainer && showFolders) || (!item.isContainer && showDocs)) + { + items.push(item); + } + } + + items.sort(sortByType); + + return ({ + "items": items + }); +} + + +/* Format and return error object */ +function jsonError(errorString) +{ + var obj = + { + "error": errorString + }; + + return obj; +} + +function sortByType(a, b) +{ + if (a.isContainer == b.isContainer) + { + return (b.name.toLowerCase() > a.name.toLowerCase() ? -1 : 1); + } + return (a.isContainer ? -1 : 1); +} \ No newline at end of file diff --git a/config/alfresco/web-scripts-application-context-test.xml b/config/alfresco/web-scripts-application-context-test.xml new file mode 100644 index 0000000000..08b30ef95f --- /dev/null +++ b/config/alfresco/web-scripts-application-context-test.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + alfresco/messages/webscripts + + + + + + + \ No newline at end of file diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml new file mode 100644 index 0000000000..4e28829727 --- /dev/null +++ b/config/alfresco/web-scripts-application-context.xml @@ -0,0 +1,225 @@ + + + + + + + + + + + + + + classpath:alfresco/web-scripts-config.xml + classpath:alfresco/extension/web-api-config-custom.xml + classpath:alfresco/extension/web-scripts-config-custom.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + workspace://SpacesStore + /${spaces.company_home.childname}/${spaces.dictionary.childname}/cm:extensionwebscripts + + + + true + workspace://SpacesStore + /${spaces.company_home.childname}/${spaces.dictionary.childname}/cm:webscripts + + + + alfresco/extension/templates/webscripts + + + + true + alfresco/templates/webscripts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${spaces.store} + /${spaces.company_home.childname} + + + + + + + + + + + + + + + + + + Repository + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + alfresco + sitestore + + + + + + alfresco + sitestore + + + diff --git a/config/alfresco/web-scripts-config.xml b/config/alfresco/web-scripts-config.xml new file mode 100644 index 0000000000..2697bfddb0 --- /dev/null +++ b/config/alfresco/web-scripts-config.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /api/search/keyword/description.xml + + + /api/search/keyword.atom?q={searchTerms}&p={startPage?}&c={count?}&l={language?}&guest={alf:guest?} + + + /api/search/keyword.rss?q={searchTerms}&p={startPage?}&c={count?}&l={language?}&guest={alf:guest?} + + + /api/search/keyword?q={searchTerms}&p={startPage?}&c={count?}&l={language?}&guest={alf:guest?} + + + + + + /api/search/person/description.xml + + + /api/search/person.atom?q={searchTerms}&p={startPage?}&c={count?}&l={language?}&guest={alf:guest?} + + + /api/search/person.rss?q={searchTerms}&p={startPage?}&c={count?}&l={language?}&guest={alf:guest?} + + + /api/search/person?q={searchTerms}&p={startPage?}&c={count?}&l={language?}&guest={alf:guest?} + + + + + + + + /api/search/engine + + + + + + diff --git a/source/java/org/alfresco/repo/web/scripts/BaseWebScriptTest.java b/source/java/org/alfresco/repo/web/scripts/BaseWebScriptTest.java new file mode 100644 index 0000000000..7984e3a61c --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/BaseWebScriptTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts; + +import java.io.IOException; +import java.util.HashMap; + +import org.alfresco.web.scripts.TestWebScriptServer; +import org.springframework.mock.web.MockHttpServletResponse; + +import junit.framework.TestCase; + +/** + * Base unit test class for web scripts. + * + * @author Roy Wetherall + */ +public abstract class BaseWebScriptTest extends TestCase +{ + /** Standard HTTP method names */ + protected static final String METHOD_POST = "post"; + protected static final String METHOD_GET = "get"; + protected static final String METHOD_PUT = "put"; + protected static final String METHOD_DELETE = "delete"; + + /** Test web script server */ + private static TestWebScriptServer server = null; + + protected static TestWebScriptServer getServer() + { + if (BaseWebScriptTest.server == null) + { + BaseWebScriptTest.server = TestWebScriptRepoServer.getTestServer(); + } + return BaseWebScriptTest.server; + } + + /** + * "GET" the url and check for the expected status code + * + * @param url + * @param expectedStatus + * @return + * @throws IOException + */ + protected MockHttpServletResponse getRequest(String url, int expectedStatus) + throws IOException + { + return sendRequest(METHOD_GET, url, expectedStatus, null, null); + } + + /** + * "POST" the url and check for the expected status code + * + * @param url + * @param expectedStatus + * @return + * @throws IOException + */ + protected MockHttpServletResponse postRequest(String url, int expectedStatus, String body, String contentType) + throws IOException + { + return sendRequest(METHOD_POST, url, expectedStatus, body, contentType); + } + + /** + * + * @param method + * @param url + * @param expectedStatus + * @return + * @throws IOException + */ + private MockHttpServletResponse sendRequest(String method, String url, int expectedStatus, String body, String contentType) + throws IOException + { + MockHttpServletResponse response = BaseWebScriptTest.getServer().submitRequest(method, url, new HashMap(), body, contentType); + if (expectedStatus != response.getStatus()) + { + if (response.getStatus() == 500) + { + System.out.println(response.getContentAsString()); + } + fail("The expected status code (" + expectedStatus + ") was not returned."); + } + return response; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/RepoStore.java b/source/java/org/alfresco/repo/web/scripts/RepoStore.java new file mode 100644 index 0000000000..d00dde97f1 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/RepoStore.java @@ -0,0 +1,850 @@ +/* + * Copyright (C) 2005-2008 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.model.filefolder.FileFolderServiceImpl; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.tenant.TenantDeployer; +import org.alfresco.repo.tenant.TenantDeployerService; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.model.FileInfo; +import org.alfresco.service.cmr.model.FileNotFoundException; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.ContentWriter; +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.search.ResultSet; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.web.scripts.ScriptContent; +import org.alfresco.web.scripts.ScriptLoader; +import org.alfresco.web.scripts.Store; +import org.alfresco.web.scripts.WebScript; +import org.alfresco.web.scripts.WebScriptException; + +import freemarker.cache.TemplateLoader; + + +/** + * Repository based Web Script Store + * + * @author davidc + */ +public class RepoStore implements Store, TenantDeployer +{ + protected boolean mustExist = false; + protected StoreRef repoStore; + protected String repoPath; + protected Map baseNodeRefs; + + // dependencies + protected RetryingTransactionHelper retryingTransactionHelper; + protected SearchService searchService; + protected NodeService nodeService; + protected ContentService contentService; + protected FileFolderService fileService; + protected NamespaceService namespaceService; + protected PermissionService permissionService; + protected TenantDeployerService tenantDeployerService; + + + /** + * Sets helper that provides transaction callbacks + */ + public void setTransactionHelper(RetryingTransactionHelper retryingTransactionHelper) + { + this.retryingTransactionHelper = retryingTransactionHelper; + } + + /** + * Sets the search service + */ + public void setSearchService(SearchService searchService) + { + this.searchService = searchService; + } + + /** + * Sets the node service + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * Sets the content service + */ + public void setContentService(ContentService contentService) + { + this.contentService = contentService; + } + + /** + * Sets the file service + */ + public void setFileFolderService(FileFolderService fileService) + { + this.fileService = fileService; + } + + /** + * Sets the namespace service + */ + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + + /** + * Sets the permission service + */ + public void setPermissionService(PermissionService permissionService) + { + this.permissionService = permissionService; + } + + /** + * Sets the tenant deployer service + */ + public void setTenantDeployerService(TenantDeployerService tenantDeployerService) + { + this.tenantDeployerService = tenantDeployerService; + } + + /** + * Sets whether the repo store must exist + * + * @param mustExist + */ + public void setMustExist(boolean mustExist) + { + this.mustExist = mustExist; + } + + /** + * Sets the repo store + */ + public void setStore(String repoStore) + { + this.repoStore = new StoreRef(repoStore); + } + + /** + * Sets the repo path + * + * @param repoPath repoPath + */ + public void setPath(String repoPath) + { + this.repoPath = repoPath; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.Store#init() + * @see org.alfresco.repo.tenant.TenantDeployer#init() + */ + public void init() + { + if (baseNodeRefs == null) + { + baseNodeRefs = new HashMap(1); + } + + getBaseNodeRef(); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.tenant.TenantDeployer#destroy() + */ + public void destroy() + { + baseNodeRefs.remove(tenantDeployerService.getCurrentUserDomain()); + } + + private NodeRef getBaseNodeRef() + { + String tenantDomain = tenantDeployerService.getCurrentUserDomain(); + NodeRef baseNodeRef = baseNodeRefs.get(tenantDomain); + if (baseNodeRef == null) + { + baseNodeRef = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + { + public NodeRef doWork() throws Exception + { + return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public NodeRef execute() throws Exception + { + String query = "PATH:\"" + repoPath + "\""; + ResultSet resultSet = searchService.query(repoStore, SearchService.LANGUAGE_LUCENE, query); + if (resultSet.length() == 1) + { + return resultSet.getNodeRef(0); + } + else if (mustExist) + { + throw new WebScriptException("Web Script Store " + repoStore.toString() + repoPath + " must exist; it was not found"); + } + return null; + } + }); + } + }, AuthenticationUtil.getSystemUserName()); + + // TODO clear on deleteTenant + baseNodeRefs.put(tenantDomain, baseNodeRef); + } + return baseNodeRef; + } + + private String getBaseDir() + { + return getPath(getBaseNodeRef()); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.Store#exists() + */ + public boolean exists() + { + return (getBaseNodeRef() != null); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.Store#getBasePath() + */ + public String getBasePath() + { + return repoStore.toString() + repoPath; + } + + /** + * Gets the display path for the specified node + * + * @param nodeRef + * @return display path + */ + protected String getPath(NodeRef nodeRef) + { + return nodeService.getPath(nodeRef).toDisplayPath(nodeService, permissionService) + + "/" + nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); + } + + /** + * Gets the node ref for the specified path within this repo store + * + * @param documentPath + * @return node ref + */ + protected NodeRef findNodeRef(String documentPath) + { + NodeRef node = null; + try + { + String[] pathElements = documentPath.split("/"); + List pathElementsList = Arrays.asList(pathElements); + FileInfo file = fileService.resolveNamePath(getBaseNodeRef(), pathElementsList); + node = file.getNodeRef(); + } + catch (FileNotFoundException e) + { + // NOTE: return null + } + return node; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.Store#getScriptDocumentPaths(org.alfresco.web.scripts.WebScript) + */ + public String[] getScriptDocumentPaths(final WebScript script) + { + return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + { + public String[] doWork() throws Exception + { + return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public String[] execute() throws Exception + { + int baseDirLength = getBaseDir().length() +1; + List documentPaths = null; + String scriptPath = script.getDescription().getScriptPath(); + NodeRef scriptNodeRef = (scriptPath.length() == 0) ? getBaseNodeRef() : findNodeRef(scriptPath); + if (scriptNodeRef != null) + { + org.alfresco.service.cmr.repository.Path repoScriptPath = nodeService.getPath(scriptNodeRef); + String id = script.getDescription().getId().substring(scriptPath.length() + (scriptPath.length() > 0 ? 1 : 0)); + String query = "+PATH:\"" + repoScriptPath.toPrefixString(namespaceService) + "//*\" +QNAME:" + id + "*"; + ResultSet resultSet = searchService.query(repoStore, SearchService.LANGUAGE_LUCENE, query); + documentPaths = new ArrayList(resultSet.length()); + List nodes = resultSet.getNodeRefs(); + for (NodeRef nodeRef : nodes) + { + String name = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); + if (name.startsWith(id)) + { + String nodeDir = getPath(nodeRef); + String documentPath = nodeDir.substring(baseDirLength); + documentPaths.add(documentPath); + } + } + } + + return documentPaths != null ? documentPaths.toArray(new String[documentPaths.size()]) : new String[0]; + } + }); + } + }, AuthenticationUtil.getSystemUserName()); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.Store#getDescriptionDocumentPaths() + */ + public String[] getDescriptionDocumentPaths() + { + return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + { + public String[] doWork() throws Exception + { + return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public String[] execute() throws Exception + { + int baseDirLength = getBaseDir().length() +1; + + String query = "+PATH:\"" + repoPath + "//*\" +QNAME:*.desc.xml"; + ResultSet resultSet = searchService.query(repoStore, SearchService.LANGUAGE_LUCENE, query); + List documentPaths = new ArrayList(resultSet.length()); + List nodes = resultSet.getNodeRefs(); + for (NodeRef nodeRef : nodes) + { + String nodeDir = getPath(nodeRef); + if (nodeDir.endsWith(".desc.xml")) + { + String documentPath = nodeDir.substring(baseDirLength); + documentPaths.add(documentPath); + } + } + + return documentPaths.toArray(new String[documentPaths.size()]); + } + }); + } + }, AuthenticationUtil.getSystemUserName()); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.Store#getAllDocumentPaths() + */ + public String[] getAllDocumentPaths() + { + return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + { + public String[] doWork() throws Exception + { + return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public String[] execute() throws Exception + { + int baseDirLength = getBaseDir().length() +1; + + String query = "+PATH:\"" + repoPath + "//*\" +TYPE:\"{http://www.alfresco.org/model/content/1.0}content\""; + ResultSet resultSet = searchService.query(repoStore, SearchService.LANGUAGE_LUCENE, query); + List documentPaths = new ArrayList(resultSet.length()); + List nodes = resultSet.getNodeRefs(); + for (NodeRef nodeRef : nodes) + { + String nodeDir = getPath(nodeRef); + documentPaths.add(nodeDir.substring(baseDirLength)); + } + + return documentPaths.toArray(new String[documentPaths.size()]); + } + }); + } + }, AuthenticationUtil.getSystemUserName()); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.Store#lastModified(java.lang.String) + */ + public long lastModified(final String documentPath) throws IOException + { + return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + { + public Long doWork() throws Exception + { + return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public Long execute() throws Exception + { + ContentReader reader = contentService.getReader( + findNodeRef(documentPath), ContentModel.PROP_CONTENT); + return reader.getLastModified(); + } + }); + } + }, AuthenticationUtil.getSystemUserName()); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.Store#hasDocument(java.lang.String) + */ + public boolean hasDocument(final String documentPath) + { + return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + { + public Boolean doWork() throws Exception + { + return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public Boolean execute() throws Exception + { + NodeRef nodeRef = findNodeRef(documentPath); + return (nodeRef != null); + } + }); + } + }, AuthenticationUtil.getSystemUserName()); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.Store#getDescriptionDocument(java.lang.String) + */ + public InputStream getDocument(final String documentPath) + throws IOException + { + return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + { + public InputStream doWork() throws Exception + { + return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public InputStream execute() throws Exception + { + NodeRef nodeRef = findNodeRef(documentPath); + if (nodeRef == null) + { + throw new IOException("Document " + documentPath + " does not exist."); + } + ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT); + if (reader == null || !reader.exists()) + { + throw new IOException("Failed to read content at " + documentPath + " (content reader does not exist)"); + } + return reader.getContentInputStream(); + } + }); + } + }, AuthenticationUtil.getSystemUserName()); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.Store#createDocument(java.lang.String, java.lang.String) + */ + public void createDocument(String documentPath, String content) throws IOException + { + String[] pathElements = documentPath.split("/"); + String[] folderElements = new String[pathElements.length -1]; + System.arraycopy(pathElements, 0, folderElements, 0, pathElements.length -1); + List folderElementsList = Arrays.asList(folderElements); + + // create folder + FileInfo pathInfo; + if (folderElementsList.size() == 0) + { + pathInfo = fileService.getFileInfo(getBaseNodeRef()); + } + else + { + pathInfo = FileFolderServiceImpl.makeFolders(fileService, getBaseNodeRef(), folderElementsList, ContentModel.TYPE_FOLDER); + } + + // create file + String fileName = pathElements[pathElements.length -1]; + if (fileService.searchSimple(pathInfo.getNodeRef(), fileName) != null) + { + throw new IOException("Document " + documentPath + " already exists"); + } + FileInfo fileInfo = fileService.create(pathInfo.getNodeRef(), fileName, ContentModel.TYPE_CONTENT); + ContentWriter writer = fileService.getWriter(fileInfo.getNodeRef()); + writer.putContent(content); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.Store#updateDocument(java.lang.String, java.lang.String) + */ + public void updateDocument(String documentPath, String content) throws IOException + { + String[] pathElements = documentPath.split("/"); + + // get parent folder + NodeRef parentRef; + if (pathElements.length == 1) + { + parentRef = getBaseNodeRef(); + } + else + { + parentRef = findNodeRef(documentPath.substring(0, documentPath.lastIndexOf('/'))); + } + + // update file + String fileName = pathElements[pathElements.length -1]; + if (fileService.searchSimple(parentRef, fileName) == null) + { + throw new IOException("Document " + documentPath + " does not exists"); + } + FileInfo fileInfo = fileService.create(parentRef, fileName, ContentModel.TYPE_CONTENT); + ContentWriter writer = fileService.getWriter(fileInfo.getNodeRef()); + writer.putContent(content); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.Store#getTemplateLoader() + */ + public TemplateLoader getTemplateLoader() + { + return new RepoTemplateLoader(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.Store#getScriptLoader() + */ + public ScriptLoader getScriptLoader() + { + return new RepoScriptLoader(); + } + + + /* (non-Javadoc) + * @see org.alfresco.repo.tenant.TenantDeployer#onEnableTenant() + */ + public void onEnableTenant() + { + init(); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.tenant.TenantDeployer#onDisableTenant() + */ + public void onDisableTenant() + { + destroy(); + } + + /** + * Repository path based template loader + * + * @author davidc + */ + private class RepoTemplateLoader implements TemplateLoader + { + /* (non-Javadoc) + * @see freemarker.cache.TemplateLoader#findTemplateSource(java.lang.String) + */ + public Object findTemplateSource(final String name) + throws IOException + { + return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + { + public Object doWork() throws Exception + { + return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public Object execute() throws Exception + { + RepoTemplateSource source = null; + NodeRef nodeRef = findNodeRef(name); + if (nodeRef != null) + { + source = new RepoTemplateSource(nodeRef); + } + return source; + } + }); + } + }, AuthenticationUtil.getSystemUserName()); + } + + /* (non-Javadoc) + * @see freemarker.cache.TemplateLoader#getLastModified(java.lang.Object) + */ + public long getLastModified(Object templateSource) + { + return ((RepoTemplateSource)templateSource).lastModified(); + } + + /* (non-Javadoc) + * @see freemarker.cache.TemplateLoader#getReader(java.lang.Object, java.lang.String) + */ + public Reader getReader(Object templateSource, String encoding) throws IOException + { + return ((RepoTemplateSource)templateSource).getReader(); + } + + /* (non-Javadoc) + * @see freemarker.cache.TemplateLoader#closeTemplateSource(java.lang.Object) + */ + public void closeTemplateSource(Object arg0) throws IOException + { + } + } + + /** + * Repository (content) node template source + * + * @author davidc + */ + private class RepoTemplateSource + { + protected final NodeRef nodeRef; + + /** + * Construct + * + * @param ref + */ + private RepoTemplateSource(NodeRef ref) + { + this.nodeRef = ref; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object o) + { + if (o instanceof RepoTemplateSource) + { + return nodeRef.equals(((RepoTemplateSource)o).nodeRef); + } + else + { + return false; + } + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + public int hashCode() + { + return nodeRef.hashCode(); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() + { + return nodeRef.toString(); + } + + /** + * Gets the last modified time of the content + * + * @return last modified time + */ + public long lastModified() + { + return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + { + public Long doWork() throws Exception + { + return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public Long execute() throws Exception + { + ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT); + return reader.getLastModified(); + } + }); + } + }, AuthenticationUtil.getSystemUserName()); + } + + /** + * Gets the content reader + * + * @return content reader + * @throws IOException + */ + public Reader getReader() throws IOException + { + return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + { + public Reader doWork() throws Exception + { + return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public Reader execute() throws Exception + { + ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT); + return new InputStreamReader(reader.getContentInputStream(), reader.getEncoding()); + } + }); + } + }, AuthenticationUtil.getSystemUserName()); + } + } + + /** + * Repository path based script loader + * + * @author davidc + */ + private class RepoScriptLoader implements ScriptLoader + { + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ScriptLoader#getScriptLocation(java.lang.String) + */ + public ScriptContent getScript(final String path) + { + return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + { + public ScriptContent doWork() throws Exception + { + return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public ScriptContent execute() throws Exception + { + ScriptContent location = null; + NodeRef nodeRef = findNodeRef(path); + if (nodeRef != null) + { + location = new RepoScriptContent(path, nodeRef); + } + return location; + } + }); + } + }, AuthenticationUtil.getSystemUserName()); + } + } + + /** + * Repo path script location + * + * @author davidc + */ + private class RepoScriptContent implements ScriptContent + { + protected String path; + protected NodeRef nodeRef; + + /** + * Construct + * + * @param location + */ + public RepoScriptContent(String path, NodeRef nodeRef) + { + this.path = path; + this.nodeRef = nodeRef; + } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.repository.ScriptLocation#getInputStream() + */ + public InputStream getInputStream() + { + return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + { + public InputStream doWork() throws Exception + { + return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public InputStream execute() throws Exception + { + ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT); + return reader.getContentInputStream(); + } + }); + } + }, AuthenticationUtil.getSystemUserName()); + } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.repository.ScriptLocation#getReader() + */ + public Reader getReader() + { + ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT); + try + { + return new InputStreamReader(getInputStream(), reader.getEncoding()); + } + catch (UnsupportedEncodingException e) + { + throw new AlfrescoRuntimeException("Unsupported Encoding", e); + } + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ScriptContent#getPath() + */ + public String getPath() + { + return repoStore + getBaseDir() + "/" + path; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ScriptContent#getPathDescription() + */ + public String getPathDescription() + { + return "/" + path + " (in repository store " + repoStore.toString() + getBaseDir() + ")"; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ScriptContent#isSecure() + */ + public boolean isSecure() + { + return false; + } + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/Repository.java b/source/java/org/alfresco/repo/web/scripts/Repository.java new file mode 100644 index 0000000000..8ceb632531 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/Repository.java @@ -0,0 +1,484 @@ +/* + * Copyright (C) 2005-2008 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.avm.AVMNodeConverter; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.tenant.TenantDeployer; +import org.alfresco.repo.tenant.TenantDeployerService; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.cmr.avm.AVMNodeDescriptor; +import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.model.FileInfo; +import org.alfresco.service.cmr.model.FileNotFoundException; +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.search.SearchService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.util.AbstractLifecycleBean; +import org.alfresco.web.scripts.WebScriptException; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; + + +/** + * Provision of Repository Context + * + * @author davidc + */ +public class Repository implements ApplicationContextAware, ApplicationListener, TenantDeployer +{ + private ProcessorLifecycle lifecycle = new ProcessorLifecycle(); + + // dependencies + private RetryingTransactionHelper retryingTransactionHelper; + private NamespaceService namespaceService; + private SearchService searchService; + private NodeService nodeService; + private FileFolderService fileFolderService; + private PersonService personService; + private AVMService avmService; + private TenantDeployerService tenantDeployerService; + + // company home + private StoreRef companyHomeStore; + private String companyHomePath; + private Map companyHomeRefs; + + + /** + * Sets the Company Home Store + * + * @param companyHomeStore + */ + public void setCompanyHomeStore(String companyHomeStore) + { + this.companyHomeStore = new StoreRef(companyHomeStore); + } + + /** + * Sets the Company Home Path + * + * @param companyHomePath + */ + public void setCompanyHomePath(String companyHomePath) + { + this.companyHomePath = companyHomePath; + } + + /** + * Sets helper that provides transaction callbacks + */ + public void setTransactionHelper(RetryingTransactionHelper retryingTransactionHelper) + { + this.retryingTransactionHelper = retryingTransactionHelper; + } + + /** + * Sets the namespace service + * + * @param namespaceService + */ + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + + /** + * Sets the search service + * + * @param searchService + */ + public void setSearchService(SearchService searchService) + { + this.searchService = searchService; + } + + /** + * Sets the node service + * + * @param nodeService + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * Sets the file folder service + * + * @param nodeService + */ + public void setFileFolderService(FileFolderService fileFolderService) + { + this.fileFolderService = fileFolderService; + } + + /** + * Sets the person service + * + * @param personService + */ + public void setPersonService(PersonService personService) + { + this.personService = personService; + } + + /** + * Sets the tenant deployer service + * + * @param tenantDeployerService + */ + public void setTenantDeployerService(TenantDeployerService tenantDeployerService) + { + this.tenantDeployerService = tenantDeployerService; + } + + /** + * Sets the AVM service + * + * @param avmService + */ + public void setAvmService(AVMService avmService) + { + this.avmService = avmService; + } + + /* (non-Javadoc) + * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) + */ + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + lifecycle.setApplicationContext(applicationContext); + } + + /* (non-Javadoc) + * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) + */ + public void onApplicationEvent(ApplicationEvent event) + { + lifecycle.onApplicationEvent(event); + } + + /** + * Hooks into Spring Application Lifecycle + */ + private class ProcessorLifecycle extends AbstractLifecycleBean + { + @Override + protected void onBootstrap(ApplicationEvent event) + { + initContext(); + } + + @Override + protected void onShutdown(ApplicationEvent event) + { + } + } + + /** + * Initialise Repository Context + */ + protected void initContext() + { + tenantDeployerService.register(this); + + if (companyHomeRefs == null) + { + companyHomeRefs = new HashMap(1); + } + + getCompanyHome(); + } + + + /** + * Gets the root home of the company home store + * + * @return root node ref + */ + public NodeRef getRootHome() + { + return nodeService.getRootNode(companyHomeStore); + } + + /** + * Gets the Company Home + * + * @return company home node ref + */ + public NodeRef getCompanyHome() + { + String tenantDomain = tenantDeployerService.getCurrentUserDomain(); + NodeRef companyHomeRef = companyHomeRefs.get(tenantDomain); + if (companyHomeRef == null) + { + companyHomeRef = AuthenticationUtil.runAs(new RunAsWork() + { + public NodeRef doWork() throws Exception + { + return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public NodeRef execute() throws Exception + { + List refs = searchService.selectNodes(nodeService.getRootNode(companyHomeStore), companyHomePath, null, namespaceService, false); + if (refs.size() != 1) + { + throw new IllegalStateException("Invalid company home path: " + companyHomePath + " - found: " + refs.size()); + } + return refs.get(0); + } + }); + } + }, AuthenticationUtil.getSystemUserName()); + + companyHomeRefs.put(tenantDomain, companyHomeRef); + } + return companyHomeRef; + } + + /** + * Gets the currently authenticated person + * + * @return person node ref + */ + public NodeRef getPerson() + { + NodeRef person = null; + String currentUserName = AuthenticationUtil.getCurrentUserName(); + if (personService.personExists(currentUserName)) + { + person = personService.getPerson(currentUserName); + } + return person; + } + + /** + * Gets the user home of the currently authenticated person + * + * @param person person + * @return user home of person + */ + public NodeRef getUserHome(NodeRef person) + { + return (NodeRef)nodeService.getProperty(person, ContentModel.PROP_HOMEFOLDER); + } + + /** + * Helper to convert a Web Script Request URL to a Node Ref + * + * 1) Node - {store_type}/{store_id}/{node_id} + * + * Resolve to node via its Node Reference. + * + * 2) Path - {store_type}/{store_id}/{path} + * + * Resolve to node via its display path. + * + * 3) AVM Path - {store_id}/{path} + * + * Resolve to AVM node via its display path + * + * 4) QName - {store_type}/{store_id}/{child_qname_path} TODO: Implement + * + * Resolve to node via its child qname path. + * + * @param referenceType one of node, path, avmpath or qname + * @return reference array of reference segments (as described above for each reference type) + */ + public NodeRef findNodeRef(String referenceType, String[] reference) + { + NodeRef nodeRef = null; + + if (referenceType.equals("avmpath")) + { + if (reference.length == 0) + { + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Reference " + Arrays.toString(reference) + " is not properly formed"); + } + String path = reference[0] + ":/"; + if (reference.length > 1) + { + Object[] pathElements = ArrayUtils.subarray(reference, 1, reference.length); + path += StringUtils.join(pathElements, "/"); + } + AVMNodeDescriptor nodeDesc = avmService.lookup(-1, path); + if (nodeDesc != null) + { + nodeRef = AVMNodeConverter.ToNodeRef(-1, path); + } + } + else + { + // construct store reference + if (reference.length < 3) + { + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Reference " + Arrays.toString(reference) + " is not properly formed"); + } + StoreRef storeRef = new StoreRef(reference[0], reference[1]); + if (nodeService.exists(storeRef)) + { + if (referenceType.equals("node")) + { + // find the node the rest of the path is relative to + NodeRef relRef = new NodeRef(storeRef, reference[2]); + if (nodeService.exists(relRef)) + { + // are there any relative path elements to process? + if (reference.length == 3 || reference.length == 4) + { + // just the NodeRef can be specified + nodeRef = relRef; + } + else + { + // process optional path elements + List paths = new ArrayList(reference.length - 3); + for (int i=3; i 2) + { + Object[] pathElements = ArrayUtils.subarray(reference, 2, reference.length); + path += StringUtils.join(pathElements, "/"); + } + AVMNodeDescriptor nodeDesc = avmService.lookup(-1, path); + if (nodeDesc != null) + { + nodeRef = AVMNodeConverter.ToNodeRef(-1, path); + } + } + else + { + // TODO: Allow a root path to be specified - for now, hard-code to Company Home + //NodeRef rootNodeRef = nodeService.getRootNode(storeRef); + NodeRef rootNodeRef = getCompanyHome(); + if (reference.length == 3) + { + nodeRef = rootNodeRef; + } + else + { + String[] path = new String[reference.length - /*2*/3]; + System.arraycopy(reference, /*2*/3, path, 0, path.length); + + try + { + FileInfo fileInfo = fileFolderService.resolveNamePath(rootNodeRef, Arrays.asList(path)); + nodeRef = fileInfo.getNodeRef(); + } + catch (FileNotFoundException e) + { + // NOTE: return null node ref + } + } + } + } + + else + { + // TODO: Implement 'qname' style + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Web Script Node URL specified an invalid reference style of '" + referenceType + "'"); + } + } + } + + return nodeRef; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.tenant.TenantDeployer#onEnableTenant() + */ + public void onEnableTenant() + { + init(); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.tenant.TenantDeployer#onDisableTenant() + */ + public void onDisableTenant() + { + destroy(); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.tenant.TenantDeployer#init() + */ + public void init() + { + initContext(); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.tenant.TenantDeployer#destroy() + */ + public void destroy() + { + companyHomeRefs.remove(tenantDeployerService.getCurrentUserDomain()); + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java b/source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java new file mode 100644 index 0000000000..87dce7d53b --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2005-2008 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.repo.cache.SimpleCache; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.tenant.TenantDeployer; +import org.alfresco.repo.tenant.TenantDeployerService; +import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.TemplateService; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.descriptor.DescriptorService; +import org.alfresco.web.scripts.AbstractRuntimeContainer; +import org.alfresco.web.scripts.Authenticator; +import org.alfresco.web.scripts.Description; +import org.alfresco.web.scripts.Registry; +import org.alfresco.web.scripts.ServerModel; +import org.alfresco.web.scripts.WebScript; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.scripts.Description.RequiredAuthentication; +import org.alfresco.web.scripts.Description.RequiredTransaction; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.ObjectFactory; + + +/** + * Repository (server-tier) container for Web Scripts + * + * @author davidc + */ +public class RepositoryContainer extends AbstractRuntimeContainer implements TenantDeployer +{ + // Logger + protected static final Log logger = LogFactory.getLog(RepositoryContainer.class); + + /** Component Dependencies */ + private Repository repository; + private RepositoryImageResolver imageResolver; + private RetryingTransactionHelper retryingTransactionHelper; + private AuthorityService authorityService; + private PermissionService permissionService; + private DescriptorService descriptorService; + private TenantDeployerService tenantDeployerService; + private ObjectFactory registryFactory; + private SimpleCache webScriptsRegistryCache; + + /** + * @param webScriptsRegistryCache + */ + public void setWebScriptsRegistryCache(SimpleCache webScriptsRegistryCache) + { + this.webScriptsRegistryCache = webScriptsRegistryCache; + } + + /** + * @param registryFactory + */ + public void setRegistryFactory(ObjectFactory registryFactory) { + this.registryFactory = registryFactory; + } + + /** + * @param repository + */ + public void setRepository(Repository repository) + { + this.repository = repository; + } + + /** + * @param imageResolver + */ + public void setRepositoryImageResolver(RepositoryImageResolver imageResolver) + { + this.imageResolver = imageResolver; + } + + /** + * @param permissionService + */ + public void setPermissionService(PermissionService permissionService) + { + this.permissionService = permissionService; + } + + /** + * @param retryingTransactionHelper + */ + public void setTransactionHelper(RetryingTransactionHelper retryingTransactionHelper) + { + this.retryingTransactionHelper = retryingTransactionHelper; + } + + /** + * @param descriptorService + */ + public void setDescriptorService(DescriptorService descriptorService) + { + this.descriptorService = descriptorService; + } + + /** + * @param authorityService + */ + public void setAuthorityService(AuthorityService authorityService) + { + this.authorityService = authorityService; + } + + /** + * @param tenantDeployerService + */ + public void setTenantDeployerService(TenantDeployerService tenantDeployerService) + { + this.tenantDeployerService = tenantDeployerService; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.Container#getDescription() + */ + public ServerModel getDescription() + { + return new RepositoryServerModel(descriptorService.getServerDescriptor()); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.AbstractRuntimeContainer#getScriptParameters() + */ + public Map getScriptParameters() + { + Map params = new HashMap(); + params.putAll(super.getScriptParameters()); + addRepoParameters(params); + return params; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.AbstractRuntimeContainer#getTemplateParameters() + */ + public Map getTemplateParameters() + { + Map params = new HashMap(); + params.putAll(super.getTemplateParameters()); + params.put(TemplateService.KEY_IMAGE_RESOLVER, imageResolver.getImageResolver()); + addRepoParameters(params); + return params; + } + + /** + * Add Repository specific parameters + * + * @param params + */ + private void addRepoParameters(Map params) + { + if (AlfrescoTransactionSupport.getTransactionId() != null && AuthenticationUtil.getCurrentAuthentication() != null) + { + NodeRef rootHome = repository.getRootHome(); + if (rootHome != null && permissionService.hasPermission(rootHome, PermissionService.READ).equals(AccessStatus.ALLOWED)) + { + params.put("roothome", rootHome); + } + NodeRef companyHome = repository.getCompanyHome(); + if (companyHome != null && permissionService.hasPermission(companyHome, PermissionService.READ).equals(AccessStatus.ALLOWED)) + { + params.put("companyhome", companyHome); + } + NodeRef person = repository.getPerson(); + if (person != null && permissionService.hasPermission(companyHome, PermissionService.READ).equals(AccessStatus.ALLOWED)) + { + params.put("person", person); + params.put("userhome", repository.getUserHome(person)); + } + } + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.RuntimeContainer#executeScript(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse, org.alfresco.web.scripts.Authenticator) + */ + public void executeScript(WebScriptRequest scriptReq, WebScriptResponse scriptRes, Authenticator auth) + throws IOException + { + WebScript script = scriptReq.getServiceMatch().getWebScript(); + Description desc = script.getDescription(); + RequiredAuthentication required = desc.getRequiredAuthentication(); + boolean isGuest = scriptReq.isGuest(); + + if (required == RequiredAuthentication.none) + { + // MT-context will pre-authenticate (see MTWebScriptAuthenticationFilter) + if (! AuthenticationUtil.isMtEnabled()) + { + // TODO revisit - cleared here, in-lieu of WebClient clear + AuthenticationUtil.clearCurrentSecurityContext(); + } + transactionedExecute(script, scriptReq, scriptRes); + } + else if ((required == RequiredAuthentication.user || required == RequiredAuthentication.admin) && isGuest) + { + throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires user authentication; however, a guest has attempted access."); + } + else + { + String currentUser = null; + + try + { + // + // Determine if user already authenticated + // + currentUser = AuthenticationUtil.getCurrentUserName(); + if (logger.isDebugEnabled()) + { + logger.debug("Current authentication: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser)); + logger.debug("Authentication required: " + required); + logger.debug("Guest login: " + isGuest); + } + + // + // Apply appropriate authentication to Web Script invocation + // + if (auth == null || auth.authenticate(required, isGuest)) + { + if (required == RequiredAuthentication.admin && !authorityService.hasAdminAuthority()) + { + throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires admin authentication; however, a non-admin has attempted access."); + } + + // Execute Web Script + transactionedExecute(script, scriptReq, scriptRes); + } + } + finally + { + // + // Reset authentication for current thread + // + AuthenticationUtil.clearCurrentSecurityContext(); + if (currentUser != null) + { + AuthenticationUtil.setCurrentUser(currentUser); + } + + if (logger.isDebugEnabled()) + logger.debug("Authentication reset: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser)); + } + } + } + + /** + * Execute script within required level of transaction + * + * @param scriptReq + * @param scriptRes + * @throws IOException + */ + protected void transactionedExecute(final WebScript script, final WebScriptRequest scriptReq, final WebScriptResponse scriptRes) + throws IOException + { + final Description description = script.getDescription(); + if (description.getRequiredTransaction() == RequiredTransaction.none) + { + script.execute(scriptReq, scriptRes); + } + else + { + // encapsulate script within transaction + RetryingTransactionCallback work = new RetryingTransactionCallback() + { + public Object execute() throws Exception + { + if (logger.isDebugEnabled()) + logger.debug("Begin transaction: " + description.getRequiredTransaction()); + + script.execute(scriptReq, scriptRes); + + if (logger.isDebugEnabled()) + logger.debug("End transaction: " + description.getRequiredTransaction()); + + return null; + } + }; + + if (description.getRequiredTransaction() == RequiredTransaction.required) + { + retryingTransactionHelper.doInTransaction(work); + } + else + { + retryingTransactionHelper.doInTransaction(work, false, true); + } + } + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.AbstractRuntimeContainer#getRegistry() + */ + @Override + public Registry getRegistry() + { + String tenantDomain = tenantDeployerService.getCurrentUserDomain(); + Registry registry = webScriptsRegistryCache.get(tenantDomain); + if (registry == null) + { + init(); + registry = webScriptsRegistryCache.get(tenantDomain); + } + return registry; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.AbstractRuntimeContainer#reset() + */ + @Override + public void reset() + { + destroy(); + init(); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.tenant.TenantDeployer#onEnableTenant() + */ + public void onEnableTenant() + { + init(); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.tenant.TenantDeployer#onDisableTenant() + */ + public void onDisableTenant() + { + destroy(); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.tenant.TenantDeployer#init() + */ + public void init() + { + tenantDeployerService.register(this); + + Registry registry = (Registry)registryFactory.getObject(); + webScriptsRegistryCache.put(tenantDeployerService.getCurrentUserDomain(), registry); + + super.reset(); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.tenant.TenantDeployer#destroy() + */ + public void destroy() + { + webScriptsRegistryCache.remove(tenantDeployerService.getCurrentUserDomain()); + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/RepositoryImageResolver.java b/source/java/org/alfresco/repo/web/scripts/RepositoryImageResolver.java new file mode 100644 index 0000000000..670910e6ea --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/RepositoryImageResolver.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts; + +import javax.servlet.ServletContext; + +import org.alfresco.service.cmr.repository.FileTypeImageSize; +import org.alfresco.service.cmr.repository.TemplateImageResolver; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.web.context.ServletContextAware; + + +/** + * Web Scripts Image Resolver + * + * @author davidc + */ +public class RepositoryImageResolver + implements ServletContextAware, InitializingBean +{ + private ServletContext servletContext; + private TemplateImageResolver imageResolver; + + + /* (non-Javadoc) + * @see org.springframework.web.context.ServletContextAware#setServletContext(javax.servlet.ServletContext) + */ + public void setServletContext(ServletContext context) + { + this.servletContext = context; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + @SuppressWarnings("serial") + public void afterPropertiesSet() + throws Exception + { + this.imageResolver = new TemplateImageResolver() + { + public String resolveImagePathForName(String filename, FileTypeImageSize size) + { + return FileTypeImageUtils.getFileTypeImage(servletContext, filename, size); + } + }; + } + + /** + * @return image resolver + */ + public TemplateImageResolver getImageResolver() + { + return this.imageResolver; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/RepositoryScriptProcessor.java b/source/java/org/alfresco/repo/web/scripts/RepositoryScriptProcessor.java new file mode 100644 index 0000000000..24e4a5d667 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/RepositoryScriptProcessor.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts; + +import java.io.InputStream; +import java.io.Reader; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.alfresco.repo.jscript.ValueConverter; +import org.alfresco.scripts.ScriptException; +import org.alfresco.service.cmr.repository.ScriptLocation; +import org.alfresco.service.cmr.repository.ScriptService; +import org.alfresco.web.scripts.MultiScriptLoader; +import org.alfresco.web.scripts.ScriptContent; +import org.alfresco.web.scripts.ScriptLoader; +import org.alfresco.web.scripts.ScriptProcessor; +import org.alfresco.web.scripts.SearchPath; +import org.alfresco.web.scripts.Store; +import org.alfresco.web.scripts.WebScriptException; + + +/** + * Repository (server-tier) Web Script Processor + * + * @author davidc + */ +public class RepositoryScriptProcessor implements ScriptProcessor +{ + // dependencies + protected ScriptService scriptService; + protected ScriptLoader scriptLoader; + protected SearchPath searchPath; + + // Javascript Converter + private ValueConverter valueConverter = new ValueConverter(); + + + /** + * @param scriptService + */ + public void setScriptService(ScriptService scriptService) + { + this.scriptService = scriptService; + } + + /** + * @param searchPath + */ + public void setSearchPath(SearchPath searchPath) + { + this.searchPath = searchPath; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ScriptProcessor#findScript(java.lang.String) + */ + public ScriptContent findScript(String path) + { + return scriptLoader.getScript(path); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ScriptProcessor#executeScript(java.lang.String, java.util.Map) + */ + public Object executeScript(String path, Map model) + throws ScriptException + { + // locate script within web script stores + ScriptContent scriptContent = findScript(path); + if (scriptContent == null) + { + throw new WebScriptException("Unable to locate script " + path); + } + // execute script + return executeScript(scriptContent, model); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ScriptProcessor#executeScript(org.alfresco.web.scripts.ScriptContent, java.util.Map) + */ + public Object executeScript(ScriptContent content, Map model) + { + return scriptService.executeScript("javascript", new RepositoryScriptLocation(content), model); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ScriptProcessor#unwrapValue(java.lang.Object) + */ + public Object unwrapValue(Object value) + { + return (value instanceof Serializable) ? valueConverter.convertValueForRepo((Serializable)value) : value; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ScriptProcessor#reset() + */ + public void reset() + { + init(); + } + + /** + * Register script loader from each Web Script Store with Script Processor + */ + private void init() + { + List loaders = new ArrayList(); + for (Store apiStore : searchPath.getStores()) + { + ScriptLoader loader = apiStore.getScriptLoader(); + if (loader == null) + { + throw new WebScriptException("Unable to retrieve script loader for Web Script store " + apiStore.getBasePath()); + } + loaders.add(loader); + } + scriptLoader = new MultiScriptLoader(loaders.toArray(new ScriptLoader[loaders.size()])); + } + + + /** + * Script Location Facade + */ + private static class RepositoryScriptLocation implements ScriptLocation + { + private ScriptContent content; + + private RepositoryScriptLocation(ScriptContent content) + { + this.content = content; + } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.repository.ScriptLocation#getInputStream() + */ + public InputStream getInputStream() + { + return content.getInputStream(); + } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.repository.ScriptLocation#getReader() + */ + public Reader getReader() + { + return content.getReader(); + } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.repository.ScriptLocation#isSecure() + */ + public boolean isSecure() + { + return content.isSecure(); + } + + @Override + public String toString() + { + return content.getPathDescription(); + } + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/RepositoryServerModel.java b/source/java/org/alfresco/repo/web/scripts/RepositoryServerModel.java new file mode 100644 index 0000000000..4cd4ce28a6 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/RepositoryServerModel.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts; + +import org.alfresco.service.descriptor.Descriptor; +import org.alfresco.web.scripts.ServerModel; + + +/** + * Script / Template Model representing Repository Server meta-data + * + * @author davidc + */ +public class RepositoryServerModel implements ServerModel +{ + private Descriptor serverDescriptor; + + /** + * Construct + * + * @param serverDescriptor + */ + /*package*/ RepositoryServerModel(Descriptor serverDescriptor) + { + this.serverDescriptor = serverDescriptor; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ServerModel#getContainerName() + */ + public String getContainerName() + { + return "Repository"; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ServerModel#getVersionMajor() + */ + public String getVersionMajor() + { + return serverDescriptor.getVersionMajor(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ServerModel#getVersionMinor() + */ + public String getVersionMinor() + { + return serverDescriptor.getVersionMinor(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ServerModel#getVersionRevision() + */ + public String getVersionRevision() + { + return serverDescriptor.getVersionRevision(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ServerModel#getVersionLabel() + */ + public String getVersionLabel() + { + return serverDescriptor.getVersionLabel(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ServerModel#getVersionBuild() + */ + public String getVersionBuild() + { + return serverDescriptor.getVersionBuild(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ServerModel#getVersion() + */ + public String getVersion() + { + return serverDescriptor.getVersion(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ServerModel#getEdition() + */ + public String getEdition() + { + return serverDescriptor.getEdition(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ServerModel#getSchema() + */ + public int getSchema() + { + return serverDescriptor.getSchema(); + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/RepositoryTemplateProcessor.java b/source/java/org/alfresco/repo/web/scripts/RepositoryTemplateProcessor.java new file mode 100644 index 0000000000..bdd8345f5c --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/RepositoryTemplateProcessor.java @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.alfresco.repo.template.FreeMarkerProcessor; +import org.alfresco.repo.template.QNameAwareObjectWrapper; +import org.alfresco.service.cmr.repository.ProcessorExtension; +import org.alfresco.util.AbstractLifecycleBean; +import org.alfresco.web.scripts.SearchPath; +import org.alfresco.web.scripts.Store; +import org.alfresco.web.scripts.TemplateProcessor; +import org.alfresco.web.scripts.WebScriptException; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; + +import freemarker.cache.MruCacheStorage; +import freemarker.cache.MultiTemplateLoader; +import freemarker.cache.TemplateLoader; +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateExceptionHandler; + + +/** + * Repository (server-tier) Web Script Template Processor + * + * @author davidc + */ +public class RepositoryTemplateProcessor extends FreeMarkerProcessor + implements TemplateProcessor, ApplicationContextAware, ApplicationListener +{ + private ProcessorLifecycle lifecycle = new ProcessorLifecycle(); + protected SearchPath searchPath; + protected String defaultEncoding; + protected Configuration templateConfig; + protected FreeMarkerProcessor freeMarkerProcessor; + + + /* (non-Javadoc) + * @see org.alfresco.repo.template.FreeMarkerProcessor#setDefaultEncoding(java.lang.String) + */ + public void setDefaultEncoding(String defaultEncoding) + { + this.defaultEncoding = defaultEncoding; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.TemplateProcessor#getDefaultEncoding() + */ + public String getDefaultEncoding() + { + return this.defaultEncoding; + } + + /** + * @param searchPath + */ + public void setSearchPath(SearchPath searchPath) + { + this.searchPath = searchPath; + } + + /** + * Set the freemarker processor + * + * @param freeMarkerProcessor the free marker processor + */ + public void setFreeMarkerProcessor(FreeMarkerProcessor freeMarkerProcessor) + { + this.freeMarkerProcessor = freeMarkerProcessor; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.template.FreeMarkerProcessor#getConfig() + */ + @Override + protected Configuration getConfig() + { + return templateConfig; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.TemplateProcessor#reset() + */ + public void reset() + { + if (templateConfig != null) + { + templateConfig.clearTemplateCache(); + } + initConfig(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.TemplateProcessor#hasTemplate(java.lang.String) + */ + public boolean hasTemplate(String templatePath) + { + boolean hasTemplate = false; + try + { + Template template = templateConfig.getTemplate(templatePath); + hasTemplate = (template != null); + } + catch(FileNotFoundException e) + { + // NOTE: return false as template is not found + } + catch(IOException e) + { + throw new WebScriptException("Failed to retrieve template " + templatePath, e); + } + return hasTemplate; + } + + /** + * Initialise FreeMarker Configuration + */ + protected void initConfig() + { + Configuration config = new Configuration(); + + // setup template cache + config.setCacheStorage(new MruCacheStorage(20, 100)); + config.setTemplateUpdateDelay(0); + + // setup template loaders + List loaders = new ArrayList(); + for (Store apiStore : searchPath.getStores()) + { + TemplateLoader loader = apiStore.getTemplateLoader(); + if (loader == null) + { + throw new WebScriptException("Unable to retrieve template loader for Web Script store " + apiStore.getBasePath()); + } + loaders.add(loader); + } + MultiTemplateLoader loader = new MultiTemplateLoader(loaders.toArray(new TemplateLoader[loaders.size()])); + config.setTemplateLoader(loader); + + // use our custom object wrapper that can deal with QNameMap objects directly + config.setObjectWrapper(new QNameAwareObjectWrapper()); + + // rethrow any exception so we can deal with them + config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); + + // turn off locale sensitive lookup - to save numerous wasted calls to nodeservice.exists() + config.setLocalizedLookup(false); + + // set template encoding + if (defaultEncoding != null) + { + config.setDefaultEncoding(defaultEncoding); + } + + // set output encoding + config.setOutputEncoding("UTF-8"); + + templateConfig = config; + } + + /** + * Tempory fix to initialise this template processor with the freeMarker extensions expected by + * the templates. + */ + private void initProcessorExtensions() + { + for (ProcessorExtension processorExtension : this.freeMarkerProcessor.getProcessorExtensions()) + { + this.registerProcessorExtension(processorExtension); + } + } + + /* (non-Javadoc) + * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) + */ + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + lifecycle.setApplicationContext(applicationContext); + } + + /* (non-Javadoc) + * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) + */ + public void onApplicationEvent(ApplicationEvent event) + { + lifecycle.onApplicationEvent(event); + } + + /** + * Hooks into Spring Application Lifecycle + */ + private class ProcessorLifecycle extends AbstractLifecycleBean + { + @Override + protected void onBootstrap(ApplicationEvent event) + { + initProcessorExtensions(); + } + + @Override + protected void onShutdown(ApplicationEvent event) + { + } + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/TestWebScriptRepoServer.java b/source/java/org/alfresco/repo/web/scripts/TestWebScriptRepoServer.java new file mode 100644 index 0000000000..57b8870783 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/TestWebScriptRepoServer.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +import org.alfresco.repo.security.authentication.AuthenticationException; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.web.scripts.TestWebScriptServer; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + + +/** + * Stand-alone Web Script Test Server + * + * @author davidc + */ +public class TestWebScriptRepoServer extends TestWebScriptServer +{ + private RetryingTransactionHelper retryingTransactionHelper; + private AuthenticationService authenticationService; + + + /** + * Sets helper that provides transaction callbacks + */ + public void setTransactionHelper(RetryingTransactionHelper retryingTransactionHelper) + { + this.retryingTransactionHelper = retryingTransactionHelper; + } + + /** + * @param authenticationService + */ + public void setAuthenticationService(AuthenticationService authenticationService) + { + this.authenticationService = authenticationService; + } + + /** + * Main entry point. + */ + public static void main(String[] args) + { + try + { + TestWebScriptServer testServer = getTestServer(); + testServer.rep(); + } + catch(Throwable e) + { + StringWriter strWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(strWriter); + e.printStackTrace(printWriter); + System.out.println(strWriter.toString()); + } + finally + { + System.exit(0); + } + } + + /** + * Retrieve an instance of the TestWebScriptServer + * + * @return Test Server + */ + public static TestWebScriptServer getTestServer() + { + String[] CONFIG_LOCATIONS = new String[] + { + "classpath:alfresco/application-context.xml", + "classpath:alfresco/webscript-framework-application-context.xml", + "classpath:alfresco/web-scripts-application-context.xml", + "classpath:alfresco/web-scripts-application-context-test.xml" + }; + ApplicationContext context = new ClassPathXmlApplicationContext(CONFIG_LOCATIONS); + TestWebScriptServer testServer = (TestWebScriptRepoServer)context.getBean("webscripts.test"); + return testServer; + } + + /** + * Interpret a single command using the BufferedReader passed in for any data needed. + * + * @param line The unparsed command + * @return The textual output of the command. + */ + @Override + protected String interpretCommand(final String line) + throws IOException + { + try + { + if (username.startsWith("TICKET_")) + { + try + { + retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public Object execute() throws Exception + { + authenticationService.validate(username); + return null; + } + }); + return executeCommand(line); + } + finally + { + authenticationService.clearCurrentSecurityContext(); + } + } + } + catch(AuthenticationException e) + { + executeCommand("user admin"); + } + + // execute command in context of currently selected user + return AuthenticationUtil.runAs(new RunAsWork() + { + @SuppressWarnings("synthetic-access") + public String doWork() throws Exception + { + return executeCommand(line); + } + }, username); + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/bean/AVMRemoteStore.java b/source/java/org/alfresco/repo/web/scripts/bean/AVMRemoteStore.java new file mode 100644 index 0000000000..82170a07ec --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/bean/AVMRemoteStore.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.repo.web.scripts.bean; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Writer; +import java.net.SocketException; + +import org.alfresco.repo.avm.AVMNodeConverter; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.service.cmr.avm.AVMNodeDescriptor; +import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.repository.ContentIOException; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.scripts.servlet.WebScriptServletResponse; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * AVM Remote Store service. + * + * @see BaseRemoteStore for API methods. + * + * @author Kevin Roast + */ +public class AVMRemoteStore extends BaseRemoteStore +{ + private static final Log logger = LogFactory.getLog(AVMRemoteStore.class); + + private String rootPath; + private AVMService avmService; + + + /** + * @param rootPath the root path under which to process store requests + */ + public void setRootPath(String rootPath) + { + this.rootPath = rootPath; + } + + /** + * @param avmService the AVMService to set + */ + public void setAvmService(AVMService avmService) + { + this.avmService = avmService; + } + + + /** + * Gets the last modified timestamp for the document. + * + * @param path document path to an existing document + */ + @Override + protected void lastModified(WebScriptResponse res, String path) + throws IOException + { + String avmPath = buildAVMPath(path); + AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); + if (desc == null) + { + throw new WebScriptException("Unable to locate AVM file: " + avmPath); + } + + Writer out = res.getWriter(); + out.write(Long.toString(desc.getModDate())); + out.close(); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#getDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String) + */ + @Override + protected void getDocument(WebScriptResponse res, String path) throws IOException + { + String avmPath = buildAVMPath(path); + AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); + if (desc == null) + { + throw new WebScriptException("Unable to locate file: " + avmPath); + } + + ContentReader reader = this.avmService.getContentReader(-1, avmPath); + if (reader == null) + { + throw new WebScriptException("No content found for AVM file: " + avmPath); + } + + // establish mimetype + String mimetype = reader.getMimetype(); + if (mimetype == null || mimetype.length() == 0) + { + mimetype = MimetypeMap.MIMETYPE_BINARY; + int extIndex = path.lastIndexOf('.'); + if (extIndex != -1) + { + String ext = path.substring(extIndex + 1); + String mt = this.mimetypeService.getMimetypesByExtension().get(ext); + if (mt != null) + { + mimetype = mt; + } + } + } + + // set mimetype for the content and the character encoding + length for the stream + WebScriptServletResponse httpRes = (WebScriptServletResponse)res; + httpRes.setContentType(mimetype); + httpRes.getHttpServletResponse().setCharacterEncoding(reader.getEncoding()); + httpRes.getHttpServletResponse().setDateHeader("Last-Modified", desc.getModDate()); + httpRes.setHeader("Content-Length", Long.toString(reader.getSize())); + + // get the content and stream directly to the response output stream + // assuming the repository is capable of streaming in chunks, this should allow large files + // to be streamed directly to the browser response stream. + try + { + reader.getContent(res.getOutputStream()); + } + catch (SocketException e1) + { + // the client cut the connection - our mission was accomplished apart from a little error message + if (logger.isInfoEnabled()) + logger.info("Client aborted stream read:\n\tnode: " + avmPath + "\n\tcontent: " + reader); + } + catch (ContentIOException e2) + { + if (logger.isInfoEnabled()) + logger.info("Client aborted stream read:\n\tnode: " + avmPath + "\n\tcontent: " + reader); + } + } + + /* (non-Javadoc) + * @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#hasDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String) + */ + @Override + protected void hasDocument(WebScriptResponse res, String path) throws IOException + { + String avmPath = buildAVMPath(path); + AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); + + Writer out = res.getWriter(); + out.write(Boolean.toString(desc != null)); + out.close(); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#createDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String, java.io.InputStream) + */ + @Override + protected void createDocument(WebScriptResponse res, String path, InputStream content) + { + String avmPath = buildAVMPath(path); + AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); + if (desc != null) + { + throw new WebScriptException("Unable to create, file already exists: " + avmPath); + } + + String[] parts = AVMNodeConverter.SplitBase(avmPath); + this.avmService.createFile(parts[0], parts[1], content); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#updateDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String, java.io.InputStream) + */ + @Override + protected void updateDocument(WebScriptResponse res, String path, InputStream content) + { + String avmPath = buildAVMPath(path); + AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); + if (desc == null) + { + throw new WebScriptException("Unable to locate file for update: " + avmPath); + } + + ContentWriter writer = this.avmService.getContentWriter(avmPath); + writer.putContent(content); + } + + /** + * @param path root path relative + * + * @return full AVM path to document including store and root path components + */ + private String buildAVMPath(String path) + { + return this.store + ":/" + this.rootPath + "/" + path; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/bean/BaseRemoteStore.java b/source/java/org/alfresco/repo/web/scripts/bean/BaseRemoteStore.java new file mode 100644 index 0000000000..5730d11009 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/bean/BaseRemoteStore.java @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.repo.web.scripts.bean; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.MimetypeService; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.web.scripts.AbstractWebScript; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.scripts.servlet.WebScriptServletRequest; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Remote Store service. + * + * Responsible for providing remote HTTP based access to a store. Designed to be accessed + * from a web-tier application to remotely mirror a WebScript Store instance. + * + * Request format: + * // + * + * Example: + * /service/remotestore/lastmodified/sites/xyz/pages/page.xml + * + * where: + * /service/remotestore -> service path + * /lastmodified -> method name + * /sites/../page.xml -> document path + * + * Note: path is relative to the root path as configured for this webscript bean + * + * For content create and update the request should be POSTed and the content sent as the + * payload of the request content. + * + * Supported method API: + * GET lastmodified -> return long timestamp of a document + * GET has -> return true/false of existence for a document + * GET get -> return document content - in addition the usual HTTP headers for the + * character encoding, content type, length and modified date will be supplied + * POST create -> create a new document with request content payload + * POST update -> update an existing document with request content payload + * + * @author Kevin Roast + */ +public abstract class BaseRemoteStore extends AbstractWebScript +{ + private static final Log logger = LogFactory.getLog(BaseRemoteStore.class); + + protected String store; + protected ContentService contentService; + protected MimetypeService mimetypeService; + + + /** + * @param store the store name of the store to process document requests against + */ + public void setStore(String store) + { + this.store = store; + } + + /** + * @param contentService the ContentService to set + */ + public void setContentService(ContentService contentService) + { + this.contentService = contentService; + } + + /** + * @param mimetypeService the MimetypeService to set + */ + public void setMimetypeService(MimetypeService mimetypeService) + { + this.mimetypeService = mimetypeService; + } + + /** + * Execute the webscript based on the request parameters + */ + public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException + { + // NOTE: This web script must be executed in a HTTP Servlet environment + if (!(req instanceof WebScriptServletRequest)) + { + throw new WebScriptException("Remote Store access must be executed in HTTP Servlet environment"); + } + + HttpServletRequest httpReq = ((WebScriptServletRequest)req).getHttpServletRequest(); + + // break down and validate the request - expecting method name and document path + String extPath = req.getExtensionPath(); + String[] extParts = extPath == null ? new String[0] : extPath.split("/"); + if (extParts.length < 1) + { + throw new WebScriptException("Remote Store expecting method name."); + } + if (extParts.length < 2) + { + throw new WebScriptException("Remote Store expecting document path."); + } + + // build path as a string and as a list of path elements + String path = req.getExtensionPath().substring(extParts[0].length() + 1); + + if (logger.isDebugEnabled()) + logger.debug("Remote store method: " + extParts[0] + " path: " + path); + + // TODO: support storeref name override as argument (i.e. for AVM virtualisation) + + try + { + // generate enum from string method name - so we can use a fast switch table lookup + APIMethod method = APIMethod.valueOf(extParts[0].toUpperCase()); + switch (method) + { + case LASTMODIFIED: + lastModified(res, path); + break; + + case HAS: + hasDocument(res, path); + break; + + case GET: + getDocument(res, path); + break; + + case CREATE: + createDocument(res, path, httpReq.getInputStream()); + break; + + case UPDATE: + updateDocument(res, path, httpReq.getInputStream()); + break; + } + } + catch (IllegalArgumentException enumErr) + { + throw new WebScriptException("Unknown method specified to remote store API: " + extParts[0]); + } + catch (IOException ioErr) + { + throw new WebScriptException("Error during remote store API: " + ioErr.getMessage()); + } + } + + /** + * Helper to break down webscript extension path into path component elements + */ + protected List getPathParts(String[] extPaths) + { + List pathParts = new ArrayList(extPaths.length - 1); + for (int i=1; i exists, false => does not exist + */ + protected abstract void hasDocument(WebScriptResponse res, String path) + throws IOException; + + /** + * Gets a document + * + * @param path document path + * @return input stream onto document + * + * @throws IOException if the document does not exist in the store + */ + protected abstract void getDocument(WebScriptResponse res, String path) + throws IOException; + + /** + * Creates a document. + * + * @param path document path + * @param content content of the document to write + * + * @throws IOException if the document already exists or the create fails + */ + protected abstract void createDocument(WebScriptResponse res, String path, InputStream content); + + /** + * Updates an existing document. + * + * @param path document path + * @param content content to update the document with + * + * @throws IOException if the document does not exist or the update fails + */ + protected abstract void updateDocument(WebScriptResponse res, String path, InputStream content); + + + /** + * Enum representing the API method on the Store. + */ + private enum APIMethod + { + LASTMODIFIED, + HAS, + GET, + CREATE, + UPDATE + }; +} diff --git a/source/java/org/alfresco/repo/web/scripts/bean/ContentGet.java b/source/java/org/alfresco/repo/web/scripts/bean/ContentGet.java new file mode 100644 index 0000000000..8ac63a248a --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/bean/ContentGet.java @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.bean; + +import java.io.IOException; +import java.net.SocketException; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.Date; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.web.scripts.Repository; +import org.alfresco.service.cmr.repository.ContentIOException; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.MimetypeService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.URLEncoder; +import org.alfresco.web.scripts.AbstractWebScript; +import org.alfresco.web.scripts.Cache; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.scripts.servlet.WebScriptServletRequest; +import org.alfresco.web.scripts.servlet.WebScriptServletResponse; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Content Retrieval Service + * + * Stream content from the Repository. + * + * @author davidc + */ +public class ContentGet extends AbstractWebScript +{ + // Logger + private static final Log logger = LogFactory.getLog(ContentGet.class); + + private static final String NODE_URL = "/api/node/content/{0}/{1}/{2}/{3}"; + + // Component dependencies + private Repository repository; + private NamespaceService namespaceService; + private PermissionService permissionService; + private NodeService nodeService; + private ContentService contentService; + private MimetypeService mimetypeService; + + /** + * @param repository + */ + public void setRepository(Repository repository) + { + this.repository = repository; + } + + /** + * @param namespaceService + */ + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + + /** + * @param permissionService + */ + public void setPermissionService(PermissionService permissionService) + { + this.permissionService = permissionService; + } + + /** + * @param nodeService + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * @param contentService + */ + public void setContentService(ContentService contentService) + { + this.contentService = contentService; + } + + /** + * @param mimetypeService + */ + public void setMimetypeService(MimetypeService mimetypeService) + { + this.mimetypeService = mimetypeService; + } + + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScript#execute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + public void execute(WebScriptRequest req, WebScriptResponse res) + throws IOException + { + // NOTE: This web script must be executed in a HTTP Servlet environment + if (!(req instanceof WebScriptServletRequest)) + { + throw new WebScriptException("Content retrieval must be executed in HTTP Servlet environment"); + } + HttpServletRequest httpReq = ((WebScriptServletRequest)req).getHttpServletRequest(); + HttpServletResponse httpRes = ((WebScriptServletResponse)res).getHttpServletResponse(); + + // convert web script URL to node reference in Repository + String match = req.getServiceMatch().getPath(); + String[] matchParts = match.split("/"); + String extensionPath = req.getExtensionPath(); + String[] extParts = extensionPath == null ? new String[1] : extensionPath.split("/"); + String[] path = new String[extParts.length -1]; + System.arraycopy(extParts, 1, path, 0, extParts.length -1); + NodeRef nodeRef = repository.findNodeRef(matchParts[2], path); + if (nodeRef == null) + { + throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + matchParts[2] + " reference " + Arrays.toString(path)); + } + + // determine content property + QName propertyQName = ContentModel.PROP_CONTENT; + String contentPart = extParts[0]; + if (contentPart.length() > 0 && contentPart.charAt(0) == ';') + { + if (contentPart.length() < 2) + { + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Content property malformed"); + } + String propertyName = contentPart.substring(1); + if (propertyName.length() > 0) + { + propertyQName = QName.createQName(propertyName, namespaceService); + } + } + + // determine attachment + boolean attach = Boolean.valueOf(req.getParameter("a")); + + if (logger.isDebugEnabled()) + logger.debug("Retrieving content from node ref " + nodeRef.toString() + " (property: " + propertyQName.toString() + ") (attach: " + attach + ")"); + + // check that the user has at least READ_CONTENT access - else redirect to the login page + if (permissionService.hasPermission(nodeRef, PermissionService.READ_CONTENT) == AccessStatus.DENIED) + { + throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "Permission denied"); + } + + // check If-Modified-Since header and set Last-Modified header as appropriate + Date modified = (Date)nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED); + long modifiedSince = httpReq.getDateHeader("If-Modified-Since"); + if (modifiedSince > 0L) + { + // round the date to the ignore millisecond value which is not supplied by header + long modDate = (modified.getTime() / 1000L) * 1000L; + if (modDate <= modifiedSince) + { + httpRes.setStatus(HttpServletResponse.SC_NOT_MODIFIED); + return; + } + } + + // handle attachment + if (attach == true) + { + // set header based on filename - will force a Save As from the browse if it doesn't recognize it + // this is better than the default response of the browser trying to display the contents + httpRes.setHeader("Content-Disposition", "attachment"); + } + + // get the content reader + ContentReader reader = contentService.getReader(nodeRef, propertyQName); + if (reader == null || !reader.exists()) + { + throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to locate content for node ref " + nodeRef + " (property: " + propertyQName.toString() + ")"); + } + + // establish mimetype + String mimetype = reader.getMimetype(); + if (mimetype == null || mimetype.length() == 0) + { + mimetype = MimetypeMap.MIMETYPE_BINARY; + int extIndex = extensionPath.lastIndexOf('.'); + if (extIndex != -1) + { + String ext = extensionPath.substring(extIndex + 1); + String mt = mimetypeService.getMimetypesByExtension().get(ext); + if (mt != null) + { + mimetype = mt; + } + } + } + + // set mimetype for the content and the character encoding + length for the stream + httpRes.setContentType(mimetype); + httpRes.setCharacterEncoding(reader.getEncoding()); + httpRes.setHeader("Content-Length", Long.toString(reader.getSize())); + + // set caching + Cache cache = new Cache(); + cache.setNeverCache(false); + cache.setMustRevalidate(true); + cache.setLastModified(modified); + res.setCache(cache); + + // get the content and stream directly to the response output stream + // assuming the repository is capable of streaming in chunks, this should allow large files + // to be streamed directly to the browser response stream. + try + { + reader.getContent(res.getOutputStream()); + } + catch (SocketException e1) + { + // the client cut the connection - our mission was accomplished apart from a little error message + if (logger.isInfoEnabled()) + logger.info("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader); + } + catch (ContentIOException e2) + { + if (logger.isInfoEnabled()) + logger.info("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader); + } + } + + /** + * Helper to generate a URL to a content node for downloading content from the server. + * The content is supplied directly in the reponse. This generally means a browser will + * attempt to open the content directly if possible, else it will prompt to save the file. + * + * @param ref NodeRef of the content node to generate URL for (cannot be null) + * @param name File name end element to return on the url (used by the browser on Save) + * + * @return URL to download the content from the specified node + */ + public final static String generateNodeURL(NodeRef ref, String name) + { + return MessageFormat.format(NODE_URL, new Object[] { + ref.getStoreRef().getProtocol(), + ref.getStoreRef().getIdentifier(), + ref.getId(), + URLEncoder.encode(name) } ); + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/bean/JavascriptDebugger.java b/source/java/org/alfresco/repo/web/scripts/bean/JavascriptDebugger.java new file mode 100644 index 0000000000..3aaa395bdd --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/bean/JavascriptDebugger.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.bean; + +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.repo.jscript.AlfrescoRhinoScriptDebugger; +import org.alfresco.web.scripts.DeclarativeWebScript; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.Status; + + +/** + * Javascript Debugger + * + * @author davidc + */ +public class JavascriptDebugger extends DeclarativeWebScript +{ + // dependencies + private AlfrescoRhinoScriptDebugger debugger; + + /** + * @param ticketComponent + */ + public void setDebugger(AlfrescoRhinoScriptDebugger debugger) + { + this.debugger = debugger; + } + + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + @Override + protected Map executeImpl(WebScriptRequest req, Status status) + { + // construct model + Map model = new HashMap(7, 1.0f); + model.put("visible", debugger.isVisible()); + return model; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/bean/JavascriptDebuggerPost.java b/source/java/org/alfresco/repo/web/scripts/bean/JavascriptDebuggerPost.java new file mode 100644 index 0000000000..21c0a927d1 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/bean/JavascriptDebuggerPost.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.bean; + +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.repo.jscript.AlfrescoRhinoScriptDebugger; +import org.alfresco.web.scripts.DeclarativeWebScript; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.Status; + + +/** + * Javascript Debugger + * + * @author davidc + */ +public class JavascriptDebuggerPost extends DeclarativeWebScript +{ + // dependencies + private AlfrescoRhinoScriptDebugger debugger; + + /** + * @param ticketComponent + */ + public void setDebugger(AlfrescoRhinoScriptDebugger debugger) + { + this.debugger = debugger; + } + + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + @Override + protected Map executeImpl(WebScriptRequest req, Status status) + { + String visibleStr = req.getParameter("visible"); + boolean visible = Boolean.valueOf(visibleStr); + + if (visible) + { + debugger.show(); + } + else + { + debugger.hide(); + } + + Map model = new HashMap(7, 1.0f); + model.put("visible", debugger.isVisible()); + return model; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/bean/KeywordSearch.java b/source/java/org/alfresco/repo/web/scripts/bean/KeywordSearch.java new file mode 100644 index 0000000000..44cdaab0fb --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/bean/KeywordSearch.java @@ -0,0 +1,419 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.bean; + +import java.io.StringWriter; +import java.io.Writer; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import org.alfresco.i18n.I18NUtil; +import org.alfresco.repo.template.TemplateNode; +import org.alfresco.repo.web.scripts.RepositoryImageResolver; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.TemplateException; +import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.SearchParameters; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.util.GUID; +import org.alfresco.util.ParameterCheck; +import org.alfresco.util.URLEncoder; +import org.alfresco.web.scripts.DeclarativeWebScript; +import org.alfresco.web.scripts.Status; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptRequest; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.util.StringUtils; + + +/** + * Alfresco Keyword (simple) Search Service + * + * @author davidc + */ +public class KeywordSearch extends DeclarativeWebScript +{ + // Logger + private static final Log logger = LogFactory.getLog(KeywordSearch.class); + + // search parameters + // TODO: allow configuration of search store + protected static final StoreRef SEARCH_STORE = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore"); + protected static final int DEFAULT_ITEMS_PER_PAGE = 10; + protected static final String QUERY_FORMAT = "query_"; + + // dependencies + protected ServiceRegistry serviceRegistry; + protected RepositoryImageResolver imageResolver; + protected SearchService searchService; + + /** + * @param searchService + */ + public void setSearchService(SearchService searchService) + { + this.searchService = searchService; + } + + /** + * @param imageResolver + */ + public void setRepositoryImageResolver(RepositoryImageResolver imageResolver) + { + this.imageResolver = imageResolver; + } + + /** + * @param serviceRegistry + */ + public void setServiceRegistry(ServiceRegistry serviceRegistry) + { + this.serviceRegistry = serviceRegistry; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + @Override + protected Map executeImpl(WebScriptRequest req, Status status) + { + // + // process arguments + // + + String searchTerms = req.getParameter("q"); + ParameterCheck.mandatoryString("q", searchTerms); + String startPageArg = req.getParameter("p"); + int startPage = 1; + try + { + startPage = new Integer(startPageArg); + } + catch(NumberFormatException e) + { + // NOTE: use default startPage + } + String itemsPerPageArg = req.getParameter("c"); + int itemsPerPage = DEFAULT_ITEMS_PER_PAGE; + try + { + itemsPerPage = new Integer(itemsPerPageArg); + } + catch(NumberFormatException e) + { + // NOTE: use default itemsPerPage + } + Locale locale = I18NUtil.getLocale(); + String language = req.getParameter("l"); + if (language != null && language.length() > 0) + { + // NOTE: Simple conversion from XML Language Id to Java Locale Id + locale = new Locale(language.replace("-", "_")); + } + + // + // execute the search + // + + SearchResult results = search(searchTerms, startPage, itemsPerPage, locale, req); + + // + // create model + // + + Map model = new HashMap(7, 1.0f); + model.put("search", results); + return model; + } + + /** + * Execute the search + * + * @param searchTerms + * @param startPage + * @return + */ + private SearchResult search(String searchTerms, int startPage, int itemsPerPage, Locale locale, WebScriptRequest req) + { + SearchResult searchResult = null; + ResultSet results = null; + + try + { + // construct search statement + String[] terms = searchTerms.split(" "); + Map statementModel = new HashMap(7, 1.0f); + statementModel.put("args", createArgs(req)); + statementModel.put("terms", terms); + Writer queryWriter = new StringWriter(1024); + renderFormatTemplate(QUERY_FORMAT, statementModel, queryWriter); + String query = queryWriter.toString(); + + // execute query + if (logger.isDebugEnabled()) + { + logger.debug("Search parameters: searchTerms=" + searchTerms + ", startPage=" + startPage + ", itemsPerPage=" + itemsPerPage + ", search locale=" + locale.toString()); + logger.debug("Issuing lucene search: " + query); + } + + SearchParameters parameters = new SearchParameters(); + parameters.addStore(SEARCH_STORE); + parameters.setLanguage(SearchService.LANGUAGE_LUCENE); + parameters.setQuery(query); + if (locale != null) + { + parameters.addLocale(locale); + } + results = searchService.query(parameters); + int totalResults = results.length(); + + if (logger.isDebugEnabled()) + logger.debug("Results: " + totalResults + " rows (limited: " + results.getResultSetMetaData().getLimitedBy() + ")"); + + // are we out-of-range + int totalPages = (totalResults / itemsPerPage); + totalPages += (totalResults % itemsPerPage != 0) ? 1 : 0; + if (totalPages != 0 && (startPage < 1 || startPage > totalPages)) + { + throw new WebScriptException("Start page " + startPage + " is outside boundary of " + totalPages + " pages"); + } + + // construct search result + searchResult = new SearchResult(); + searchResult.setSearchTerms(searchTerms); + searchResult.setLocale(locale); + searchResult.setItemsPerPage(itemsPerPage); + searchResult.setStartPage(startPage); + searchResult.setTotalResults(totalResults); + if (totalResults == 0) + { + searchResult.setTotalPages(0); + searchResult.setStartIndex(0); + searchResult.setTotalPageItems(0); + } + else + { + searchResult.setTotalPages(totalPages); + searchResult.setStartIndex(((startPage -1) * itemsPerPage) + 1); + searchResult.setTotalPageItems(Math.min(itemsPerPage, totalResults - searchResult.getStartIndex() + 1)); + } + SearchTemplateNode[] nodes = new SearchTemplateNode[searchResult.getTotalPageItems()]; + for (int i = 0; i < searchResult.getTotalPageItems(); i++) + { + NodeRef node = results.getNodeRef(i + searchResult.getStartIndex() - 1); + float score = results.getScore(i + searchResult.getStartIndex() - 1); + nodes[i] = new SearchTemplateNode(node, score); + } + searchResult.setResults(nodes); + return searchResult; + } + finally + { + if (results != null) + { + results.close(); + } + } + } + + /** + * Search Result + * + * @author davidc + */ + public static class SearchResult + { + private String id; + private String searchTerms; + private Locale locale; + private int itemsPerPage; + private int totalPages; + private int totalResults; + private int totalPageItems; + private int startPage; + private int startIndex; + private SearchTemplateNode[] results; + + + public int getItemsPerPage() + { + return itemsPerPage; + } + + /*package*/ void setItemsPerPage(int itemsPerPage) + { + this.itemsPerPage = itemsPerPage; + } + + public TemplateNode[] getResults() + { + return results; + } + + /*package*/ void setResults(SearchTemplateNode[] results) + { + this.results = results; + } + + public int getStartIndex() + { + return startIndex; + } + + /*package*/ void setStartIndex(int startIndex) + { + this.startIndex = startIndex; + } + + public int getStartPage() + { + return startPage; + } + + /*package*/ void setStartPage(int startPage) + { + this.startPage = startPage; + } + + public int getTotalPageItems() + { + return totalPageItems; + } + + /*package*/ void setTotalPageItems(int totalPageItems) + { + this.totalPageItems = totalPageItems; + } + + public int getTotalPages() + { + return totalPages; + } + + /*package*/ void setTotalPages(int totalPages) + { + this.totalPages = totalPages; + } + + public int getTotalResults() + { + return totalResults; + } + + /*package*/ void setTotalResults(int totalResults) + { + this.totalResults = totalResults; + } + + public String getSearchTerms() + { + return searchTerms; + } + + /*package*/ void setSearchTerms(String searchTerms) + { + this.searchTerms = searchTerms; + } + + public Locale getLocale() + { + return locale; + } + + /** + * @return XML 1.0 Language Identification + */ + public String getLocaleId() + { + return locale.toString().replace('_', '-'); + } + + /*package*/ void setLocale(Locale locale) + { + this.locale = locale; + } + + public String getId() + { + if (id == null) + { + id = GUID.generate(); + } + return id; + } + } + + /** + * Search result row template node + */ + public class SearchTemplateNode extends TemplateNode + { + protected final static String URL = "/api/node/content/{0}/{1}/{2}/{3}"; + + private static final long serialVersionUID = -1791913270786140012L; + private float score; + + /** + * Construct + * + * @param nodeRef + * @param score + */ + public SearchTemplateNode(NodeRef nodeRef, float score) + { + super(nodeRef, serviceRegistry, KeywordSearch.this.imageResolver.getImageResolver()); + this.score = score; + } + + /** + * Gets the result row score + * + * @return score + */ + public float getScore() + { + return score; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.template.BaseContentNode#getUrl() + */ + @Override + public String getUrl() + { + return MessageFormat.format(URL, new Object[] { + getNodeRef().getStoreRef().getProtocol(), + getNodeRef().getStoreRef().getIdentifier(), + getNodeRef().getId(), + URLEncoder.encode(getName()) } ); + } + } + +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/bean/Login.java b/source/java/org/alfresco/repo/web/scripts/bean/Login.java new file mode 100644 index 0000000000..3bf64e03ca --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/bean/Login.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.bean; + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.repo.security.authentication.AuthenticationException; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.web.scripts.DeclarativeWebScript; +import org.alfresco.web.scripts.Status; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptRequest; + + +/** + * Login and establish a ticket + * + * @author davidc + */ +public class Login extends DeclarativeWebScript +{ + // dependencies + private AuthenticationService authenticationService; + + /** + * @param authenticationService + */ + public void setAuthenticationService(AuthenticationService authenticationService) + { + this.authenticationService = authenticationService; + } + + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + @Override + protected Map executeImpl(WebScriptRequest req, Status status) + { + // extract username and password + String username = req.getParameter("u"); + if (username == null || username.length() == 0) + { + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Username not specified"); + } + String password = req.getParameter("pw"); + if (password == null) + { + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Password not specified"); + } + + try + { + // get ticket + authenticationService.authenticate(username, password.toCharArray()); + + // add ticket to model for javascript and template access + Map model = new HashMap(7, 1.0f); + model.put("ticket", authenticationService.getCurrentTicket()); + return model; + } + catch(AuthenticationException e) + { + throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "Login failed"); + } + finally + { + authenticationService.clearCurrentSecurityContext(); + } + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/bean/LoginTicket.java b/source/java/org/alfresco/repo/web/scripts/bean/LoginTicket.java new file mode 100644 index 0000000000..3104bc51ed --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/bean/LoginTicket.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.bean; + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.repo.security.authentication.AuthenticationException; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.TicketComponent; +import org.alfresco.web.scripts.DeclarativeWebScript; +import org.alfresco.web.scripts.Status; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptRequest; + + +/** + * Login Ticket + * + * @author davidc + */ +public class LoginTicket extends DeclarativeWebScript +{ + // dependencies + private TicketComponent ticketComponent; + + /** + * @param ticketComponent + */ + public void setTicketComponent(TicketComponent ticketComponent) + { + this.ticketComponent = ticketComponent; + } + + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + @Override + protected Map executeImpl(WebScriptRequest req, Status status) + { + // retrieve ticket from request and current ticket + String ticket = req.getExtensionPath(); + if (ticket == null && ticket.length() == 0) + { + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Ticket not specified"); + } + + // construct model for ticket + Map model = new HashMap(7, 1.0f); + model.put("ticket", ticket); + + try + { + String ticketUser = ticketComponent.validateTicket(ticket); + + // do not go any further if tickets are different + if (!AuthenticationUtil.getCurrentUserName().equals(ticketUser)) + { + status.setRedirect(true); + status.setCode(HttpServletResponse.SC_NOT_FOUND); + status.setMessage("Ticket not found"); + } + } + catch(AuthenticationException e) + { + status.setRedirect(true); + status.setCode(HttpServletResponse.SC_NOT_FOUND); + status.setMessage("Ticket not found"); + } + + return model; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/bean/LoginTicketDelete.java b/source/java/org/alfresco/repo/web/scripts/bean/LoginTicketDelete.java new file mode 100644 index 0000000000..503dd6e854 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/bean/LoginTicketDelete.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.bean; + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.repo.security.authentication.AuthenticationException; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.TicketComponent; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.web.scripts.DeclarativeWebScript; +import org.alfresco.web.scripts.Status; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptRequest; + + +/** + * Delete Login Ticket + * + * @author davidc + */ +public class LoginTicketDelete extends DeclarativeWebScript +{ + // dependencies + private AuthenticationService authenticationService; + private TicketComponent ticketComponent; + + /** + * @param ticketComponent + */ + public void setTicketComponent(TicketComponent ticketComponent) + { + this.ticketComponent = ticketComponent; + } + + /** + * @param authenticationService + */ + public void setAuthenticationService(AuthenticationService authenticationService) + { + this.authenticationService = authenticationService; + } + + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + @Override + protected Map executeImpl(WebScriptRequest req, Status status) + { + // retrieve ticket from request and current ticket + String ticket = req.getExtensionPath(); + if (ticket == null && ticket.length() == 0) + { + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Ticket not specified"); + } + + // construct model for ticket + Map model = new HashMap(7, 1.0f); + model.put("ticket", ticket); + + try + { + String ticketUser = ticketComponent.validateTicket(ticket); + + // do not go any further if tickets are different + if (!AuthenticationUtil.getCurrentUserName().equals(ticketUser)) + { + status.setCode(HttpServletResponse.SC_NOT_FOUND); + status.setMessage("Ticket not found"); + } + else + { + // delete the ticket + authenticationService.invalidateTicket(ticket); + status.setMessage("Deleted Ticket " + ticket); + } + } + catch(AuthenticationException e) + { + status.setCode(HttpServletResponse.SC_NOT_FOUND); + status.setMessage("Ticket not found"); + } + + status.setRedirect(true); + return model; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/bean/SearchEngines.java b/source/java/org/alfresco/repo/web/scripts/bean/SearchEngines.java new file mode 100644 index 0000000000..da106b1517 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/bean/SearchEngines.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.bean; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.alfresco.config.Config; +import org.alfresco.config.ConfigService; +import org.alfresco.i18n.I18NUtil; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement; +import org.alfresco.web.scripts.DeclarativeWebScript; +import org.alfresco.web.scripts.Status; +import org.alfresco.web.scripts.WebScriptRequest; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * List of (server-side) registered Search Engines + * + * @author davidc + */ +public class SearchEngines extends DeclarativeWebScript +{ + // url argument values + public static final String URL_ARG_DESCRIPTION = "description"; + public static final String URL_ARG_TEMPLATE = "template"; + public static final String URL_ARG_ALL = "all"; + + // Logger + private static final Log logger = LogFactory.getLog(SearchEngines.class); + + // dependencies + protected ConfigService configService; + protected SearchProxy searchProxy; + + /** + * @param configService + */ + public void setConfigService(ConfigService configService) + { + this.configService = configService; + } + + /** + * @param searchProxy + */ + public void setSearchProxy(SearchProxy searchProxy) + { + this.searchProxy = searchProxy; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + @SuppressWarnings("deprecation") + @Override + protected Map executeImpl(WebScriptRequest req, Status status) + { + String urlType = req.getParameter("type"); + if (urlType == null || urlType.length() == 0) + { + urlType = URL_ARG_DESCRIPTION; + } + else if (!urlType.equals(URL_ARG_DESCRIPTION) && !urlType.equals(URL_ARG_TEMPLATE) && !urlType.equals(URL_ARG_ALL)) + { + urlType = URL_ARG_DESCRIPTION; + } + + // + // retrieve open search engines configuration + // + + Set urls = getUrls(urlType); + Map model = new HashMap(7, 1.0f); + model.put("urltype", urlType); + model.put("engines", urls); + return model; + } + + /** + * Retrieve registered search engines + * + * @return set of search engines + */ + private Set getUrls(String urlType) + { + if (logger.isDebugEnabled()) + logger.debug("Search Engine parameters: urltype=" + urlType); + + Set urls = new HashSet(); + Config config = configService.getConfig("OpenSearch"); + + OpenSearchConfigElement searchConfig = (OpenSearchConfigElement)config.getConfigElement(OpenSearchConfigElement.CONFIG_ELEMENT_ID); + for (OpenSearchConfigElement.EngineConfig engineConfig : searchConfig.getEngines()) + { + Map engineUrls = engineConfig.getUrls(); + for (Map.Entry engineUrl : engineUrls.entrySet()) + { + String type = engineUrl.getKey(); + String url = searchProxy.createUrl(engineConfig, type); + + if ((urlType.equals(URL_ARG_ALL)) || + (urlType.equals(URL_ARG_DESCRIPTION) && type.equals(MimetypeMap.MIMETYPE_OPENSEARCH_DESCRIPTION)) || + (urlType.equals(URL_ARG_TEMPLATE) && !type.equals(MimetypeMap.MIMETYPE_OPENSEARCH_DESCRIPTION))) + { + String label = engineConfig.getLabel(); + String labelId = engineConfig.getLabelId(); + if (labelId != null && labelId.length() > 0) + { + String i18nLabel = I18NUtil.getMessage(labelId); + if (i18nLabel == null && label == null) + { + label = (i18nLabel == null) ? "$$" + labelId + "$$" : i18nLabel; + } + } + urls.add(new UrlTemplate(label, type, url)); + } + + // TODO: Extract URL templates from OpenSearch description + else if (urlType.equals(URL_ARG_TEMPLATE) && + type.equals(MimetypeMap.MIMETYPE_OPENSEARCH_DESCRIPTION)) + { + } + } + } + + if (logger.isDebugEnabled()) + logger.debug("Retrieved " + urls.size() + " engine registrations"); + + return urls; + } + + /** + * Model object for representing a registered search engine + */ + public static class UrlTemplate + { + private String type; + private String label; + private String url; + private UrlTemplate engine; + + public UrlTemplate(String label, String type, String url) + { + this.label = label; + this.type = type; + this.url = url; + this.engine = null; + } + + public UrlTemplate(String label, String type, String url, UrlTemplate engine) + { + this(label, type, url); + this.engine = engine; + } + + public String getLabel() + { + return label; + } + + public String getType() + { + return type; + } + + public String getUrl() + { + return url; + } + + public String getUrlType() + { + return (type.equals(MimetypeMap.MIMETYPE_OPENSEARCH_DESCRIPTION) ? "description" : "template"); + } + + public UrlTemplate getEngine() + { + return engine; + } + } + +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/bean/SearchProxy.java b/source/java/org/alfresco/repo/web/scripts/bean/SearchProxy.java new file mode 100644 index 0000000000..bf56f81657 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/bean/SearchProxy.java @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.bean; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.config.Config; +import org.alfresco.config.ConfigService; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement; +import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement.EngineConfig; +import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement.ProxyConfig; +import org.alfresco.web.scripts.AbstractWebScript; +import org.alfresco.web.scripts.FormatRegistry; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.scripts.servlet.HTTPProxy; +import org.alfresco.web.scripts.servlet.WebScriptServletResponse; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.dom4j.Attribute; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.dom4j.XPath; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.SAXReader; +import org.dom4j.io.XMLWriter; +import org.springframework.beans.factory.InitializingBean; + + +/** + * Alfresco OpenSearch Proxy Service + * + * Provides the ability to submit a request to a registered search engine + * via the Alfresco server. + * + * @author davidc + */ +public class SearchProxy extends AbstractWebScript implements InitializingBean +{ + // Logger + private static final Log logger = LogFactory.getLog(SearchProxy.class); + + // dependencies + protected FormatRegistry formatRegistry; + protected ConfigService configService; + protected OpenSearchConfigElement searchConfig; + protected String proxyPath; + + /** + * @param formatRegistry + */ + public void setFormatRegistry(FormatRegistry formatRegistry) + { + this.formatRegistry = formatRegistry; + } + + /** + * @param configService + */ + public void setConfigService(ConfigService configService) + { + this.configService = configService; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + public void afterPropertiesSet() throws Exception + { + Config config = configService.getConfig("OpenSearch"); + searchConfig = (OpenSearchConfigElement)config.getConfigElement(OpenSearchConfigElement.CONFIG_ELEMENT_ID); + if (searchConfig == null) + { + throw new WebScriptException("OpenSearch configuration not found"); + } + ProxyConfig proxyConfig = searchConfig.getProxy(); + if (proxyConfig == null) + { + throw new WebScriptException("OpenSearch proxy configuration not found"); + } + proxyPath = proxyConfig.getUrl(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScript#execute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + public void execute(WebScriptRequest req, WebScriptResponse res) + throws IOException + { + String extensionPath = req.getExtensionPath(); + String[] extensionPaths = extensionPath.split("/"); + if (extensionPaths.length != 2) + { + throw new WebScriptException("OpenSearch engine has not been specified as /{engine}/{format}"); + } + + // retrieve search engine configuration + String engine = extensionPaths[0]; + EngineConfig engineConfig = searchConfig.getEngine(engine); + if (engineConfig == null) + { + throw new WebScriptException("OpenSearch engine '" + engine + "' does not exist"); + } + + // retrieve engine url as specified by format + String format = extensionPaths[1]; + String mimetype = formatRegistry.getMimeType(null, format); + if (mimetype == null) + { + throw new WebScriptException("Format '" + format + "' does not map to a registered mimetype"); + } + Map engineUrls = engineConfig.getUrls(); + String engineUrl = engineUrls.get(mimetype); + if (engineUrl == null) + { + throw new WebScriptException("Url mimetype '" + mimetype + "' does not exist for engine '" + engine + "'"); + } + + // replace template url arguments with actual arguments specified on request + int engineUrlArgIdx = engineUrl.indexOf("?"); + if (engineUrlArgIdx != -1) + { + engineUrl = engineUrl.substring(0, engineUrlArgIdx); + } + if (req.getQueryString() != null) + { + engineUrl += "?" + req.getQueryString(); + } + + if (logger.isDebugEnabled()) + logger.debug("Mapping engine '" + engine + "' (mimetype '" + mimetype + "') to url '" + engineUrl + "'"); + + // issue request against search engine + // NOTE: This web script must be executed in a HTTP servlet environment + if (!(res instanceof WebScriptServletResponse)) + { + throw new WebScriptException("Search Proxy must be executed in HTTP Servlet environment"); + } + HttpServletResponse servletRes = ((WebScriptServletResponse)res).getHttpServletResponse(); + SearchEngineHttpProxy proxy = new SearchEngineHttpProxy(req.getServicePath() + "/" + req.getContextPath(), engine, engineUrl, servletRes); + proxy.service(); + } + + /** + * OpenSearch HTTPProxy + * + * This proxy remaps OpenSearch links (e.g. previous, next) found in search results. + * + * @author davidc + */ + private class SearchEngineHttpProxy extends HTTPProxy + { + private final static String ATOM_NS_URI = "http://www.w3.org/2005/Atom"; + private final static String ATOM_NS_PREFIX = "atom"; + private final static String ATOM_LINK_XPATH = "atom:link[@rel=\"first\" or @rel=\"last\" or @rel=\"next\" or @rel=\"previous\" or @rel=\"self\" or @rel=\"alternate\"]"; + private String engine; + private String rootPath; + + /** + * Construct + * + * @param requestUrl + * @param response + * @throws MalformedURLException + */ + public SearchEngineHttpProxy(String rootPath, String engine, String engineUrl, HttpServletResponse response) + throws MalformedURLException + { + super(engineUrl.startsWith("/") ? rootPath + engineUrl : engineUrl, response); + this.engine = engine; + this.rootPath = rootPath; + } + + /* (non-Javadoc) + * @see org.alfresco.web.app.servlet.HTTPProxy#writeResponse(java.io.InputStream, java.io.OutputStream) + */ + @Override + protected void writeResponse(InputStream input, OutputStream output) + throws IOException + { + if (response.getContentType().startsWith(MimetypeMap.MIMETYPE_ATOM) || + response.getContentType().startsWith(MimetypeMap.MIMETYPE_RSS)) + { + // Only post-process ATOM and RSS feeds + // Replace all navigation links with "proxied" versions + SAXReader reader = new SAXReader(); + try + { + Document document = reader.read(input); + Element rootElement = document.getRootElement(); + + XPath xpath = rootElement.createXPath(ATOM_LINK_XPATH); + Map uris = new HashMap(); + uris.put(ATOM_NS_PREFIX, ATOM_NS_URI); + xpath.setNamespaceURIs(uris); + + List nodes = xpath.selectNodes(rootElement); + Iterator iter = nodes.iterator(); + while (iter.hasNext()) + { + Element element = (Element)iter.next(); + Attribute hrefAttr = element.attribute("href"); + String mimetype = element.attributeValue("type"); + if (mimetype == null || mimetype.length() == 0) + { + mimetype = MimetypeMap.MIMETYPE_HTML; + } + String url = createUrl(engine, hrefAttr.getValue(), mimetype); + if (url.startsWith("/")) + { + url = rootPath + url; + } + hrefAttr.setValue(url); + } + + OutputFormat outputFormat = OutputFormat.createPrettyPrint(); + XMLWriter writer = new XMLWriter(output, outputFormat); + writer.write(rootElement); + writer.flush(); + } + catch(DocumentException e) + { + throw new IOException(e.toString()); + } + } + else + { + super.writeResponse(input, output); + } + } + } + + /** + * Construct a "proxied" search engine url + * + * @param engine engine name (as identified by ) + * @param mimetype url to proxy (as identified by mimetype) + * @return "proxied" url + */ + public String createUrl(OpenSearchConfigElement.EngineConfig engine, String mimetype) + { + Map urls = engine.getUrls(); + String url = urls.get(mimetype); + if (url != null) + { + String proxy = engine.getProxy(); + if (proxy != null && !mimetype.equals(MimetypeMap.MIMETYPE_OPENSEARCH_DESCRIPTION)) + { + url = createUrl(proxy, url, mimetype); + } + } + return url; + } + + /** + * Construct a "proxied" search engine url + * + * @param engine engine name (as identified by ) + * @param url engine url + * @param mimetype mimetype of url + * @return "proxied" url + */ + public String createUrl(String engine, String url, String mimetype) + { + String format = formatRegistry.getFormat(null, mimetype); + if (format == null) + { + throw new WebScriptException("Mimetype '" + mimetype + "' is not registered."); + } + + String proxyUrl = null; + int argIdx = url.indexOf("?"); + if (argIdx == -1) + { + proxyUrl = proxyPath + "/" + engine + "/" + format; + } + else + { + proxyUrl = proxyPath + "/" + engine + "/" + format + url.substring(argIdx); + } + return proxyUrl; + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/config/OpenSearchConfigElement.java b/source/java/org/alfresco/repo/web/scripts/config/OpenSearchConfigElement.java new file mode 100644 index 0000000000..1fe73ebf24 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/config/OpenSearchConfigElement.java @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.config; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.alfresco.config.ConfigElement; +import org.alfresco.config.ConfigException; +import org.alfresco.config.element.ConfigElementAdapter; + + +/** + * Custom config element that represents the config data for open search + * + * @author davidc + */ +public class OpenSearchConfigElement extends ConfigElementAdapter +{ + public static final String CONFIG_ELEMENT_ID = "opensearch"; + + private ProxyConfig proxy; + private Set engines = new HashSet(8, 10f); + private Map enginesByProxy = new HashMap(); + + + /** + * Default constructor + */ + public OpenSearchConfigElement() + { + super(CONFIG_ELEMENT_ID); + } + + /** + * Constructor + * + * @param name Name of the element this config element represents + */ + public OpenSearchConfigElement(String name) + { + super(name); + } + + /** + * @see org.alfresco.config.ConfigElement#getChildren() + */ + public List getChildren() + { + throw new ConfigException("Reading the open search config via the generic interfaces is not supported"); + } + + /** + * @see org.alfresco.config.ConfigElement#combine(org.alfresco.config.ConfigElement) + */ + public ConfigElement combine(ConfigElement configElement) + { + OpenSearchConfigElement newElement = (OpenSearchConfigElement) configElement; + OpenSearchConfigElement combinedElement = new OpenSearchConfigElement(); + + // add all the plugins from this element + for (EngineConfig plugin : this.getEngines()) + { + combinedElement.addEngine(plugin); + } + + // add all the plugins from the given element + for (EngineConfig plugin : newElement.getEngines()) + { + combinedElement.addEngine(plugin); + } + + // set the proxy configuration + ProxyConfig proxyConfig = this.getProxy(); + if (proxyConfig != null) + { + combinedElement.setProxy(proxyConfig); + } + + return combinedElement; + } + + /** + * Sets the proxy configuration + * + * @param proxyConfig + */ + /*package*/ void setProxy(ProxyConfig proxyConfig) + { + this.proxy = proxyConfig; + } + + /** + * Gets the proxy configuration + * + * @return The proxy configuration + */ + public ProxyConfig getProxy() + { + return this.proxy; + } + + /** + * @return Returns a set of the engines + */ + public Set getEngines() + { + return this.engines; + } + + /** + * @param proxy name of engine proxy + * @return associated engine config (or null, if none registered against proxy) + */ + public EngineConfig getEngine(String proxy) + { + return this.enginesByProxy.get(proxy); + } + + /** + * Adds an engine + * + * @param pluginConfig A pre-configured engine config object + */ + /*package*/ void addEngine(EngineConfig engineConfig) + { + this.engines.add(engineConfig); + String proxy = engineConfig.getProxy(); + if (proxy != null && proxy.length() > 0) + { + this.enginesByProxy.put(proxy, engineConfig); + } + } + + + /** + * Inner class representing the configuration of an OpenSearch engine + * + * @author davidc + */ + public static class EngineConfig + { + protected String label; + protected String labelId; + protected String proxy; + protected Map urls = new HashMap(8, 10f); + + + /** + * Construct + * + * @param label + * @param labelId + */ + public EngineConfig(String label, String labelId) + { + if ((label == null || label.length() == 0) && (labelId == null || labelId.length() == 0)) + { + throw new IllegalArgumentException("'label' or 'label-id' must be specified"); + } + this.label = label; + this.labelId = labelId; + } + + /** + * Construct + * + * @param label + * @param labelId + * @param proxy + */ + public EngineConfig(String label, String labelId, String proxy) + { + this(label, labelId); + this.proxy = proxy; + } + + /** + * @return I18N label id + */ + public String getLabelId() + { + return labelId; + } + + /** + * @return label + */ + public String getLabel() + { + return label; + } + + /** + * @return proxy + */ + public String getProxy() + { + return proxy; + } + + /** + * Gets the urls supported by this engine + * + * @return urls + */ + public Map getUrls() + { + return urls; + } + + /** + * Adds a url + * + * @param pluginConfig A pre-configured plugin config object + */ + /*package*/ void addUrl(String mimetype, String uri) + { + this.urls.put(mimetype, uri); + } + + } + + + /** + * Inner class representing the configuration of the OpenSearch proxy + * + * @author davidc + */ + public static class ProxyConfig + { + protected String url; + + /** + * Construct + * + * @param url + */ + public ProxyConfig(String url) + { + if (url == null || url.length() == 0) + { + throw new IllegalArgumentException("'url' must be specified"); + } + this.url = url; + } + + /** + * @return url + */ + public String getUrl() + { + return url; + } + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/config/OpenSearchElementReader.java b/source/java/org/alfresco/repo/web/scripts/config/OpenSearchElementReader.java new file mode 100644 index 0000000000..2d52551990 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/config/OpenSearchElementReader.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.config; + +import java.util.Iterator; + +import org.alfresco.config.ConfigElement; +import org.alfresco.config.ConfigException; +import org.alfresco.config.xml.elementreader.ConfigElementReader; +import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement.EngineConfig; +import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement.ProxyConfig; +import org.dom4j.Element; + + +/** + * Custom element reader to parse config for the open search + * + * @author davidc + */ +public class OpenSearchElementReader implements ConfigElementReader +{ + public static final String ELEMENT_OPENSEARCH = "opensearch"; + public static final String ELEMENT_ENGINES = "engines"; + public static final String ELEMENT_ENGINE = "engine"; + public static final String ELEMENT_URL = "url"; + public static final String ELEMENT_PROXY = "proxy"; + public static final String ATTR_TYPE = "type"; + public static final String ATTR_LABEL = "label"; + public static final String ATTR_LABEL_ID = "label-id"; + public static final String ATTR_PROXY = "proxy"; + + + /** + * @see org.alfresco.config.xml.elementreader.ConfigElementReader#parse(org.dom4j.Element) + */ + @SuppressWarnings("unchecked") + public ConfigElement parse(Element element) + { + OpenSearchConfigElement configElement = null; + + if (element != null) + { + String elementName = element.getName(); + if (elementName.equals(ELEMENT_OPENSEARCH) == false) + { + throw new ConfigException("OpenSearchElementReader can only parse " + ELEMENT_OPENSEARCH + + "elements, the element passed was '" + elementName + "'"); + } + + // go through the registered engines + configElement = new OpenSearchConfigElement(); + Element pluginsElem = element.element(ELEMENT_ENGINES); + if (pluginsElem != null) + { + Iterator engines = pluginsElem.elementIterator(ELEMENT_ENGINE); + while(engines.hasNext()) + { + // construct engine + Element engineElem = engines.next(); + String label = engineElem.attributeValue(ATTR_LABEL); + String labelId = engineElem.attributeValue(ATTR_LABEL_ID); + String proxy = engineElem.attributeValue(ATTR_PROXY); + EngineConfig engineCfg = new EngineConfig(label, labelId, proxy); + + // construct urls for engine + Iterator urlsConfig = engineElem.elementIterator(ELEMENT_URL); + while (urlsConfig.hasNext()) + { + Element urlConfig = urlsConfig.next(); + String type = urlConfig.attributeValue(ATTR_TYPE); + String url = urlConfig.getTextTrim(); + engineCfg.addUrl(type, url); + } + + // register engine config + configElement.addEngine(engineCfg); + } + } + + // extract proxy configuration + String url = null; + Element proxyElem = element.element(ELEMENT_PROXY); + if (proxyElem != null) + { + Element urlElem = proxyElem.element(ELEMENT_URL); + if (urlElem != null) + { + url = urlElem.getTextTrim(); + ProxyConfig proxyCfg = new ProxyConfig(url); + configElement.setProxy(proxyCfg); + } + } + } + + return configElement; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/facebook/FacebookAuthenticatorFactory.java b/source/java/org/alfresco/repo/web/scripts/facebook/FacebookAuthenticatorFactory.java new file mode 100644 index 0000000000..f4b3e811aa --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/facebook/FacebookAuthenticatorFactory.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.facebook; + +import java.io.IOException; + +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.web.scripts.Authenticator; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.Description.RequiredAuthentication; +import org.alfresco.web.scripts.facebook.FacebookServletRequest; +import org.alfresco.web.scripts.servlet.ServletAuthenticatorFactory; +import org.alfresco.web.scripts.servlet.WebScriptServletRequest; +import org.alfresco.web.scripts.servlet.WebScriptServletResponse; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Web Script Authenticator that supports Facebook authentication + * mechanism. + * + * Upon success, the request is authenticated as the Facebook User Id. + * + * @author davidc + */ +public class FacebookAuthenticatorFactory implements ServletAuthenticatorFactory +{ + // Logger + private static final Log logger = LogFactory.getLog(FacebookAuthenticator.class); + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.servlet.ServletAuthenticatorFactory#create(org.alfresco.web.scripts.servlet.WebScriptServletRequest, org.alfresco.web.scripts.servlet.WebScriptServletResponse) + */ + public Authenticator create(WebScriptServletRequest req, WebScriptServletResponse res) + { + if (!(req instanceof FacebookServletRequest)) + { + throw new WebScriptException("Facebook request is required; instead a " + req.getClass().getName() + " has been provided"); + } + return new FacebookAuthenticator((FacebookServletRequest)req, res); + } + + + /** + * Web Script Authenticator that supports Facebook authentication + * mechanism. + * + * Upon success, the request is authenticated as the Facebook User Id. + * + * @author davidc + */ + public class FacebookAuthenticator implements Authenticator + { + + // FBML for Facebook login redirect + private static final String LOGIN_REDIRECT = ""; + + + // dependencies + private FacebookServletRequest fbReq; + private WebScriptServletResponse fbRes; + + /** + * Construct + * + * @param authenticationService + * @param req + * @param res + */ + public FacebookAuthenticator(FacebookServletRequest req, WebScriptServletResponse res) + { + this.fbReq = req; + this.fbRes = res; + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) + */ + public boolean authenticate(RequiredAuthentication required, boolean isGuest) + { + String sessionKey = fbReq.getSessionKey(); + String user = fbReq.getUserId(); + + if (logger.isDebugEnabled()) + { + logger.debug("fb_sig_session_key = '" + sessionKey + "'"); + logger.debug("fb_sig_user = '" + user + "'"); + } + + if ((sessionKey == null || sessionKey.length() == 0) || (user == null || user.length() == 0)) + { + // session has not been established, redirect to login + + String apiKey = fbReq.getApiKey(); + String canvas = (fbReq.isInCanvas()) ? "&canvas" : ""; + + if (logger.isDebugEnabled()) + { + logger.debug("fb_sig_api_key = '" + apiKey + "'"); + logger.debug("fb_sig_in_canvas = '" + canvas + "'"); + } + + try + { + String redirect = String.format(LOGIN_REDIRECT, apiKey, canvas); + + if (logger.isDebugEnabled()) + logger.debug("Facebook session not established; redirecting via " + redirect); + + fbRes.getWriter().write(redirect); + } + catch (IOException e) + { + throw new WebScriptException("Redirect to login failed", e); + } + return false; + } + + if (logger.isDebugEnabled()) + logger.debug("Facebook session established; authenticating as user " + user); + + // session has been established, authenticate as Facebook user id + AuthenticationUtil.setCurrentUser(user); + return true; + } + } + +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/portlet/JSR168PortletAuthenticatorFactory.java b/source/java/org/alfresco/repo/web/scripts/portlet/JSR168PortletAuthenticatorFactory.java new file mode 100644 index 0000000000..d8ab2b7dc8 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/portlet/JSR168PortletAuthenticatorFactory.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.portlet; + +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; +import javax.servlet.http.HttpServletResponse; +import javax.transaction.UserTransaction; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.web.scripts.Authenticator; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.Description.RequiredAuthentication; +import org.alfresco.web.scripts.portlet.PortletAuthenticatorFactory; +import org.alfresco.web.scripts.portlet.WebScriptPortletRequest; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Portlet authenticator + * + * @author davidc + */ +public class JSR168PortletAuthenticatorFactory implements PortletAuthenticatorFactory +{ + // Logger + private static final Log logger = LogFactory.getLog(JSR168PortletAuthenticatorFactory.class); + + // dependencies + private AuthenticationService unprotAuthenticationService; + private TransactionService txnService; + + /** + * @param authenticationService + */ + public void setUnprotAuthenticationService(AuthenticationService authenticationService) + { + this.unprotAuthenticationService = authenticationService; + } + + /** + * @param transactionService + */ + public void setTransactionService(TransactionService transactionService) + { + this.txnService = transactionService; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.portlet.PortletAuthenticatorFactory#create(javax.portlet.RenderRequest, javax.portlet.RenderResponse) + */ + public Authenticator create(RenderRequest req, RenderResponse res) + { + return new JSR168PortletAuthenticator(req, res); + } + + + /** + * Portlet authenticator + * + * @author davidc + */ + public class JSR168PortletAuthenticator implements Authenticator + { + // dependencies + private RenderRequest req; + + /** + * Construct + * + * @param authenticationService + * @param req + * @param res + */ + public JSR168PortletAuthenticator(RenderRequest req, RenderResponse res) + { + this.req = req; + } + + /*(non-Javadoc) + * @see org.alfresco.web.scripts.Authenticator#authenticate(org.alfresco.web.scripts.Description.RequiredAuthentication, boolean) + */ + public boolean authenticate(RequiredAuthentication required, boolean isGuest) + { + // first look for the username key in the session - we add this by hand for some portals + // when the WebScriptPortletRequest is created + String portalUser = (String)req.getPortletSession().getAttribute(WebScriptPortletRequest.ALFPORTLETUSERNAME); + if (portalUser == null) + { + portalUser = req.getRemoteUser(); + } + + if (logger.isDebugEnabled()) + { + logger.debug("JSR-168 Remote user: " + portalUser); + } + + if (isGuest || portalUser == null) + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating as Guest"); + + // authenticate as guest + AuthenticationUtil.setCurrentUser(AuthenticationUtil.getGuestUserName()); + } + else + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating as user " + portalUser); + + UserTransaction txn = null; + try + { + txn = txnService.getUserTransaction(); + txn.begin(); + + if (!unprotAuthenticationService.authenticationExists(portalUser)) + { + throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "User " + portalUser + " is not a known Alfresco user"); + } + AuthenticationUtil.setCurrentUser(portalUser); + } + catch (Throwable err) + { + throw new AlfrescoRuntimeException("Error authenticating user: " + portalUser, err); + } + finally + { + try + { + if (txn != null) + { + txn.rollback(); + } + } + catch (Exception tex) + { + // nothing useful we can do with this + } + } + } + + return true; + } + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/servlet/BasicHttpAuthenticatorFactory.java b/source/java/org/alfresco/repo/web/scripts/servlet/BasicHttpAuthenticatorFactory.java new file mode 100644 index 0000000000..333a69facc --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/servlet/BasicHttpAuthenticatorFactory.java @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.servlet; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.repo.security.authentication.AuthenticationException; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.util.Base64; +import org.alfresco.web.scripts.Authenticator; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.Description.RequiredAuthentication; +import org.alfresco.web.scripts.servlet.ServletAuthenticatorFactory; +import org.alfresco.web.scripts.servlet.WebScriptServletRequest; +import org.alfresco.web.scripts.servlet.WebScriptServletResponse; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * HTTP Basic Authentication + * + * @author davidc + */ +public class BasicHttpAuthenticatorFactory implements ServletAuthenticatorFactory +{ + // Logger + private static Log logger = LogFactory.getLog(BasicHttpAuthenticator.class); + + // Component dependencies + private AuthenticationService authenticationService; + + + /** + * @param authenticationService + */ + public void setAuthenticationService(AuthenticationService authenticationService) + { + this.authenticationService = authenticationService; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.servlet.ServletAuthenticatorFactory#create(org.alfresco.web.scripts.servlet.WebScriptServletRequest, org.alfresco.web.scripts.servlet.WebScriptServletResponse) + */ + public Authenticator create(WebScriptServletRequest req, WebScriptServletResponse res) + { + return new BasicHttpAuthenticator(req, res); + } + + + /** + * HTTP Basic Authentication + * + * @author davidc + */ + public class BasicHttpAuthenticator implements Authenticator + { + // dependencies + private WebScriptServletRequest servletReq; + private WebScriptServletResponse servletRes; + + /** + * Construct + * + * @param authenticationService + * @param req + * @param res + */ + public BasicHttpAuthenticator(WebScriptServletRequest req, WebScriptServletResponse res) + { + this.servletReq = req; + this.servletRes = res; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.Authenticator#authenticate(org.alfresco.web.scripts.Description.RequiredAuthentication, boolean) + */ + public boolean authenticate(RequiredAuthentication required, boolean isGuest) + { + boolean authorized = false; + + // + // validate credentials + // + + HttpServletRequest req = servletReq.getHttpServletRequest(); + HttpServletResponse res = servletRes.getHttpServletResponse(); + String authorization = req.getHeader("Authorization"); + String ticket = req.getParameter("alf_ticket"); + + if (logger.isDebugEnabled()) + { + logger.debug("HTTP Authorization provided: " + (authorization != null && authorization.length() > 0)); + logger.debug("URL ticket provided: " + (ticket != null && ticket.length() > 0)); + } + + // authenticate as guest, if service allows + if (isGuest && RequiredAuthentication.guest == required) + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating as Guest"); + + authenticationService.authenticateAsGuest(); + authorized = true; + } + + // authenticate as specified by explicit ticket on url + else if (ticket != null && ticket.length() > 0) + { + try + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating (URL argument) ticket " + ticket); + + // assume a ticket has been passed + authenticationService.validate(ticket); + authorized = true; + } + catch(AuthenticationException e) + { + // failed authentication + } + } + + // authenticate as specified by HTTP Basic Authentication + else if (authorization != null && authorization.length() > 0) + { + try + { + String[] authorizationParts = authorization.split(" "); + if (!authorizationParts[0].equalsIgnoreCase("basic")) + { + throw new WebScriptException("Authorization '" + authorizationParts[0] + "' not supported."); + } + String decodedAuthorisation = new String(Base64.decode(authorizationParts[1])); + String[] parts = decodedAuthorisation.split(":"); + + if (parts.length == 1) + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating (BASIC HTTP) ticket " + parts[0]); + + // assume a ticket has been passed + authenticationService.validate(parts[0]); + authorized = true; + } + else + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating (BASIC HTTP) user " + parts[0]); + + // assume username and password passed + if (parts[0].equals(AuthenticationUtil.getGuestUserName())) + { + if (required == RequiredAuthentication.guest) + { + authenticationService.authenticateAsGuest(); + authorized = true; + } + } + else + { + authenticationService.authenticate(parts[0], parts[1].toCharArray()); + authorized = true; + } + } + } + catch(AuthenticationException e) + { + // failed authentication + } + } + + // + // request credentials if not authorized + // + + if (!authorized) + { + if (logger.isDebugEnabled()) + logger.debug("Requesting authorization credentials"); + + res.setStatus(401); + res.setHeader("WWW-Authenticate", "Basic realm=\"Alfresco\""); + } + return authorized; + } + } + +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/site/TestSiteService.java b/source/java/org/alfresco/repo/web/scripts/site/TestSiteService.java new file mode 100644 index 0000000000..1957f4b9df --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/site/TestSiteService.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.site; + +import org.alfresco.repo.web.scripts.BaseWebScriptTest; +import org.alfresco.util.GUID; +import org.json.JSONArray; +import org.json.JSONObject; +import org.springframework.mock.web.MockHttpServletResponse; + +/** + * Unit test to test site Web Script API + * + * @author Roy Wetherall + */ +public class TestSiteService extends BaseWebScriptTest +{ + private static final String URL_SITES = "/api/sites"; + + public void testCreateSite() throws Exception + { + String shortName = GUID.generate(); + + // == Create a new site == + + JSONObject site = new JSONObject(); + site.put("sitePreset", "myPreset"); + site.put("shortName", shortName); + site.put("title", "myTitle"); + site.put("description", "myDescription"); + site.put("isPublic", true); + + MockHttpServletResponse response = postRequest(URL_SITES, 200, site.toString(), "application/json"); + + JSONObject result = new JSONObject(response.getContentAsString()); + + assertEquals("myPreset", result.get("sitePreset")); + assertEquals(shortName, result.get("shortName")); + assertEquals("myTitle", result.get("title")); + assertEquals("myDescription", result.get("description")); + assertTrue(result.getBoolean("isPublic")); + + // == Create a site with a duplicate shortName == + + response = postRequest(URL_SITES, 500, site.toString(), "application/json"); + result = new JSONObject(response.getContentAsString()); + } + + public void testGetSites() throws Exception + { + // == Test basic GET with no filters == + + MockHttpServletResponse response = getRequest(URL_SITES, 200); + JSONArray result = new JSONArray(response.getContentAsString()); + + // TODO formalise this test once i can be sure that i know what's already in the site store + // ie: .. i need to clean up after myself in this test + + System.out.println(response.getContentAsString()); + } + +}