Merge branch 'webapp22' into 'master'
Version 2.2.0 RC1 Release Candidate 1 of 2.2.0 version. See changelog for changes... See merge request !1
This commit is contained in:
commit
187b2a60f2
8
.idea/calendarimporter.iml
Normal file
8
.idea/calendarimporter.iml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
3
.idea/copyright/profiles_settings.xml
Normal file
3
.idea/copyright/profiles_settings.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<component name="CopyrightManager">
|
||||
<settings default="" />
|
||||
</component>
|
4
.idea/encodings.xml
Normal file
4
.idea/encodings.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
|
||||
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/calendarimporter.iml" filepath="$PROJECT_DIR$/.idea/calendarimporter.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
4
.idea/php.xml
Normal file
4
.idea/php.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="5.5.0" />
|
||||
</project>
|
5
.idea/scopes/scope_settings.xml
Normal file
5
.idea/scopes/scope_settings.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<component name="DependencyValidationManager">
|
||||
<state>
|
||||
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
|
||||
</state>
|
||||
</component>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
677
.idea/workspace.xml
Normal file
677
.idea/workspace.xml
Normal file
@ -0,0 +1,677 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="e7c9c2bb-66f1-4e37-904c-d33d8c113bde" name="Default" comment="">
|
||||
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/changelog.txt" afterPath="$PROJECT_DIR$/changelog.txt" />
|
||||
</list>
|
||||
<ignored path="calendarimporter.iws" />
|
||||
<ignored path=".idea/workspace.xml" />
|
||||
<ignored path=".idea/dataSources.local.xml" />
|
||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||
<option name="TRACKING_ENABLED" value="true" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="CreatePatchCommitExecutor">
|
||||
<option name="PATCH_PATH" value="" />
|
||||
</component>
|
||||
<component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
|
||||
<component name="FavoritesManager">
|
||||
<favorites_list name="calendarimporter" />
|
||||
</component>
|
||||
<component name="FileEditorManager">
|
||||
<leaf>
|
||||
<file leaf-file-name="CalSyncEditPanel.js" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/js/settings/dialogs/CalSyncEditPanel.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="1480">
|
||||
<caret line="101" column="30" selection-start-line="101" selection-start-column="30" selection-end-line="101" selection-end-column="30" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="CalSyncGrid.js" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/js/settings/ui/CalSyncGrid.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="504">
|
||||
<caret line="85" column="59" selection-start-line="85" selection-start-column="59" selection-end-line="85" selection-end-column="59" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="SettingsCalSyncWidget.js" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/js/settings/SettingsCalSyncWidget.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="729">
|
||||
<caret line="104" column="16" selection-start-line="104" selection-start-column="16" selection-end-line="104" selection-end-column="142" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="sync.php" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/backend/sync.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="360">
|
||||
<caret line="24" column="47" selection-start-line="24" selection-start-column="47" selection-end-line="24" selection-end-column="47" />
|
||||
<folding>
|
||||
<element signature="e#21#926#0#PHP" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="changelog.txt" pinned="false" current-in-tab="true">
|
||||
<entry file="file://$PROJECT_DIR$/changelog.txt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="75">
|
||||
<caret line="5" column="19" selection-start-line="5" selection-start-column="19" selection-end-line="5" selection-end-column="19" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="manifest.xml" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/manifest.xml">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="functions.php" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/backend/functions.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="75">
|
||||
<caret line="5" column="26" selection-start-line="5" selection-start-column="26" selection-end-line="5" selection-end-column="26" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="README.txt" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/backend/README.txt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="config.php" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/backend/config.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="CalSyncEditContentPanel.js" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/js/settings/dialogs/CalSyncEditContentPanel.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="63" selection-start-line="0" selection-start-column="63" selection-end-line="0" selection-end-column="63" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
</leaf>
|
||||
</component>
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="JavaScript File" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="IdeDocumentHistory">
|
||||
<option name="CHANGED_PATHS">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/php/plugin.calendarimporter.php" />
|
||||
<option value="$PROJECT_DIR$/config.php" />
|
||||
<option value="$PROJECT_DIR$/js/plugin.calendarimporter.js" />
|
||||
<option value="$PROJECT_DIR$/php/module.calendar.php" />
|
||||
<option value="$PROJECT_DIR$/js/data/CalendarHelper.js" />
|
||||
<option value="$PROJECT_DIR$/js/data/Actions.js" />
|
||||
<option value="$PROJECT_DIR$/js/dialogs/ImportPanel.js" />
|
||||
<option value="$PROJECT_DIR$/js/settings/dialogs/CalSyncEditContentPanel.js" />
|
||||
<option value="$PROJECT_DIR$/js/settings/SettingsWidget.js" />
|
||||
<option value="$PROJECT_DIR$/js/settings/SettingsCalSyncWidget.js" />
|
||||
<option value="$PROJECT_DIR$/js/settings/ui/CalSyncGrid.js" />
|
||||
<option value="$PROJECT_DIR$/js/settings/dialogs/CalSyncEditPanel.js" />
|
||||
<option value="$PROJECT_DIR$/backend/sync.php" />
|
||||
<option value="$PROJECT_DIR$/backend/functions.php" />
|
||||
<option value="$PROJECT_DIR$/changelog.txt" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||
<component name="JsGulpfileManager">
|
||||
<detection-done>true</detection-done>
|
||||
<sorting>DEFINITION_ORDER</sorting>
|
||||
</component>
|
||||
<component name="PhpWorkspaceProjectConfiguration" backward_compatibility_performed="true" />
|
||||
<component name="ProjectFrameBounds">
|
||||
<option name="x" value="65" />
|
||||
<option name="y" value="24" />
|
||||
<option name="width" value="1792" />
|
||||
<option name="height" value="999" />
|
||||
</component>
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||
<OptionsSetting value="true" id="Add" />
|
||||
<OptionsSetting value="true" id="Remove" />
|
||||
<OptionsSetting value="true" id="Checkout" />
|
||||
<OptionsSetting value="true" id="Update" />
|
||||
<OptionsSetting value="true" id="Status" />
|
||||
<OptionsSetting value="true" id="Edit" />
|
||||
<ConfirmationsSetting value="0" id="Add" />
|
||||
<ConfirmationsSetting value="0" id="Remove" />
|
||||
</component>
|
||||
<component name="ProjectView">
|
||||
<navigator currentView="ProjectPane" proportions="" version="1">
|
||||
<flattenPackages />
|
||||
<showMembers />
|
||||
<showModules />
|
||||
<showLibraryContents />
|
||||
<hideEmptyPackages />
|
||||
<abbreviatePackageNames />
|
||||
<autoscrollToSource />
|
||||
<autoscrollFromSource />
|
||||
<sortByType />
|
||||
<manualOrder />
|
||||
<foldersAlwaysOnTop value="true" />
|
||||
</navigator>
|
||||
<panes>
|
||||
<pane id="Scratches" />
|
||||
<pane id="ProjectPane">
|
||||
<subPane>
|
||||
<PATH>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||
</PATH_ELEMENT>
|
||||
</PATH>
|
||||
<PATH>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
</PATH>
|
||||
<PATH>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="js" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
</PATH>
|
||||
<PATH>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="js" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="ui" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
</PATH>
|
||||
<PATH>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="js" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="settings" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
</PATH>
|
||||
<PATH>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="js" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="settings" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="ui" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
</PATH>
|
||||
<PATH>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="js" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="settings" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="dialogs" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
</PATH>
|
||||
<PATH>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="js" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="dialogs" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
</PATH>
|
||||
<PATH>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="js" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="data" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
</PATH>
|
||||
<PATH>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="calendarimporter" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="backend" />
|
||||
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||
</PATH_ELEMENT>
|
||||
</PATH>
|
||||
</subPane>
|
||||
</pane>
|
||||
<pane id="Scope" />
|
||||
</panes>
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||
<property name="js-jscs-nodeInterpreter" value="/usr/bin/node" />
|
||||
</component>
|
||||
<component name="RunManager">
|
||||
<configuration default="true" type="JavascriptDebugType" factoryName="JavaScript Debug">
|
||||
<method />
|
||||
</configuration>
|
||||
<configuration default="true" type="NodeJSConfigurationType" factoryName="Node.js" path-to-node="project" working-dir="">
|
||||
<method />
|
||||
</configuration>
|
||||
<configuration default="true" type="PHPUnitRunConfigurationType" factoryName="PHPUnit">
|
||||
<TestRunner />
|
||||
<method />
|
||||
</configuration>
|
||||
<configuration default="true" type="PhpBehatConfigurationType" factoryName="Behat">
|
||||
<BehatRunner />
|
||||
<method />
|
||||
</configuration>
|
||||
<configuration default="true" type="PhpLocalRunConfigurationType" factoryName="PHP Console">
|
||||
<method />
|
||||
</configuration>
|
||||
<configuration default="true" type="js.build_tools.gulp" factoryName="Gulp.js">
|
||||
<method />
|
||||
</configuration>
|
||||
<configuration default="true" type="js.build_tools.npm" factoryName="npm">
|
||||
<command value="run-script" />
|
||||
<scripts />
|
||||
<node-interpreter value="project" />
|
||||
<envs />
|
||||
<method />
|
||||
</configuration>
|
||||
<configuration default="true" type="mocha-javascript-test-runner" factoryName="Mocha">
|
||||
<node-interpreter>project</node-interpreter>
|
||||
<node-options />
|
||||
<working-directory />
|
||||
<pass-parent-env>true</pass-parent-env>
|
||||
<envs />
|
||||
<ui />
|
||||
<extra-mocha-options />
|
||||
<test-kind>DIRECTORY</test-kind>
|
||||
<test-directory />
|
||||
<recursive>false</recursive>
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
||||
<component name="ShelveChangesManager" show_recycled="false">
|
||||
<option name="remove_strategy" value="false" />
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="e7c9c2bb-66f1-4e37-904c-d33d8c113bde" name="Default" comment="" />
|
||||
<created>1477949602474</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1477949602474</updated>
|
||||
<workItem from="1477949603566" duration="8606000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TimeTrackingManager">
|
||||
<option name="totallyTimeSpent" value="8606000" />
|
||||
</component>
|
||||
<component name="ToolWindowManager">
|
||||
<frame x="65" y="24" width="1792" height="999" extended-state="6" />
|
||||
<editor active="true" />
|
||||
<layout>
|
||||
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
|
||||
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
|
||||
<window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32900432" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32900432" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
|
||||
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
|
||||
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||
</layout>
|
||||
</component>
|
||||
<component name="Vcs.Log.UiProperties">
|
||||
<option name="RECENTLY_FILTERED_USER_GROUPS">
|
||||
<collection />
|
||||
</option>
|
||||
<option name="RECENTLY_FILTERED_BRANCH_GROUPS">
|
||||
<collection />
|
||||
</option>
|
||||
</component>
|
||||
<component name="VcsContentAnnotationSettings">
|
||||
<option name="myLimit" value="2678400000" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<option name="time" value="1" />
|
||||
</breakpoint-manager>
|
||||
<watches-manager />
|
||||
</component>
|
||||
<component name="editorHistoryManager">
|
||||
<entry file="file://$PROJECT_DIR$/Makefile">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/php/composer.json">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/php/upload.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/js/data/ResponseHandler.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-456">
|
||||
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="n#!!doc" expanded="false" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/php/module.calendar.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="1057">
|
||||
<caret line="467" column="64" selection-start-line="467" selection-start-column="64" selection-end-line="467" selection-end-column="64" />
|
||||
<folding>
|
||||
<element signature="n#__construct#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||
<element signature="n#execute#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||
<element signature="n#randomstring#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||
<element signature="n#getDurationStringFromMintues#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||
<element signature="n#exportCalendar#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||
<element signature="n#importCalendar#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||
<element signature="n#getAttachmentPath#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||
<element signature="n#loadCalendar#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||
<element signature="n#parseCalendarToArray#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/config.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="60">
|
||||
<caret line="4" column="60" selection-start-line="4" selection-start-column="12" selection-end-line="4" selection-end-column="60" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/php/plugin.calendarimporter.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="569">
|
||||
<caret line="82" column="40" selection-start-line="82" selection-start-column="29" selection-end-line="82" selection-end-column="40" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/js/dialogs/ImportContentPanel.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-171">
|
||||
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="n#!!doc" expanded="false" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/js/data/CalendarHelper.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/js/dialogs/ImportPanel.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="332">
|
||||
<caret line="245" column="12" selection-start-line="245" selection-start-column="12" selection-end-line="245" selection-end-column="226" />
|
||||
<folding>
|
||||
<element signature="n#!!doc" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/js/data/Actions.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="144">
|
||||
<caret line="133" column="67" selection-start-line="133" selection-start-column="22" selection-end-line="133" selection-end-column="67" />
|
||||
<folding>
|
||||
<element signature="n#!!doc" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/js/settings/SettingsWidget.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="340">
|
||||
<caret line="83" column="82" selection-start-line="83" selection-start-column="82" selection-end-line="83" selection-end-column="82" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/js/plugin.calendarimporter.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-51">
|
||||
<caret line="262" column="12" selection-start-line="262" selection-start-column="12" selection-end-line="262" selection-end-column="12" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/js/settings/ui/CalSyncGrid.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="504">
|
||||
<caret line="85" column="59" selection-start-line="85" selection-start-column="59" selection-end-line="85" selection-end-column="59" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/js/settings/SettingsCalSyncWidget.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="729">
|
||||
<caret line="104" column="16" selection-start-line="104" selection-start-column="16" selection-end-line="104" selection-end-column="142" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/js/settings/dialogs/CalSyncEditContentPanel.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="63" selection-start-line="0" selection-start-column="63" selection-end-line="0" selection-end-column="63" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/js/settings/dialogs/CalSyncEditPanel.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="1480">
|
||||
<caret line="101" column="30" selection-start-line="101" selection-start-column="30" selection-end-line="101" selection-end-column="30" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/backend/functions.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="75">
|
||||
<caret line="5" column="26" selection-start-line="5" selection-start-column="26" selection-end-line="5" selection-end-column="26" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/backend/config.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/backend/README.txt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/backend/sync.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="360">
|
||||
<caret line="24" column="47" selection-start-line="24" selection-start-column="47" selection-end-line="24" selection-end-column="47" />
|
||||
<folding>
|
||||
<element signature="e#21#926#0#PHP" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/manifest.xml">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/changelog.txt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="75">
|
||||
<caret line="5" column="19" selection-start-line="5" selection-start-column="19" selection-end-line="5" selection-end-column="19" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</component>
|
||||
</project>
|
2
Makefile
Normal file
2
Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
default:
|
||||
ant deploy; cp -r /home/osboxes/Documents/kopano-webapp-3.2.0.285/deploy/plugins/calendarimporter /usr/share/kopano-webapp/plugins/
|
@ -3,7 +3,7 @@
|
||||
* functions.php, zarafa calender to ics im/exporter backend
|
||||
*
|
||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||
* Copyright (C) 2012-2014 Christoph Haas
|
||||
* Copyright (C) 2012-2016 Christoph Haas
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -4,7 +4,7 @@
|
||||
* sync.php, zarafa calender to ics im/exporter backend
|
||||
*
|
||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||
* Copyright (C) 2012-2014 Christoph Haas
|
||||
* Copyright (C) 2012-2016 Christoph Haas
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -129,7 +129,7 @@ foreach($userList as $userName => $userData) {
|
||||
if($icsData != NULL) {
|
||||
file_put_contents($tmpFilename, $icsData);
|
||||
echo "Got valid data for " . $syncItem["icsurl"] . " stored in " . $tmpFilename . "\n";
|
||||
$result = upload_ics_to_caldav($tmpFilename, $CALDAVURL, $userName, $syncItem["calendar"], $ADMINUSERNAME, $ADMINPASSWORD);
|
||||
$result = upload_ics_to_caldav($tmpFilename, $CALDAVURL, $userName, $syncItem["calendarname"], $ADMINUSERNAME, $ADMINPASSWORD);
|
||||
if(intval($result) == 200) {
|
||||
echo "Import completed: $result\n";
|
||||
$result = update_last_sync_date($userStore, $syncItemName);
|
||||
|
156
build.xml
156
build.xml
@ -1,18 +1,15 @@
|
||||
<project default="all">
|
||||
<!--############# CONFIGURE ALL PROPERTIES FOR THE REPLACER HERE ################-->
|
||||
<property name="plugin_version" value="2.1.0"/>
|
||||
<!-- EOC -->
|
||||
|
||||
<property name="root-folder" value="${basedir}/../"/>
|
||||
<property name="tools-folder" value="${root-folder}/TOOLS/"/>
|
||||
<property name="target-folder" value="${root-folder}/DEPLOY/plugins"/>
|
||||
<property environment="env"/>
|
||||
<property name="root-folder" value="${basedir}/../../"/>
|
||||
<property name="tools-folder" value="${root-folder}/tools/"/>
|
||||
<property name="target-folder" value="${root-folder}/deploy/plugins"/>
|
||||
<property name="server-folder" value="${root-folder}/server"/>
|
||||
|
||||
<import file="${tools-folder}/antutil.xml"/>
|
||||
|
||||
<typedef file="${tools-folder}/antlib.xml">
|
||||
<classpath>
|
||||
<pathelement location="${tools-folder}/tools.jar"/>
|
||||
<pathelement location="${tools-folder}/lib/compiler.jar"/>
|
||||
</classpath>
|
||||
</typedef>
|
||||
|
||||
@ -22,29 +19,7 @@
|
||||
</classpath>
|
||||
</taskdef>
|
||||
|
||||
<!-- os checks for xmllint... -->
|
||||
<condition property="isWindows" value="true">
|
||||
<os family="windows" />
|
||||
</condition>
|
||||
|
||||
<!-- define nicknames for libraries -->
|
||||
<property name="yui-compressor" location="${tools-folder}/lib/yuicompressor-2.4.2.jar" />
|
||||
<property name="yui-compressor-ant-task" location="${tools-folder}/lib/yui-compressor-ant-task-0.5.jar" />
|
||||
|
||||
<!-- adds libraries to the classpath -->
|
||||
<path id="yui.classpath">
|
||||
<pathelement location="${yui-compressor}" />
|
||||
<pathelement location="${yui-compressor-ant-task}" />
|
||||
</path>
|
||||
|
||||
<!-- define tasks -->
|
||||
<taskdef name="yui-compressor" classname="net.noha.tools.ant.yuicompressor.tasks.YuiCompressorTask">
|
||||
<classpath refid="yui.classpath" />
|
||||
</taskdef>
|
||||
|
||||
|
||||
<!-- Determine plugin name -->
|
||||
<var name="plugin" unset="true"/>
|
||||
<basename file="${basedir}" property="plugin"/>
|
||||
|
||||
<!-- The Plugin distribution files -->
|
||||
@ -54,8 +29,7 @@
|
||||
|
||||
<!-- The Plugin CSS files -->
|
||||
<property name="plugin-css-folder" value="resources/css"/>
|
||||
<property name="plugin-css-file" value="${plugin}-min.css"/>
|
||||
<property name="plugin-css-debug-file" value="${plugin}.css"/>
|
||||
<property name="plugin-css-file" value="${plugin}.css"/>
|
||||
|
||||
<!-- Meta target -->
|
||||
<target name="all" depends="concat, compress"/>
|
||||
@ -68,16 +42,6 @@
|
||||
<include name="${plugin-file}"/>
|
||||
<include name="${plugin-debugfile}"/>
|
||||
</fileset>
|
||||
<fileset dir="${target-folder}/${plugin-folder}/php">
|
||||
<include name="**/*.php"/>
|
||||
</fileset>
|
||||
<fileset dir="${target-folder}/${plugin-folder}/resources">
|
||||
<include name="**/*"/>
|
||||
</fileset>
|
||||
<fileset dir="${target-folder}/${plugin-folder}/${plugin-css-folder}">
|
||||
<include name="${plugin-css-debug-file}"/>
|
||||
<include name="${plugin-css-file}"/>
|
||||
</fileset>
|
||||
</delete>
|
||||
</target>
|
||||
|
||||
@ -89,27 +53,11 @@
|
||||
<then>
|
||||
<mkdir dir="${target-folder}/${plugin-folder}/js"/>
|
||||
<echo message="Concatenating: ${plugin-debugfile}"/>
|
||||
<!-- TODO: fix JS files for zConcat -->
|
||||
<!--zConcat outputFolder="${target-folder}/${plugin-folder}/js" outputFile="${plugin-debugfile}" prioritize="\w+">
|
||||
<zConcat outputFolder="${target-folder}/${plugin-folder}/js" outputFile="${plugin-debugfile}" prioritize="\w+">
|
||||
<concatfiles>
|
||||
<fileset dir="js" includes="**/*.js" />
|
||||
</concatfiles>
|
||||
</zConcat-->
|
||||
<concat destfile="${target-folder}/${plugin-folder}/js/${plugin-debugfile}">
|
||||
<fileset file="js/ABOUT.js" />
|
||||
<fileset file="js/external/Ext.util.base64.js" />
|
||||
<fileset file="js/data/timezones.js" />
|
||||
<fileset file="js/plugin.calendarimporter.js" />
|
||||
<fileset file="js/data/ResponseHandler.js" />
|
||||
<fileset file="js/dialogs/ImportContentPanel.js" />
|
||||
<fileset file="js/dialogs/ImportPanel.js" />
|
||||
<fileset file="js/settings/SettingsWidget.js" />
|
||||
<fileset file="js/settings/SettingsCalSyncWidget.js" />
|
||||
<fileset file="js/settings/ui/CalSyncPanel.js" />
|
||||
<fileset file="js/settings/ui/CalSyncGrid.js" />
|
||||
<fileset file="js/settings/dialogs/CalSyncEditContentPanel.js" />
|
||||
<fileset file="js/settings/dialogs/CalSyncEditPanel.js" />
|
||||
</concat>
|
||||
</zConcat>
|
||||
</then>
|
||||
</if>
|
||||
|
||||
@ -118,8 +66,8 @@
|
||||
<available file="${plugin-css-folder}" type="dir" />
|
||||
<then>
|
||||
<mkdir dir="${target-folder}/${plugin-folder}/${plugin-css-folder}"/>
|
||||
<echo message="Concatenating: ${plugin-css-debug-file}"/>
|
||||
<zConcat outputFolder="${target-folder}/${plugin-folder}/${plugin-css-folder}" outputFile="${plugin-css-debug-file}">
|
||||
<echo message="Concatenating: ${plugin-css-file}"/>
|
||||
<zConcat outputFolder="${target-folder}/${plugin-folder}/${plugin-css-folder}" outputFile="${plugin-css-file}">
|
||||
<concatfiles>
|
||||
<fileset dir="${plugin-css-folder}" includes="**/*.css" />
|
||||
</concatfiles>
|
||||
@ -164,21 +112,15 @@
|
||||
var pgettext = function(msgctxt, msgid) {};
|
||||
</externs>
|
||||
</zCompile>
|
||||
<!--yui-compressor
|
||||
warn="false"
|
||||
munge="true"
|
||||
preserveallsemicolons="false"
|
||||
fromdir="${target-folder}/${plugin-folder}/js"
|
||||
todir="${target-folder}/${plugin-folder}/js">
|
||||
|
||||
<include name="${plugin-debugfile}" />
|
||||
</yui-compressor-->
|
||||
</then>
|
||||
</if>
|
||||
</target>
|
||||
|
||||
<!-- syntax check all PHP files -->
|
||||
<target name="validate">
|
||||
<if>
|
||||
<available file="php" filepath="${env.PATH}" />
|
||||
<then>
|
||||
<if>
|
||||
<available file="config.php" type="file" />
|
||||
<then>
|
||||
@ -193,92 +135,66 @@
|
||||
<foreach target="syntax-check" param="file">
|
||||
<path>
|
||||
<fileset dir=".">
|
||||
<exclude name="php/vendor/**" />
|
||||
<include name="**/*.php"/>
|
||||
</fileset>
|
||||
</path>
|
||||
</foreach>
|
||||
</then>
|
||||
</if>
|
||||
</then>
|
||||
<else>
|
||||
<echo message="WARNING: PHP not available, not performing syntax-check on php files"/>
|
||||
</else>
|
||||
</if>
|
||||
</target>
|
||||
|
||||
<target name="syntax-check">
|
||||
<echo message="validating ${file}"/>
|
||||
<exec executable="php" failonerror="true" failifexecutionfails="false">
|
||||
<exec executable="php" failonerror="true">
|
||||
<arg value="-l"/>
|
||||
<arg value="${file}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- on windows we do not check the xml file -->
|
||||
<target name="xml-os-sel" depends="xml-check,xml-copy">
|
||||
<echo>Processing manifest.xml</echo>
|
||||
</target>
|
||||
<!-- Install all files into the target folder -->
|
||||
<target name="deploy" depends="compress, validate">
|
||||
<mkdir dir="${target-folder}/${plugin-folder}"/>
|
||||
|
||||
<!-- check manifest.xml if we are on windows... -->
|
||||
<target name="xml-check" unless="isWindows">
|
||||
<echo message="Checking xml: manifest.xml" />
|
||||
<!-- Copy (and validate) manifest.xml -->
|
||||
<exec executable="xmllint" output="${target-folder}/${plugin-folder}/manifest.xml" failonerror="true" error="/dev/stdout" failifexecutionfails="false">
|
||||
<if>
|
||||
<available file="xmllint" filepath="${env.PATH}" />
|
||||
<then>
|
||||
<exec executable="xmllint" output="${target-folder}/${plugin-folder}/manifest.xml" failonerror="true">
|
||||
<arg value="--valid"/>
|
||||
<arg value="--path"/>
|
||||
<arg value="${root-folder}/server"/>
|
||||
<arg value="${server-folder}"/>
|
||||
<arg value="manifest.xml"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- check manifest.xml if we are on windows... -->
|
||||
<target name="xml-copy" if="isWindows">
|
||||
<echo message="Copying xml: manifest.xml" />
|
||||
<!-- Copy manifest.xml -->
|
||||
</then>
|
||||
<else>
|
||||
<echo message="WARNING: xmllint not available, not performing syntax-check on manifest.xml"/>
|
||||
<!-- xmllint is not available, so we must copy the file manually -->
|
||||
<copy todir="${target-folder}/${plugin-folder}">
|
||||
<fileset dir=".">
|
||||
<include name="manifest.xml"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<!-- Install all files into the target folder -->
|
||||
<target name="deploy" depends="clean, compress, compresscss, validate, xml-os-sel">
|
||||
<mkdir dir="${target-folder}/${plugin-folder}"/>
|
||||
</else>
|
||||
</if>
|
||||
|
||||
<!-- copy files -->
|
||||
<copy todir="${target-folder}/${plugin-folder}">
|
||||
<fileset dir=".">
|
||||
<include name="resources/**/*"/>
|
||||
<include name="resources/**/*.*"/>
|
||||
<include name="external/**/*.*"/>
|
||||
<include name="php/**/*.php"/>
|
||||
<include name="config.php"/>
|
||||
<include name="changelog.txt"/>
|
||||
<!-- exclude the ant script -->
|
||||
<exclude name="build.xml"/>
|
||||
<!-- CSS is generated during build -->
|
||||
<exclude name="resources/css/*.*"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
|
||||
<!-- replace all variables... -->
|
||||
<replace file="${target-folder}/${plugin-folder}/manifest.xml" token="@_@PLUGIN_VERSION@_@" value="${plugin_version}" />
|
||||
</target>
|
||||
|
||||
<!-- compresses each CSS file -->
|
||||
<target name="compresscss" depends="concat">
|
||||
|
||||
<available file="${tools-folder}/lib/yui-compressor-ant-task-0.5.jar" property="YUIANT_AVAILABLE" />
|
||||
<fail unless="YUIANT_AVAILABLE" message="yui-compressor-ant-task-0.5.jar not found" />
|
||||
|
||||
<if>
|
||||
<available file="${target-folder}/${plugin-folder}/${plugin-css-folder}/${plugin-css-debug-file}" type="file" />
|
||||
<then>
|
||||
<yui-compressor
|
||||
warn="false"
|
||||
munge="true"
|
||||
preserveallsemicolons="false"
|
||||
fromdir="${target-folder}/${plugin-folder}/${plugin-css-folder}"
|
||||
todir="${target-folder}/${plugin-folder}/${plugin-css-folder}">
|
||||
|
||||
<include name="${plugin-css-debug-file}" />
|
||||
</yui-compressor>
|
||||
</then>
|
||||
</if>
|
||||
</target>
|
||||
|
||||
</project>
|
@ -1,3 +1,10 @@
|
||||
calendarimporter 2.2.0:
|
||||
- support for Kopano Webapp 3.1.1
|
||||
- Code rework
|
||||
- Calendar export improved
|
||||
- Calendar import improved
|
||||
- GUI improvements
|
||||
|
||||
calendarimporter 2.1.0:
|
||||
- ics sync is now implemented
|
||||
|
||||
|
@ -1,15 +1,13 @@
|
||||
<?php
|
||||
/** Disable the import plugin for all clients */
|
||||
define('PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE', false);
|
||||
/** Disable the export feature for all clients */
|
||||
define('PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE_EXPORT', false);
|
||||
define('PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE', true);
|
||||
/** Disable the sync feature for all clients */
|
||||
define('PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE_SYNC', true); // not yet implemented
|
||||
|
||||
/** The default calendar to import to*/
|
||||
define('PLUGIN_CALENDARIMPORTER_DEFAULT', "calendar");
|
||||
define('PLUGIN_CALENDARIMPORTER_DEFAULT', "Kalender");
|
||||
define('PLUGIN_CALENDARIMPORTER_DEFAULT_TIMEZONE', "Europe/Vienna");
|
||||
|
||||
/** Tempory path for uploaded files... */
|
||||
define('PLUGIN_CALENDARIMPORTER_TMP_UPLOAD', "/var/lib/zarafa-webapp/tmp/");
|
||||
define('PLUGIN_CALENDARIMPORTER_TMP_UPLOAD', "/var/lib/kopano-webapp/tmp/");
|
||||
?>
|
||||
|
@ -1,87 +0,0 @@
|
||||
/**
|
||||
* A small tool to create our timezone mappings list =)
|
||||
*/
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class Main {
|
||||
static String map[] = new String[51]; // one field = 30 minutes step
|
||||
|
||||
private static void initMap() {
|
||||
map[0] = "Pacific/Midway";
|
||||
map[1] = "";
|
||||
map[2] = "Pacific/Fakaofo";
|
||||
map[3] = "Pacific/Marquesas";
|
||||
map[4] = "America/Anchorage";
|
||||
map[5] = "";
|
||||
map[6] = "America/Dawson";
|
||||
map[7] = "";
|
||||
map[8] = "America/Dawson_Creek";
|
||||
map[9] = "";
|
||||
map[10] = "America/Chicago";
|
||||
map[11] = "America/Caracas";
|
||||
map[12] = "America/Detroit";
|
||||
map[13] = "America/Caracas";
|
||||
map[14] = "America/Santiago";
|
||||
map[15] = "America/St_Johns";
|
||||
map[16] = "America/Sao_Paulo";
|
||||
map[17] = "";
|
||||
map[18] = "America/Noronha";
|
||||
map[19] = "";
|
||||
map[20] = "Atlantic/Cape_Verde";
|
||||
map[21] = "";
|
||||
map[22] = "Africa/Abidjan";
|
||||
map[23] = "";
|
||||
map[24] = "Europe/Vienna";
|
||||
map[25] = "";
|
||||
map[26] = "Asia/Jerusalem";
|
||||
map[27] = "";
|
||||
map[28] = "Africa/Addis_Ababa";
|
||||
map[29] = "Asia/Tehran";
|
||||
map[30] = "Asia/Dubai";
|
||||
map[31] = "Asia/Kabul";
|
||||
map[32] = "Antarctica/Mawson";
|
||||
map[33] = "Asia/Colombo";
|
||||
map[34] = "Antarctica/Vostok";
|
||||
map[35] = "Asia/Rangoon";
|
||||
map[36] = "Antarctica/Davis";
|
||||
map[37] = "";
|
||||
map[38] = "Antarctica/Casey";
|
||||
map[39] = "";
|
||||
map[40] = "Asia/Dili";
|
||||
map[41] = "Australia/Darwin";
|
||||
map[42] = "Australia/Currie";
|
||||
map[43] = "Australia/Lord_Howe";
|
||||
map[44] = "Antarctica/Macquarie";
|
||||
map[45] = "Pacific/Norfolk";
|
||||
map[46] = "Antarctica/McMurdo";
|
||||
map[47] = "";
|
||||
map[48] = "Pacific/Enderbury";
|
||||
map[49] = "";
|
||||
map[50] = "Pacific/Kiritimati";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
initMap();
|
||||
|
||||
int i = 0;
|
||||
for(int time = -660; time < 900; time += 30) {
|
||||
|
||||
int hours = time / 60;
|
||||
int minutes = Math.abs(time) % 60;
|
||||
|
||||
String[] avaiId = TimeZone.getAvailableIDs(time*60*1000);
|
||||
|
||||
if(avaiId.length > 0) {
|
||||
System.out.printf("\t\t/*%+d:%02d*/\n", hours, minutes);
|
||||
for (String string : avaiId) {
|
||||
System.out.println("\t\t'" + string + "' : '" + map[i] + "',");
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
* ABOUT.js zarafa calender to ics im/exporter
|
||||
*
|
||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||
* Copyright (C) 2012-2013 Christoph Haas
|
||||
* Copyright (C) 2012-2016 Christoph Haas
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -29,7 +29,7 @@ Ext.namespace('Zarafa.plugins.calendarimporter');
|
||||
* The copyright string holding the copyright notice for the Zarafa calendarimporter Plugin.
|
||||
*/
|
||||
Zarafa.plugins.calendarimporter.ABOUT = ""
|
||||
+ "<p>Copyright (C) 2012-2013 Christoph Haas <christoph.h@sprinternet.at></p>"
|
||||
+ "<p>Copyright (C) 2012-2016 Christoph Haas <christoph.h@sprinternet.at></p>"
|
||||
|
||||
+ "<p>This program is free software; you can redistribute it and/or "
|
||||
+ "modify it under the terms of the GNU Lesser General Public "
|
||||
|
178
js/data/Actions.js
Normal file
178
js/data/Actions.js
Normal file
@ -0,0 +1,178 @@
|
||||
/**
|
||||
* Actions.js zarafa calender to ics im/exporter
|
||||
*
|
||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||
* Copyright (C) 2012-2016 Christoph Haas
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* ResponseHandler
|
||||
*
|
||||
* This class handles all responses from the php backend
|
||||
*/
|
||||
Ext.namespace('Zarafa.plugins.calendarimporter.data');
|
||||
|
||||
/**
|
||||
* @class Zarafa.plugins.calendarimporter.data.Actions
|
||||
* Common actions which can be used within {@link Ext.Button buttons}
|
||||
* or other {@link Ext.Component components} with action handlers.
|
||||
* @singleton
|
||||
*/
|
||||
Zarafa.plugins.calendarimporter.data.Actions = {
|
||||
/**
|
||||
* Callback for the export request.
|
||||
* @param {Object} response
|
||||
*/
|
||||
downloadICS: function (response) {
|
||||
if (response.status == false) {
|
||||
Zarafa.common.dialogs.MessageBox.show({
|
||||
title : dgettext('plugin_files', 'Warning'),
|
||||
msg : dgettext('plugin_files', response.message),
|
||||
icon : Zarafa.common.dialogs.MessageBox.WARNING,
|
||||
buttons: Zarafa.common.dialogs.MessageBox.OK
|
||||
});
|
||||
} else {
|
||||
var downloadFrame = Ext.getBody().createChild({
|
||||
tag: 'iframe',
|
||||
cls: 'x-hidden'
|
||||
});
|
||||
|
||||
var url = document.URL;
|
||||
var link = url.substring(0, url.lastIndexOf('/') + 1);
|
||||
|
||||
link += "index.php?sessionid=" + container.getUser().getSessionId() + "&load=custom&name=download_ics";
|
||||
link = Ext.urlAppend(link, "token=" + encodeURIComponent(response.download_token));
|
||||
link = Ext.urlAppend(link, "filename=" + encodeURIComponent(response.filename));
|
||||
|
||||
downloadFrame.dom.contentWindow.location = link;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get all calendar folders.
|
||||
* @param {boolean} asDropdownStore If true, a simple array store will be returned.
|
||||
* @returns {*}
|
||||
*/
|
||||
getAllCalendarFolders: function (asDropdownStore) {
|
||||
asDropdownStore = Ext.isEmpty(asDropdownStore) ? false : asDropdownStore;
|
||||
|
||||
var allFolders = [];
|
||||
|
||||
var inbox = container.getHierarchyStore().getDefaultStore();
|
||||
var pub = container.getHierarchyStore().getPublicStore();
|
||||
|
||||
if (!Ext.isEmpty(inbox.subStores) && inbox.subStores.folders.totalLength > 0) {
|
||||
for (var i = 0; i < inbox.subStores.folders.totalLength; i++) {
|
||||
var folder = inbox.subStores.folders.getAt(i);
|
||||
if (folder.get("container_class") == "IPF.Appointment") {
|
||||
if (asDropdownStore) {
|
||||
allFolders.push([
|
||||
folder.get("entryid"),
|
||||
folder.get("display_name")
|
||||
]);
|
||||
} else {
|
||||
allFolders.push({
|
||||
display_name : folder.get("display_name"),
|
||||
entryid : folder.get("entryid"),
|
||||
store_entryid: folder.get("store_entryid"),
|
||||
is_public : false
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Ext.isEmpty(pub.subStores) && pub.subStores.folders.totalLength > 0) {
|
||||
for (var j = 0; j < pub.subStores.folders.totalLength; j++) {
|
||||
var folder = pub.subStores.folders.getAt(j);
|
||||
if (folder.get("container_class") == "IPF.Appointment") {
|
||||
if (asDropdownStore) {
|
||||
allFolders.push([
|
||||
folder.get("entryid"),
|
||||
folder.get("display_name") + " (Public)"
|
||||
]);
|
||||
} else {
|
||||
allFolders.push({
|
||||
display_name : folder.get("display_name"),
|
||||
entryid : folder.get("entryid"),
|
||||
store_entryid: folder.get("store_entryid"),
|
||||
is_public : true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (asDropdownStore) {
|
||||
return allFolders.sort(Zarafa.plugins.calendarimporter.data.Actions.dynamicSort(1));
|
||||
} else {
|
||||
return allFolders;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a calendar folder element by name.
|
||||
* @param {string} name
|
||||
* @returns {*}
|
||||
*/
|
||||
getCalendarFolderByName: function (name) {
|
||||
var folders = Zarafa.plugins.calendarimporter.data.Actions.getAllCalendarFolders(false);
|
||||
|
||||
for (var i = 0; i < folders.length; i++) {
|
||||
if (folders[i].display_name == name) {
|
||||
return folders[i];
|
||||
}
|
||||
}
|
||||
|
||||
return container.getHierarchyStore().getDefaultFolder('calendar');
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a calendar folder element by entryid.
|
||||
* @param {string} entryid
|
||||
* @returns {*}
|
||||
*/
|
||||
getCalendarFolderByEntryid: function (entryid) {
|
||||
var folders = Zarafa.plugins.calendarimporter.data.Actions.getAllCalendarFolders(false);
|
||||
|
||||
for (var i = 0; i < folders.length; i++) {
|
||||
if (folders[i].entryid == entryid) {
|
||||
return folders[i];
|
||||
}
|
||||
}
|
||||
|
||||
return container.getHierarchyStore().getDefaultFolder('calendar');
|
||||
},
|
||||
|
||||
/**
|
||||
* Dynamic sort function, sorts by property name.
|
||||
* @param {string|int} property
|
||||
* @returns {Function}
|
||||
*/
|
||||
dynamicSort: function (property) {
|
||||
var sortOrder = 1;
|
||||
if (property[0] === "-") {
|
||||
sortOrder = -1;
|
||||
property = property.substr(1);
|
||||
}
|
||||
return function (a, b) {
|
||||
var result = (a[property].toLowerCase() < b[property].toLowerCase()) ? -1 : (a[property].toLowerCase() > b[property].toLowerCase()) ? 1 : 0;
|
||||
return result * sortOrder;
|
||||
}
|
||||
}
|
||||
};
|
@ -2,7 +2,7 @@
|
||||
* ResponseHandler.js zarafa calender to ics im/exporter
|
||||
*
|
||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||
* Copyright (C) 2012-2013 Christoph Haas
|
||||
* Copyright (C) 2012-2016 Christoph Haas
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -52,7 +52,7 @@ Zarafa.plugins.calendarimporter.data.ResponseHandler = Ext.extend(Zarafa.core.da
|
||||
* Call the successCallback callback function.
|
||||
* @param {Object} response Object contained the response data.
|
||||
*/
|
||||
doList : function(response) {
|
||||
doLoad: function (response) {
|
||||
this.successCallback(response);
|
||||
},
|
||||
|
||||
@ -68,7 +68,7 @@ Zarafa.plugins.calendarimporter.data.ResponseHandler = Ext.extend(Zarafa.core.da
|
||||
* Call the successCallback callback function.
|
||||
* @param {Object} response Object contained the response data.
|
||||
*/
|
||||
doAttachmentpath : function(response) {
|
||||
doImportattachment: function (response) {
|
||||
this.successCallback(response);
|
||||
},
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
* timezones.js zarafa calender to ics im/exporter
|
||||
*
|
||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||
* Copyright (C) 2012-2013 Christoph Haas
|
||||
* Copyright (C) 2012-2016 Christoph Haas
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -2,7 +2,7 @@
|
||||
* ImportContentPanel.js zarafa calender to ics im/exporter
|
||||
*
|
||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||
* Copyright (C) 2012-2013 Christoph Haas
|
||||
* Copyright (C) 2012-2016 Christoph Haas
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -42,13 +42,9 @@ Zarafa.plugins.calendarimporter.dialogs.ImportContentPanel = Ext.extend(Zarafa.c
|
||||
*/
|
||||
constructor : function(config) {
|
||||
config = config || {};
|
||||
var title = _('Import Calendar File');
|
||||
if(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/enable_export")){
|
||||
title = _('Import/Export Calendar File');
|
||||
}
|
||||
Ext.applyIf(config, {
|
||||
layout : 'fit',
|
||||
title : title,
|
||||
title : _('Import Calendar File'),
|
||||
closeOnSave : true,
|
||||
width : 800,
|
||||
height : 700,
|
||||
@ -56,7 +52,8 @@ Zarafa.plugins.calendarimporter.dialogs.ImportContentPanel = Ext.extend(Zarafa.c
|
||||
items : [
|
||||
{
|
||||
xtype : 'calendarimporter.importpanel',
|
||||
filename : config.filename
|
||||
filename : config.filename,
|
||||
folder : config.folder
|
||||
}
|
||||
]
|
||||
});
|
||||
|
@ -2,7 +2,7 @@
|
||||
* ImportPanel.js zarafa calender to ics im/exporter
|
||||
*
|
||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||
* Copyright (C) 2012-2013 Christoph Haas
|
||||
* Copyright (C) 2012-2016 Christoph Haas
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -29,7 +29,7 @@ Ext.namespace("Zarafa.plugins.calendarimporter.dialogs");
|
||||
|
||||
/**
|
||||
* @class Zarafa.plugins.calendarimporter.dialogs.ImportPanel
|
||||
* @extends Ext.form.FormPanel
|
||||
* @extends Ext.Panel
|
||||
*/
|
||||
Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
|
||||
@ -46,7 +46,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
loadMask: null,
|
||||
|
||||
/* export event buffer */
|
||||
exportResponse: new Array(),
|
||||
exportResponse: [],
|
||||
|
||||
/* how many requests are still running? */
|
||||
runningRequests: null,
|
||||
@ -54,13 +54,8 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
/* The store for the selection grid */
|
||||
store: null,
|
||||
|
||||
/**
|
||||
* The internal 'iframe' which is hidden from the user, which is used for downloading
|
||||
* attachments. See {@link #doOpen}.
|
||||
* @property
|
||||
* @type Ext.Element
|
||||
*/
|
||||
downloadFrame : undefined,
|
||||
/* selected folder */
|
||||
folder : null,
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
@ -71,24 +66,30 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
var self = this;
|
||||
this.timezone = container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_timezone");
|
||||
|
||||
if(typeof config.filename !== "undefined") {
|
||||
if (!Ext.isEmpty(config.filename)) {
|
||||
this.icsfile = config.filename;
|
||||
}
|
||||
|
||||
if (!Ext.isEmpty(config.folder)) {
|
||||
this.folder = config.folder;
|
||||
}
|
||||
|
||||
// create the data store
|
||||
this.store = new Ext.data.ArrayStore({
|
||||
fields: [
|
||||
{name: 'title'},
|
||||
{name: 'start'},
|
||||
{name: 'end'},
|
||||
{name: 'subject'},
|
||||
{name: 'startdate'},
|
||||
{name: 'enddate'},
|
||||
{name: 'location'},
|
||||
{name: 'description'},
|
||||
{name: 'body'},
|
||||
{name: 'priority'},
|
||||
{name: 'label'},
|
||||
{name: 'busy'},
|
||||
{name: 'privatestate'},
|
||||
{name: 'class'},
|
||||
{name: 'organizer'},
|
||||
{name: 'trigger'}
|
||||
{name: 'alarms'},
|
||||
{name: 'timezone'},
|
||||
{name: 'record'}
|
||||
]
|
||||
});
|
||||
|
||||
@ -114,29 +115,19 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
this.createGrid()
|
||||
],
|
||||
buttons: [
|
||||
this.createExportAllButton(),
|
||||
this.createSubmitAllButton(),
|
||||
this.createSubmitButton(),
|
||||
this.createCancelButton()
|
||||
],
|
||||
listeners: {
|
||||
afterrender: function (cmp) {
|
||||
Ext.getCmp('importbutton').disable();
|
||||
this.loadMask = new Ext.LoadMask(Ext.getCmp("importpanel").getEl(), {msg:'Loading...'});
|
||||
this.loadMask = new Ext.LoadMask(this.getEl(), {msg:'Loading...'});
|
||||
|
||||
if(this.icsfile != null) { // if we have got the filename from an attachment
|
||||
this.parseCalendar(this.icsfile, this.timezone, this.ignoredst);
|
||||
}
|
||||
},
|
||||
close: function (cmp) {
|
||||
Ext.getCmp('importbutton').enable();
|
||||
},
|
||||
hide: function (cmp) {
|
||||
Ext.getCmp('importbutton').enable();
|
||||
},
|
||||
destroy: function (cmp) {
|
||||
Ext.getCmp('importbutton').enable();
|
||||
}
|
||||
scope: this
|
||||
}
|
||||
});
|
||||
|
||||
@ -174,22 +165,25 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
reloadGridStore: function(eventdata) {
|
||||
var parsedData = [];
|
||||
|
||||
// this is done to get rid of the local browser timezone....
|
||||
// because all timezone specific stuff is done via php
|
||||
var local_tz_offset = new Date().getTimezoneOffset() * 60000; // getTimezoneOffset returns minutes... we need milliseconds
|
||||
|
||||
|
||||
if(eventdata !== null) {
|
||||
parsedData = new Array(eventdata.events.length);
|
||||
var i = 0;
|
||||
for(i = 0; i < eventdata.events.length; i++) {
|
||||
var trigger = null;
|
||||
|
||||
if(eventdata.events[i]["VALARM"]) {
|
||||
trigger = eventdata.events[i]["VALARM"]["TRIGGER"];
|
||||
trigger = new Date(parseInt(trigger) + local_tz_offset);
|
||||
}
|
||||
parsedData[i] = new Array(eventdata.events[i]["SUMMARY"], new Date(parseInt(eventdata.events[i]["DTSTART"]) + local_tz_offset), new Date(parseInt(eventdata.events[i]["DTEND"]) + local_tz_offset), eventdata.events[i]["LOCATION"], eventdata.events[i]["DESCRIPTION"],eventdata.events[i]["PRIORITY"],eventdata.events[i]["X-ZARAFA-LABEL"],eventdata.events[i]["X-MICROSOFT-CDO-BUSYSTATUS"],eventdata.events[i]["CLASS"],eventdata.events[i]["ORGANIZER"],trigger);
|
||||
parsedData[i] = [
|
||||
eventdata.events[i]["subject"],
|
||||
new Date(parseInt(eventdata.events[i]["startdate"]) * 1000),
|
||||
new Date(parseInt(eventdata.events[i]["duedate"]) * 1000),
|
||||
eventdata.events[i]["location"],
|
||||
eventdata.events[i]["body"],
|
||||
eventdata.events[i]["priority"],
|
||||
eventdata.events[i]["label"],
|
||||
eventdata.events[i]["busystatus"],
|
||||
eventdata.events[i]["private"],
|
||||
eventdata.events[i]["organizer"],
|
||||
eventdata.events[i]["alarms"],
|
||||
eventdata.events[i]["timezone"],
|
||||
eventdata.events[i]
|
||||
];
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
@ -223,17 +217,18 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
sortable: true
|
||||
},
|
||||
columns: [
|
||||
{id: 'Summary', header: 'Title', width: 200, sortable: true, dataIndex: 'title'},
|
||||
{header: 'Start', width: 200, sortable: true, dataIndex: 'start', renderer : Zarafa.common.ui.grid.Renderers.datetime},
|
||||
{header: 'End', width: 200, sortable: true, dataIndex: 'end', renderer : Zarafa.common.ui.grid.Renderers.datetime},
|
||||
{id: 'Summary', header: 'Title', width: 200, sortable: true, dataIndex: 'subject'},
|
||||
{header: 'Start', width: 200, sortable: true, dataIndex: 'startdate', renderer : Zarafa.common.ui.grid.Renderers.datetime},
|
||||
{header: 'End', width: 200, sortable: true, dataIndex: 'enddate', renderer : Zarafa.common.ui.grid.Renderers.datetime},
|
||||
{header: 'Location', width: 150, sortable: true, dataIndex: 'location'},
|
||||
{header: 'Description', sortable: true, dataIndex: 'description'},
|
||||
{header: 'Description', sortable: true, dataIndex: 'body'},
|
||||
{header: "Priority", dataIndex: 'priority', hidden: true},
|
||||
{header: "Label", dataIndex: 'label', hidden: true},
|
||||
{header: "Busystatus", dataIndex: 'busy', hidden: true},
|
||||
{header: "Privacystatus", dataIndex: 'privatestate', hidden: true},
|
||||
{header: "Privacystatus", dataIndex: 'class', hidden: true},
|
||||
{header: "Organizer", dataIndex: 'organizer', hidden: true},
|
||||
{header: "Alarm", dataIndex: 'trigger', hidden: true, renderer : Zarafa.common.ui.grid.Renderers.datetime}
|
||||
{header: "Alarm", dataIndex: 'alarms', hidden: true, renderer : Zarafa.common.ui.grid.Renderers.datetime},
|
||||
{header: "Timezone", dataIndex: 'timezone', hidden: true}
|
||||
]
|
||||
}),
|
||||
sm: new Ext.grid.RowSelectionModel({multiSelect:true})
|
||||
@ -241,52 +236,23 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
},
|
||||
|
||||
createSelectBox: function() {
|
||||
var defaultFolder = container.getHierarchyStore().getDefaultFolder('calendar'); // @type: Zarafa.hierarchy.data.MAPIFolderRecord
|
||||
var subFolders = defaultFolder.getChildren();
|
||||
var myStore = [];
|
||||
|
||||
/* add all local calendar folders */
|
||||
var i = 0;
|
||||
myStore.push(new Array(defaultFolder.getDefaultFolderKey(), defaultFolder.getDisplayName()));
|
||||
for(i = 0; i < subFolders.length; i++) {
|
||||
/* Store all subfolders */
|
||||
myStore.push(new Array(subFolders[i].getDisplayName(), subFolders[i].getDisplayName(), false)); // 3rd field = isPublicfolder
|
||||
}
|
||||
|
||||
/* add all shared calendar folders */
|
||||
var pubStore = container.getHierarchyStore().getPublicStore();
|
||||
|
||||
if(typeof pubStore !== "undefined") {
|
||||
try {
|
||||
var pubFolder = pubStore.getDefaultFolder("publicfolders");
|
||||
var pubSubFolders = pubFolder.getChildren();
|
||||
|
||||
for(i = 0; i < pubSubFolders.length; i++) {
|
||||
if(pubSubFolders[i].isContainerClass("IPF.Appointment")){
|
||||
myStore.push(new Array(pubSubFolders[i].getDisplayName(), pubSubFolders[i].getDisplayName() + " [Shared]", true)); // 3rd field = isPublicfolder
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Error opening the shared folder...");
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
var myStore = Zarafa.plugins.calendarimporter.data.Actions.getAllCalendarFolders(true);
|
||||
|
||||
return {
|
||||
xtype: "selectbox",
|
||||
ref: 'calendarselector',
|
||||
id: 'calendarselector',
|
||||
editable: false,
|
||||
name: "choosen_calendar",
|
||||
value: container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_calendar"),
|
||||
value: Ext.isEmpty(this.folder) ? Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByName(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_calendar")).entryid : this.folder,
|
||||
width: 100,
|
||||
fieldLabel: "Select a calender",
|
||||
fieldLabel: "Select folder",
|
||||
store: myStore,
|
||||
mode: 'local',
|
||||
labelSeperator: ":",
|
||||
border: false,
|
||||
anchor: "100%",
|
||||
scope: this,
|
||||
hidden : Ext.isEmpty(this.folder) ? false : true,
|
||||
allowBlank: false
|
||||
}
|
||||
},
|
||||
@ -295,12 +261,11 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
return {
|
||||
xtype: "selectbox",
|
||||
ref: 'timezoneselector',
|
||||
id: 'timezoneselector',
|
||||
editable: false,
|
||||
name: "choosen_timezone",
|
||||
value: Zarafa.plugins.calendarimporter.data.Timezones.unMap(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_timezone")),
|
||||
width: 100,
|
||||
fieldLabel: "Select a timezone (optional)",
|
||||
fieldLabel: "Timezone",
|
||||
store: Zarafa.plugins.calendarimporter.data.Timezones.store,
|
||||
labelSeperator: ":",
|
||||
mode: 'local',
|
||||
@ -309,7 +274,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
scope: this,
|
||||
allowBlank: true,
|
||||
listeners: {
|
||||
'select': this.onTimezoneSelected,
|
||||
select: this.onTimezoneSelected,
|
||||
scope: this
|
||||
}
|
||||
}
|
||||
@ -319,10 +284,9 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
return {
|
||||
xtype: "checkbox",
|
||||
ref: 'dstcheck',
|
||||
id: 'dstcheck',
|
||||
name: "dst_check",
|
||||
width: 100,
|
||||
fieldLabel: "Ignore DST (optional)",
|
||||
fieldLabel: "Ignore DST",
|
||||
boxLabel: 'This will ignore "Daylight saving time" offsets.',
|
||||
labelSeperator: ":",
|
||||
border: false,
|
||||
@ -330,7 +294,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
scope: this,
|
||||
allowBlank: true,
|
||||
listeners: {
|
||||
'check': this.onDstChecked,
|
||||
check: this.onDstChecked,
|
||||
scope: this
|
||||
}
|
||||
}
|
||||
@ -346,10 +310,11 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
emptyText: 'Select an .ics calendar',
|
||||
border: false,
|
||||
anchor: "100%",
|
||||
height : "30",
|
||||
scope: this,
|
||||
allowBlank: false,
|
||||
listeners: {
|
||||
'fileselected': this.onFileSelected,
|
||||
fileselected: this.onFileSelected,
|
||||
scope: this
|
||||
}
|
||||
}
|
||||
@ -358,48 +323,28 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
createSubmitButton: function() {
|
||||
return {
|
||||
xtype: "button",
|
||||
ref: "submitButton",
|
||||
id: "submitButton",
|
||||
ref: "../submitButton",
|
||||
disabled: true,
|
||||
width: 100,
|
||||
border: false,
|
||||
text: _("Import"),
|
||||
anchor: "100%",
|
||||
handler: this.importCheckedEvents,
|
||||
scope: this,
|
||||
allowBlank: false
|
||||
scope: this
|
||||
}
|
||||
},
|
||||
|
||||
createSubmitAllButton: function() {
|
||||
return {
|
||||
xtype: "button",
|
||||
ref: "submitAllButton",
|
||||
id: "submitAllButton",
|
||||
ref: "../submitAllButton",
|
||||
disabled: true,
|
||||
width: 100,
|
||||
border: false,
|
||||
text: _("Import All"),
|
||||
anchor: "100%",
|
||||
handler: this.importAllEvents,
|
||||
scope: this,
|
||||
allowBlank: false
|
||||
}
|
||||
},
|
||||
|
||||
createExportAllButton: function() {
|
||||
return {
|
||||
xtype: "button",
|
||||
ref: "exportAllButton",
|
||||
id: "exportAllButton",
|
||||
hidden: !container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/enable_export"),
|
||||
width: 100,
|
||||
border: false,
|
||||
text: _("Export All"),
|
||||
anchor: "100%",
|
||||
handler: this.exportAllEvents,
|
||||
scope: this,
|
||||
allowBlank: false
|
||||
scope: this
|
||||
}
|
||||
},
|
||||
|
||||
@ -411,8 +356,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
text: _("Cancel"),
|
||||
anchor: "100%",
|
||||
handler: this.close,
|
||||
scope: this,
|
||||
allowBlank: false
|
||||
scope: this
|
||||
}
|
||||
},
|
||||
|
||||
@ -432,7 +376,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
|
||||
/**
|
||||
* This is called when the dst checkbox has been selected
|
||||
* @param {Ext.form.CheckBox} combo
|
||||
* @param {Ext.form.CheckBox} checkbox
|
||||
* @param {boolean} checked
|
||||
*/
|
||||
onDstChecked : function(checkbox, checked) {
|
||||
@ -456,8 +400,8 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
waitMsg: 'Uploading and parsing calendar...',
|
||||
url: 'plugins/calendarimporter/php/upload.php',
|
||||
failure: function(file, action) {
|
||||
Ext.getCmp('submitButton').disable();
|
||||
Ext.getCmp('submitAllButton').disable();
|
||||
this.submitButton.disable();
|
||||
this.submitAllButton.disable();
|
||||
Zarafa.common.dialogs.MessageBox.show({
|
||||
title : _('Error'),
|
||||
msg : _(action.result.error),
|
||||
@ -478,14 +422,15 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
|
||||
parseCalendar: function (icsPath, timezone, ignoredst) {
|
||||
this.loadMask.show();
|
||||
// call export function here!
|
||||
|
||||
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
||||
successCallback: this.handleParsingResult.createDelegate(this)
|
||||
successCallback: this.handleParsingResult,
|
||||
scope: this
|
||||
});
|
||||
|
||||
container.getRequest().singleRequest(
|
||||
'calendarmodule',
|
||||
'import',
|
||||
'load',
|
||||
{
|
||||
ics_filepath: icsPath,
|
||||
timezone: timezone,
|
||||
@ -496,20 +441,22 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
},
|
||||
|
||||
handleParsingResult: function(response) {
|
||||
this.loadMask.hide();
|
||||
var self = this.scope;
|
||||
|
||||
self.loadMask.hide();
|
||||
|
||||
if(response["status"] == true) {
|
||||
Ext.getCmp('submitButton').enable();
|
||||
Ext.getCmp('submitAllButton').enable();
|
||||
self.submitButton.enable();
|
||||
self.submitAllButton.enable();
|
||||
|
||||
if(typeof response.parsed.calendar["X-WR-TIMEZONE"] !== "undefined") {;
|
||||
this.timezone = response.parsed.calendar["X-WR-TIMEZONE"];
|
||||
this.timezoneselector.setValue(Zarafa.plugins.calendarimporter.data.Timezones.unMap(this.timezone));
|
||||
if(typeof response.parsed.calendar["X-WR-TIMEZONE"] !== "undefined") {
|
||||
self.timezone = response.parsed.calendar["X-WR-TIMEZONE"];
|
||||
self.timezoneselector.setValue(Zarafa.plugins.calendarimporter.data.Timezones.unMap(this.timezone));
|
||||
}
|
||||
this.reloadGridStore(response.parsed);
|
||||
self.reloadGridStore(response.parsed);
|
||||
} else {
|
||||
Ext.getCmp('submitButton').disable();
|
||||
Ext.getCmp('submitAllButton').disable();
|
||||
self.submitButton.disable();
|
||||
self.submitAllButton.disable();
|
||||
Zarafa.common.dialogs.MessageBox.show({
|
||||
title : _('Parser Error'),
|
||||
msg : _(response["message"]),
|
||||
@ -524,54 +471,6 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
this.dialog.close()
|
||||
},
|
||||
|
||||
convertToAppointmentRecord: function (calendarFolder,entry) {
|
||||
var newRecord = Zarafa.core.data.RecordFactory.createRecordObjectByMessageClass('IPM.Appointment', {
|
||||
startdate: new Date(entry.start),
|
||||
duedate: (entry.end != null) ?
|
||||
new Date(entry.end) :
|
||||
new Date(entry.start).add(Date.HOUR, 1),
|
||||
location: entry.location,
|
||||
subject: entry.title,
|
||||
body: entry.description,
|
||||
commonstart: new Date(entry.start),
|
||||
commonend: (entry.end != null) ?
|
||||
new Date(entry.end) :
|
||||
new Date(entry.start).add(Date.HOUR, 1),
|
||||
timezone: this.timezone,
|
||||
parent_entryid: calendarFolder.get('entryid'),
|
||||
store_entryid: calendarFolder.get('store_entryid')
|
||||
});
|
||||
|
||||
var busystate = new Array("FREE", "TENTATIVE", "BUSY", "OOF");
|
||||
var zlabel = new Array("NONE", "IMPORTANT", "WORK", "PERSONAL", "HOLIDAY", "REQUIRED", "TRAVEL REQUIRED", "PREPARATION REQUIERED", "BIRTHDAY", "SPECIAL DATE", "PHONE INTERVIEW");
|
||||
|
||||
/* optional fields */
|
||||
if(entry.priority !== "") {
|
||||
newRecord.data.importance = entry.priority;
|
||||
}
|
||||
if(entry.label !== "") {
|
||||
newRecord.data.label = zlabel.indexOf(entry.label);
|
||||
}
|
||||
if(entry.busy !== "") {
|
||||
newRecord.data.busystatus = busystate.indexOf(entry.busy);
|
||||
}
|
||||
if(entry.privatestate !== "") {
|
||||
newRecord.data["private"] = entry.privatestate == "PUBLIC" ? false : true;
|
||||
}
|
||||
if(entry.organizer !== "") {
|
||||
newRecord.data.sent_representing_email_address = entry.organizer;
|
||||
}
|
||||
if(entry.trigger != null) {
|
||||
newRecord.data.reminder = true;
|
||||
newRecord.data.reminder_minutes = new Date((entry.start - entry.trigger)/60);
|
||||
newRecord.data.reminder_time = new Date(entry.trigger);
|
||||
} else {
|
||||
newRecord.data.reminder = false;
|
||||
}
|
||||
|
||||
return newRecord;
|
||||
},
|
||||
|
||||
importCheckedEvents: function () {
|
||||
var newRecords = this.eventgrid.selModel.getSelections();
|
||||
this.importEvents(newRecords);
|
||||
@ -584,295 +483,15 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
this.importEvents(newRecords);
|
||||
},
|
||||
|
||||
exportAllEvents: function () {
|
||||
//receive existing calendar store
|
||||
var calValue = this.calendarselector.value;
|
||||
|
||||
if(calValue == undefined) { // no calendar choosen
|
||||
Zarafa.common.dialogs.MessageBox.show({
|
||||
title : _('Error'),
|
||||
msg : _('You have to choose a calendar!'),
|
||||
icon : Zarafa.common.dialogs.MessageBox.ERROR,
|
||||
buttons : Zarafa.common.dialogs.MessageBox.OK
|
||||
});
|
||||
} else {
|
||||
var calexist = true;
|
||||
var calendarFolder = container.getHierarchyStore().getDefaultFolder('calendar');
|
||||
var pubStore = container.getHierarchyStore().getPublicStore();
|
||||
var pubSubFolders = [];
|
||||
var pubFolder;
|
||||
|
||||
if(typeof pubStore !== "undefined") {
|
||||
try {
|
||||
pubFolder = pubStore.getDefaultFolder("publicfolders");
|
||||
pubSubFolders = pubFolder.getChildren();
|
||||
} catch (e) {
|
||||
console.log("Error opening the shared folder...");
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
if(calValue != "calendar") {
|
||||
var subFolders = calendarFolder.getChildren();
|
||||
var i = 0;
|
||||
|
||||
/* add public folders if any exist */
|
||||
for(i = 0; i < pubSubFolders.length; i++) {
|
||||
if(pubSubFolders[i].isContainerClass("IPF.Appointment")){
|
||||
subFolders.push(pubSubFolders[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0;i<subFolders.length;i++) {
|
||||
// loo up right folder
|
||||
// TODO: improve!!
|
||||
if(subFolders[i].getDisplayName() == calValue) {
|
||||
calendarFolder = subFolders[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(calendarFolder.isDefaultFolder()) {
|
||||
Zarafa.common.dialogs.MessageBox.show({
|
||||
title : _('Error'),
|
||||
msg : _('Selected calendar does not exist!'),
|
||||
icon : Zarafa.common.dialogs.MessageBox.ERROR,
|
||||
buttons : Zarafa.common.dialogs.MessageBox.OK
|
||||
});
|
||||
calexist = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(calexist) {
|
||||
Zarafa.common.dialogs.MessageBox.show({
|
||||
title: 'Please wait',
|
||||
msg: 'Generating ical file...',
|
||||
progressText: 'Exporting...',
|
||||
width:300,
|
||||
progress:true,
|
||||
closable:false
|
||||
});
|
||||
|
||||
// progress bar... ;)
|
||||
var updateProgressBar = function(v){
|
||||
return function(){
|
||||
if(v == 100){
|
||||
if(Zarafa.common.dialogs.MessageBox.isVisible()) {
|
||||
updateTimer();
|
||||
}
|
||||
}else{
|
||||
Zarafa.common.dialogs.MessageBox.updateProgress(v/100, 'Exporting...');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var updateTimer = function() {
|
||||
for(var i = 1; i < 101; i++){
|
||||
setTimeout(updateProgressBar(i), 20*i);
|
||||
}
|
||||
};
|
||||
|
||||
updateTimer();
|
||||
|
||||
// call export function here!
|
||||
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
||||
successCallback: this.exportPagedEvents.createDelegate(this)
|
||||
});
|
||||
|
||||
container.getRequest().singleRequest(
|
||||
'appointmentlistmodule',
|
||||
'list',
|
||||
{
|
||||
groupDir: "ASC",
|
||||
restriction: {
|
||||
//start: 0,
|
||||
//limit: 500, // limit to 500 events.... not working because of hardcoded limit in listmodule
|
||||
//startdate: 0,
|
||||
//duedate: 2145826800 // 2037... nearly highest unix timestamp
|
||||
},
|
||||
sort: [{
|
||||
"field": "startdate",
|
||||
"direction": "DESC"
|
||||
}],
|
||||
store_entryid : calendarFolder.data.store_entryid,
|
||||
entryid : calendarFolder.data.entryid
|
||||
},
|
||||
responseHandler
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate needed Requests for all events
|
||||
* Needed because the listmodule has hardcoded pageing setting -.-
|
||||
* @param {Object} response
|
||||
*/
|
||||
exportPagedEvents:function(response) {
|
||||
|
||||
if(response.page.start = 0 && response.item.length <= 0) {
|
||||
container.getNotifier().notify('info', 'Export Failed', 'There were no items to export!');
|
||||
Zarafa.common.dialogs.MessageBox.hide();
|
||||
} else {
|
||||
this.exportResponse = response.item;
|
||||
}
|
||||
|
||||
if(this.totalExportCount == null) {
|
||||
this.totalExportCount = response.page.totalrowcount;
|
||||
}
|
||||
|
||||
var requests = Math.ceil(response.page.totalrowcount / response.page.rowcount);
|
||||
this.runningRequests = requests;
|
||||
|
||||
var i = 0;
|
||||
|
||||
//receive existing calendar store
|
||||
var calValue = this.calendarselector.value;
|
||||
var calendarFolder = container.getHierarchyStore().getDefaultFolder('calendar');
|
||||
var pubStore = container.getHierarchyStore().getPublicStore();
|
||||
var pubSubFolders = [];
|
||||
var pubFolder;
|
||||
|
||||
if(typeof pubStore !== "undefined") {
|
||||
try {
|
||||
pubFolder = pubStore.getDefaultFolder("publicfolders");
|
||||
pubSubFolders = pubFolder.getChildren();
|
||||
} catch (e) {
|
||||
console.log("Error opening the shared folder...");
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
if(calValue != "calendar") {
|
||||
var subFolders = calendarFolder.getChildren();
|
||||
i = 0;
|
||||
|
||||
/* add public folders if any exist */
|
||||
for(i = 0; i < pubSubFolders.length; i++) {
|
||||
if(pubSubFolders[i].isContainerClass("IPF.Appointment")){
|
||||
subFolders.push(pubSubFolders[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0;i<subFolders.length;i++) {
|
||||
// loo up right folder
|
||||
// TODO: improve!!
|
||||
if(subFolders[i].getDisplayName() == calValue) {
|
||||
calendarFolder = subFolders[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(calendarFolder.isDefaultFolder()) {
|
||||
Zarafa.common.dialogs.MessageBox.show({
|
||||
title : _('Error'),
|
||||
msg : _('Selected calendar does not exist!'),
|
||||
icon : Zarafa.common.dialogs.MessageBox.ERROR,
|
||||
buttons : Zarafa.common.dialogs.MessageBox.OK
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < requests; i++) {
|
||||
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
||||
successCallback: this.storeResult.createDelegate(this)
|
||||
});
|
||||
this.requestNext(calendarFolder, responseHandler, response.page.rowcount *(i+1), response.page.rowcount);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Responsehandler for the single requests... will merge all events into one array
|
||||
* @param {Object} response
|
||||
*/
|
||||
storeResult: function(response) {
|
||||
var tmp = this.exportResponse;
|
||||
|
||||
this.exportResponse = tmp.concat(response.item);
|
||||
|
||||
if(this.runningRequests <= 1) {
|
||||
// final request =)
|
||||
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
||||
successCallback: this.downLoadICS.createDelegate(this)
|
||||
});
|
||||
|
||||
container.getRequest().singleRequest(
|
||||
'calendarmodule',
|
||||
'export',
|
||||
{
|
||||
data: this.exportResponse,
|
||||
calendar: this.calendarselector.value
|
||||
},
|
||||
responseHandler
|
||||
);
|
||||
container.getNotifier().notify('info', 'Exported', 'Found ' + this.exportResponse.length + ' entries to export. Preparing download...');
|
||||
this.dialog.close();
|
||||
}
|
||||
|
||||
this.runningRequests--;
|
||||
},
|
||||
|
||||
/**
|
||||
* build a new event request for the listmodule
|
||||
* @param {Object} calendarFolder the calendarFolder to export
|
||||
* @param {Object} responseHandler (should be storeResult)
|
||||
* @param {int} start
|
||||
* @param {int} limit
|
||||
*/
|
||||
requestNext: function(calendarFolder, responseHandler, start, limit) {
|
||||
|
||||
container.getRequest().singleRequest(
|
||||
'appointmentlistmodule',
|
||||
'list',
|
||||
{
|
||||
groupDir: "ASC",
|
||||
restriction: {
|
||||
start: start,
|
||||
limit: limit
|
||||
//startdate: 0,
|
||||
//duedate: 2145826800 // 2037... nearly highest unix timestamp
|
||||
},
|
||||
sort: [{
|
||||
"field": "startdate",
|
||||
"direction": "DESC"
|
||||
}],
|
||||
store_entryid : calendarFolder.data.store_entryid,
|
||||
entryid : calendarFolder.data.entryid
|
||||
},
|
||||
responseHandler
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* download ics file =)
|
||||
* @param {Object} response
|
||||
* @private
|
||||
*/
|
||||
downLoadICS : function(response) {
|
||||
Zarafa.common.dialogs.MessageBox.hide();
|
||||
if(response.status === true) {
|
||||
if(!this.downloadFrame){
|
||||
this.downloadFrame = Ext.getBody().createChild({
|
||||
tag: 'iframe',
|
||||
cls: 'x-hidden'
|
||||
});
|
||||
}
|
||||
var url = 'plugins/calendarimporter/php/download.php?fileid='+response.fileid+'&basedir='+response.basedir+'&secid='+response.secid+'&realname='+response.realname;
|
||||
this.downloadFrame.dom.contentWindow.location = url;
|
||||
} else {
|
||||
container.getNotifier().notify('error', 'Export Failed', 'ICal File creation failed!');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This function stores all given events to the appointmentstore
|
||||
* @param events
|
||||
*/
|
||||
importEvents: function (events) {
|
||||
//receive existing calendar store
|
||||
var calValue = this.calendarselector.value;
|
||||
var calValue = this.calendarselector.getValue();
|
||||
|
||||
if(calValue == undefined) { // no calendar choosen
|
||||
if(Ext.isEmpty(calValue)) { // no calendar choosen
|
||||
Zarafa.common.dialogs.MessageBox.show({
|
||||
title : _('Error'),
|
||||
msg : _('You have to choose a calendar!'),
|
||||
@ -880,7 +499,6 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
buttons : Zarafa.common.dialogs.MessageBox.OK
|
||||
});
|
||||
} else {
|
||||
var calexist = true;
|
||||
if(this.eventgrid.selModel.getCount() < 1) {
|
||||
Zarafa.common.dialogs.MessageBox.show({
|
||||
title : _('Error'),
|
||||
@ -889,53 +507,54 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||
buttons : Zarafa.common.dialogs.MessageBox.OK
|
||||
});
|
||||
} else {
|
||||
var calendarStore = new Zarafa.calendar.AppointmentStore();
|
||||
var calendarFolder = container.getHierarchyStore().getDefaultFolder('calendar');
|
||||
var pubStore = container.getHierarchyStore().getPublicStore();
|
||||
var pubFolder = pubStore.getDefaultFolder("publicfolders");
|
||||
var pubSubFolders = pubFolder.getChildren();
|
||||
var calendarFolder = Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(calValue);
|
||||
|
||||
if(calValue != "calendar") {
|
||||
var subFolders = calendarFolder.getChildren();
|
||||
var i = 0;
|
||||
for(i = 0; i < pubSubFolders.length; i++) {
|
||||
if(pubSubFolders[i].isContainerClass("IPF.Appointment")){
|
||||
subFolders.push(pubSubFolders[i]);
|
||||
}
|
||||
}
|
||||
for(i=0;i<subFolders.length;i++) {
|
||||
// look up right folder
|
||||
// TODO: improve!!
|
||||
if(subFolders[i].getDisplayName() == calValue) {
|
||||
calendarFolder = subFolders[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.loadMask.show();
|
||||
var uids = [];
|
||||
|
||||
if(calendarFolder.isDefaultFolder()) {
|
||||
//receive Records from grid rows
|
||||
Ext.each(events, function(newRecord) {
|
||||
uids.push(newRecord.data.record.internal_fields.event_uid);
|
||||
}, this);
|
||||
|
||||
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
||||
successCallback: this.importEventsDone,
|
||||
scope: this
|
||||
});
|
||||
|
||||
container.getRequest().singleRequest(
|
||||
'calendarmodule',
|
||||
'import',
|
||||
{
|
||||
storeid : calendarFolder.store_entryid,
|
||||
folderid : calendarFolder.entryid,
|
||||
uids : uids,
|
||||
ics_filepath: this.icsfile
|
||||
},
|
||||
responseHandler
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for the import request.
|
||||
* @param {Object} response
|
||||
*/
|
||||
importEventsDone: function (response) {
|
||||
var self = this.scope;
|
||||
|
||||
self.loadMask.hide();
|
||||
self.dialog.close();
|
||||
if (response.status == true) {
|
||||
container.getNotifier().notify('info', 'Imported', 'Imported ' + response.count + ' events. Please reload your calendar!');
|
||||
} else {
|
||||
Zarafa.common.dialogs.MessageBox.show({
|
||||
title : _('Error'),
|
||||
msg : _('Selected calendar does not exist!'),
|
||||
msg : _('Import failed: ') + response.message,
|
||||
icon : Zarafa.common.dialogs.MessageBox.ERROR,
|
||||
buttons: Zarafa.common.dialogs.MessageBox.OK
|
||||
});
|
||||
calexist = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(calexist) {
|
||||
this.loadMask.show();
|
||||
//receive Records from grid rows
|
||||
Ext.each(events, function(newRecord) {
|
||||
var record = this.convertToAppointmentRecord(calendarFolder,newRecord.data);
|
||||
calendarStore.add(record);
|
||||
}, this);
|
||||
calendarStore.save();
|
||||
this.loadMask.hide();
|
||||
this.dialog.close();
|
||||
container.getNotifier().notify('info', 'Imported', 'Imported ' + events.length + ' events. Please reload your calendar!');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -2,7 +2,7 @@
|
||||
* plugin.calendarimporter.js zarafa calender to ics im/exporter
|
||||
*
|
||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||
* Copyright (C) 2012-2013 Christoph Haas
|
||||
* Copyright (C) 2012-2016 Christoph Haas
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -47,44 +47,69 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
|
||||
|
||||
/* directly import received icals */
|
||||
this.registerInsertionPoint('common.contextmenu.attachment.actions', this.createAttachmentImportButton);
|
||||
/* add import button to south navigation */
|
||||
this.registerInsertionPoint("navigation.south", this.createImportButton, this);
|
||||
|
||||
/* add settings widget */
|
||||
this.registerInsertionPoint('context.settings.category.calendar', this.createSettingsWidget);
|
||||
|
||||
/* export a calendar entry via rightclick */
|
||||
this.registerInsertionPoint('context.calendar.contextmenu.actions', this.createItemExportInsertionPoint, this);
|
||||
|
||||
/* ical sync stuff */
|
||||
if (container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/enable_sync") === true) {
|
||||
/* edit panel */
|
||||
Zarafa.core.data.SharedComponentType.addProperty('plugins.calendarimporter.settings.dialogs.calsyncedit');
|
||||
|
||||
/* enable the settings widget */
|
||||
this.registerInsertionPoint('context.settings.category.calendar', this.createSettingsCalSyncWidget);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the button
|
||||
*
|
||||
* @return {Object} Configuration object for a {@link Ext.Button button}
|
||||
* This method hooks to the contact context menu and allows users to export users to vcf.
|
||||
*
|
||||
* @param include
|
||||
* @param btn
|
||||
* @returns {Object}
|
||||
*/
|
||||
createImportButton: function () {
|
||||
var button = {
|
||||
xtype : 'button',
|
||||
ref : "importbutton",
|
||||
id : "importbutton",
|
||||
text : _('Import Calendar'),
|
||||
iconCls : 'icon_calendarimporter_button',
|
||||
navigationContext : container.getContextByName('calendar'),
|
||||
handler : this.onImportButtonClick,
|
||||
scope : this
|
||||
createItemExportInsertionPoint: function (include, btn) {
|
||||
return {
|
||||
text : dgettext('plugin_files', 'Export Event'),
|
||||
handler: this.exportToICS.createDelegate(this, [btn]),
|
||||
scope : this,
|
||||
iconCls: 'icon_calendarimporter_export'
|
||||
};
|
||||
},
|
||||
|
||||
if(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/enable_export")) {
|
||||
button.text = _('Import/Export Calendar');
|
||||
/**
|
||||
* Generates a request to download the selected records as vCard.
|
||||
* @param {Ext.Button} btn
|
||||
*/
|
||||
exportToICS: function (btn) {
|
||||
if (btn.records.length == 0) {
|
||||
return; // skip if no records where given!
|
||||
}
|
||||
|
||||
return button;
|
||||
var recordIds = [];
|
||||
|
||||
for (var i = 0; i < btn.records.length; i++) {
|
||||
recordIds.push(btn.records[i].get("entryid"));
|
||||
}
|
||||
|
||||
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
||||
successCallback: Zarafa.plugins.calendarimporter.data.Actions.downloadICS,
|
||||
scope : this
|
||||
});
|
||||
|
||||
// request attachment preperation
|
||||
container.getRequest().singleRequest(
|
||||
'calendarmodule',
|
||||
'export',
|
||||
{
|
||||
storeid: btn.records[0].get("store_entryid"),
|
||||
records: recordIds
|
||||
},
|
||||
responseHandler
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -118,17 +143,17 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
|
||||
*/
|
||||
createAttachmentImportButton: function (include, btn) {
|
||||
return {
|
||||
text : _('Import Calendar'),
|
||||
handler : this.getAttachmentFileName.createDelegate(this, [btn, this.gotAttachmentFileName]),
|
||||
text : _('Import to Calendar'),
|
||||
handler : this.getAttachmentFileName.createDelegate(this, [btn]),
|
||||
scope : this,
|
||||
iconCls : 'icon_calendarimporter_button',
|
||||
beforeShow: function (item, record) {
|
||||
var extension = record.data.name.split('.').pop().toLowerCase();
|
||||
|
||||
if (record.data.filetype == "text/calendar" || extension == "ics" || extension == "ifb" || extension == "ical" || extension == "ifbf") {
|
||||
item.setDisabled(false);
|
||||
item.setVisible(true);
|
||||
} else {
|
||||
item.setDisabled(true);
|
||||
item.setVisible(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -139,10 +164,7 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
|
||||
*/
|
||||
gotAttachmentFileName: function (response) {
|
||||
if (response.status == true) {
|
||||
Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents'], undefined, {
|
||||
manager : Ext.WindowMgr,
|
||||
filename : response.tmpname
|
||||
});
|
||||
this.scope.openImportDialog(response.tmpname);
|
||||
} else {
|
||||
Zarafa.common.dialogs.MessageBox.show({
|
||||
title : _('Error'),
|
||||
@ -188,21 +210,23 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
|
||||
var store = attachmentStore.getParentRecord().get('store_entryid');
|
||||
var entryid = attachmentStore.getAttachmentParentRecordEntryId();
|
||||
var attachNum = new Array(1);
|
||||
if (attachmentRecord.get('attach_num') != -1)
|
||||
if (attachmentRecord.get('attach_num') != -1) {
|
||||
attachNum[0] = attachmentRecord.get('attach_num');
|
||||
else
|
||||
} else {
|
||||
attachNum[0] = attachmentRecord.get('tmpname');
|
||||
}
|
||||
var dialog_attachments = attachmentStore.getId();
|
||||
var filename = attachmentRecord.data.name;
|
||||
|
||||
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
||||
successCallback: callback
|
||||
successCallback: this.gotAttachmentFileName,
|
||||
scope : this
|
||||
});
|
||||
|
||||
// request attachment preperation
|
||||
container.getRequest().singleRequest(
|
||||
'calendarmodule',
|
||||
'attachmentpath',
|
||||
'importattachment',
|
||||
{
|
||||
entryid : entryid,
|
||||
store : store,
|
||||
@ -215,12 +239,17 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
|
||||
},
|
||||
|
||||
/**
|
||||
* Clickhandler for the button
|
||||
* Open the import dialog.
|
||||
* @param {String} filename
|
||||
*/
|
||||
onImportButtonClick: function () {
|
||||
Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents'], undefined, {
|
||||
manager : Ext.WindowMgr
|
||||
});
|
||||
openImportDialog: function (filename) {
|
||||
var componentType = Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents'];
|
||||
var config = {
|
||||
filename: filename,
|
||||
modal : true
|
||||
};
|
||||
|
||||
Zarafa.core.data.UIFactory.openLayerComponent(componentType, undefined, config);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -240,6 +269,13 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
|
||||
case Zarafa.core.data.SharedComponentType['plugins.calendarimporter.settings.dialogs.calsyncedit']:
|
||||
bid = 2;
|
||||
break;
|
||||
case Zarafa.core.data.SharedComponentType['common.contextmenu']:
|
||||
if (record instanceof Zarafa.core.data.MAPIRecord) {
|
||||
if (record.get('object_type') == Zarafa.core.mapi.ObjectType.MAPI_FOLDER && record.get('container_class') == "IPF.Appointment") {
|
||||
bid = 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return bid;
|
||||
},
|
||||
@ -260,6 +296,9 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
|
||||
case Zarafa.core.data.SharedComponentType['plugins.calendarimporter.settings.dialogs.calsyncedit']:
|
||||
component = Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditContentPanel;
|
||||
break;
|
||||
case Zarafa.core.data.SharedComponentType['common.contextmenu']:
|
||||
component = Zarafa.plugins.calendarimporter.ui.ContextMenu;
|
||||
break;
|
||||
}
|
||||
|
||||
return component;
|
||||
|
@ -27,6 +27,7 @@ Zarafa.plugins.calendarimporter.settings.SettingsCalSyncWidget = Ext.extend(Zara
|
||||
{ name : 'pass' },
|
||||
{ name : 'intervall', type : 'int' },
|
||||
{ name : 'calendar' },
|
||||
{ name : 'calendarname' },
|
||||
{ name : 'lastsync' }
|
||||
],
|
||||
sortInfo : {
|
||||
@ -68,8 +69,10 @@ Zarafa.plugins.calendarimporter.settings.SettingsCalSyncWidget = Ext.extend(Zara
|
||||
var icslinks = settingsModel.get('zarafa/v1/contexts/calendar/icssync', true);
|
||||
var syncArray = [];
|
||||
for (var key in icslinks) {
|
||||
if(icslinks.hasOwnProperty(key)) { // skip inherited props
|
||||
syncArray.push(Ext.apply({}, icslinks[key], {id: key}));
|
||||
}
|
||||
}
|
||||
|
||||
// Load all icslinks into the GridPanel
|
||||
var store = this.calsyncPanel.calsyncGrid.getStore();
|
||||
@ -98,7 +101,8 @@ Zarafa.plugins.calendarimporter.settings.SettingsCalSyncWidget = Ext.extend(Zara
|
||||
'user' : icslink.get('user'),
|
||||
'pass' : icslink.get('pass'),
|
||||
'lastsync' : icslink.get('lastsync'),
|
||||
'calendar' : icslink.get('calendar')
|
||||
'calendar' : icslink.get('calendar'),
|
||||
'calendarname' : Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(icslink.get('calendar')).display_name
|
||||
};
|
||||
}
|
||||
settingsModel.set('zarafa/v1/contexts/calendar/icssync', icslinkData);
|
||||
|
@ -24,13 +24,6 @@ Zarafa.plugins.calendarimporter.settings.SettingsWidget = Ext.extend(Zarafa.sett
|
||||
title : _('Calendar Import/Export plugin settings'),
|
||||
xtype : 'calendarimporter.settingswidget',
|
||||
items : [
|
||||
{
|
||||
xtype : 'checkbox',
|
||||
name : 'zarafa/v1/plugins/calendarimporter/enable_export',
|
||||
ref : 'enableExport',
|
||||
fieldLabel : 'Enable exporter',
|
||||
lazyInit : false
|
||||
},
|
||||
{
|
||||
xtype : 'checkbox',
|
||||
name : 'zarafa/v1/plugins/calendarimporter/enable_sync',
|
||||
@ -47,43 +40,14 @@ Zarafa.plugins.calendarimporter.settings.SettingsWidget = Ext.extend(Zarafa.sett
|
||||
},
|
||||
|
||||
createSelectBox: function() {
|
||||
var defaultFolder = container.getHierarchyStore().getDefaultFolder('calendar'); // @type: Zarafa.hierarchy.data.MAPIFolderRecord
|
||||
var subFolders = defaultFolder.getChildren();
|
||||
var myStore = [];
|
||||
|
||||
/* add all local calendar folders */
|
||||
var i = 0;
|
||||
myStore.push(new Array(defaultFolder.getDefaultFolderKey(), defaultFolder.getDisplayName()));
|
||||
for(i = 0; i < subFolders.length; i++) {
|
||||
/* Store all subfolders */
|
||||
myStore.push(new Array(subFolders[i].getDisplayName(), subFolders[i].getDisplayName(), false)); // 3rd field = isPublicfolder
|
||||
}
|
||||
|
||||
/* add all shared calendar folders */
|
||||
var pubStore = container.getHierarchyStore().getPublicStore();
|
||||
|
||||
if(typeof pubStore !== "undefined") {
|
||||
try {
|
||||
var pubFolder = pubStore.getDefaultFolder("publicfolders");
|
||||
var pubSubFolders = pubFolder.getChildren();
|
||||
|
||||
for(i = 0; i < pubSubFolders.length; i++) {
|
||||
if(pubSubFolders[i].isContainerClass("IPF.Appointment")){
|
||||
myStore.push(new Array(pubSubFolders[i].getDisplayName(), pubSubFolders[i].getDisplayName() + " [Shared]", true)); // 3rd field = isPublicfolder
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Error opening the shared folder...");
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
var myStore = Zarafa.plugins.calendarimporter.data.Actions.getAllCalendarFolders(true);
|
||||
|
||||
return {
|
||||
xtype: "selectbox",
|
||||
ref : 'defaultCalendar',
|
||||
editable: false,
|
||||
name: "zarafa/v1/plugins/calendarimporter/default_calendar",
|
||||
value: container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_calendar"),
|
||||
value: Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByName(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_calendar")).entryid,
|
||||
width: 100,
|
||||
fieldLabel: "Default calender",
|
||||
store: myStore,
|
||||
@ -123,9 +87,8 @@ Zarafa.plugins.calendarimporter.settings.SettingsWidget = Ext.extend(Zarafa.sett
|
||||
* @param {Zarafa.settings.SettingsModel} settingsModel The settings to load
|
||||
*/
|
||||
update : function(settingsModel) {
|
||||
this.enableExport.setValue(settingsModel.get(this.enableExport.name));
|
||||
this.enableSync.setValue(settingsModel.get(this.enableSync.name));
|
||||
this.defaultCalendar.setValue(settingsModel.get(this.defaultCalendar.name));
|
||||
this.defaultCalendar.setValue(Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByName(settingsModel.get(this.defaultCalendar.name)).entryid);
|
||||
this.defaultTimezone.setValue(settingsModel.get(this.defaultTimezone.name));
|
||||
},
|
||||
|
||||
@ -136,10 +99,114 @@ Zarafa.plugins.calendarimporter.settings.SettingsWidget = Ext.extend(Zarafa.sett
|
||||
* @param {Zarafa.settings.SettingsModel} settingsModel The settings to update
|
||||
*/
|
||||
updateSettings : function(settingsModel) {
|
||||
settingsModel.set(this.enableExport.name, this.enableExport.getValue());
|
||||
// check if the user changed a value
|
||||
var changed = false;
|
||||
|
||||
if(settingsModel.get(this.enableSync.name) != this.enableSync.getValue()) {
|
||||
changed = true;
|
||||
} else if(settingsModel.get(this.defaultCalendar.name) != Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(this.defaultCalendar.getValue()).display_name) {
|
||||
changed = true;
|
||||
} else if(settingsModel.get(this.defaultTimezone.name) != this.defaultTimezone.getValue()) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if(changed) {
|
||||
// Really save changes
|
||||
settingsModel.set(this.enableSync.name, this.enableSync.getValue());
|
||||
settingsModel.set(this.defaultCalendar.name, this.defaultCalendar.getValue());
|
||||
settingsModel.set(this.defaultCalendar.name, Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(this.defaultCalendar.getValue()).display_name); // store name
|
||||
settingsModel.set(this.defaultTimezone.name, this.defaultTimezone.getValue());
|
||||
|
||||
this.onUpdateSettings();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called after the {@link Zarafa.settings.SettingsModel} fires the {@link Zarafa.settings.SettingsModel#save save}
|
||||
* event to indicate the settings were successfully saved and it will forcefully realod the webapp.
|
||||
* settings which were saved to the server.
|
||||
* @private
|
||||
*/
|
||||
onUpdateSettings : function()
|
||||
{
|
||||
var message = _('Your WebApp needs to be reloaded to make the changes visible!');
|
||||
message += '<br/><br/>';
|
||||
message += _('WebApp will automatically restart in order for these changes to take effect');
|
||||
message += '<br/>';
|
||||
|
||||
Zarafa.common.dialogs.MessageBox.addCustomButtons({
|
||||
title: _('Restart WebApp'),
|
||||
msg : message,
|
||||
icon: Ext.MessageBox.QUESTION,
|
||||
fn : this.restartWebapp,
|
||||
customButton : [{
|
||||
text : _('Restart'),
|
||||
name : 'restart'
|
||||
}, {
|
||||
text : _('Cancel'),
|
||||
name : 'cancel'
|
||||
}],
|
||||
scope : this
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for {@link #onResetSettings}. This will check if the user
|
||||
* wishes to reset the default settings or not.
|
||||
* @param {String} button The button which user pressed.
|
||||
* @private
|
||||
*/
|
||||
restartWebapp : function(button)
|
||||
{
|
||||
if (button === 'restart') {
|
||||
var contextModel = this.ownerCt.settingsContext.getModel();
|
||||
var realModel = contextModel.getRealSettingsModel();
|
||||
|
||||
realModel.save();
|
||||
|
||||
this.loadMask = new Zarafa.common.ui.LoadMask(Ext.getBody(), {
|
||||
msg : '<b>' + _('Webapp is reloading, Please wait.') + '</b>'
|
||||
});
|
||||
this.loadMask.show();
|
||||
|
||||
this.mon(realModel, 'save', this.onSettingsSave, this);
|
||||
this.mon(realModel, 'exception', this.onSettingsException, this);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the {@link Zarafa.settings.} fires the {@link Zarafa.settings.SettingsModel#save save}
|
||||
* event to indicate the settings were successfully saved and it will forcefully realod the webapp.
|
||||
* @param {Zarafa.settings.SettingsModel} model The model which fired the event.
|
||||
* @param {Object} parameters The key-value object containing the action and the corresponding
|
||||
* settings which were saved to the server.
|
||||
* @private
|
||||
*/
|
||||
onSettingsSave : function(model, parameters)
|
||||
{
|
||||
this.mun(model, 'save', this.onSettingsSave, this);
|
||||
Zarafa.core.Util.reloadWebapp();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the {@link Zarafa.settings.SettingsModel} fires the {@link Zarafa.settings.SettingsModel#exception exception}
|
||||
* event to indicate the settings were not successfully saved.
|
||||
* @param {Zarafa.settings.SettingsModel} model The settings model which fired the event
|
||||
* @param {String} type The value of this parameter will be either 'response' or 'remote'.
|
||||
* @param {String} action Name of the action (see {@link Ext.data.Api#actions}).
|
||||
* @param {Object} options The object containing a 'path' and 'value' field indicating
|
||||
* respectively the Setting and corresponding value for the setting which was being saved.
|
||||
* @param {Object} response The response object as received from the PHP-side
|
||||
* @private
|
||||
*/
|
||||
onSettingsException : function(model, type, action, options, response)
|
||||
{
|
||||
this.loadMask.hide();
|
||||
|
||||
// Remove event handlers
|
||||
this.mun(model, 'save', this.onSettingsSave, this);
|
||||
this.mun(model, 'exception', this.onSettingsException, this);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -23,7 +23,7 @@ Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditContentPanel = Ext.e
|
||||
model : true,
|
||||
autoSave : false,
|
||||
width : 400,
|
||||
height : 350,
|
||||
height : 400,
|
||||
title : _('ICAL Sync'),
|
||||
items : [{
|
||||
xtype : 'calendarimporter.calsynceditpanel',
|
||||
|
@ -60,7 +60,6 @@ Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditPanel = Ext.extend(E
|
||||
var id = 0;
|
||||
var record = undefined;
|
||||
|
||||
console.log(this);
|
||||
if(!this.currentItem) {
|
||||
record = new store.recordType({
|
||||
id: this.hashCode(this.icsurl.getValue()),
|
||||
@ -69,6 +68,7 @@ Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditPanel = Ext.extend(E
|
||||
user: this.user.getValue(),
|
||||
pass: Ext.util.base64.encode(this.pass.getValue()),
|
||||
calendar: this.calendar.getValue(),
|
||||
calendarname : Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(this.calendar.getValue()).display_name,
|
||||
lastsync: "never"
|
||||
});
|
||||
}
|
||||
@ -82,6 +82,7 @@ Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditPanel = Ext.extend(E
|
||||
this.currentItem.set('user', this.user.getValue());
|
||||
this.currentItem.set('pass', Ext.util.base64.encode(this.pass.getValue()));
|
||||
this.currentItem.set('calendar', this.calendar.getValue());
|
||||
this.currentItem.set('calendarname', Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(this.calendar.getValue()).display_name);
|
||||
}
|
||||
this.dialog.close();
|
||||
}
|
||||
@ -95,14 +96,12 @@ Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditPanel = Ext.extend(E
|
||||
createPanelItems : function(config)
|
||||
{
|
||||
var icsurl = "";
|
||||
var intervall = "";
|
||||
var intervall = "15";
|
||||
var user = "";
|
||||
var pass = "";
|
||||
var calendar = "";
|
||||
|
||||
var defaultFolder = container.getHierarchyStore().getDefaultFolder('calendar'); // @type: Zarafa.hierarchy.data.MAPIFolderRecord
|
||||
var subFolders = defaultFolder.getChildren();
|
||||
var myStore = [];
|
||||
var calendarname = "";
|
||||
var calendar = Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByName(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_calendar")).entryid;
|
||||
var myStore = Zarafa.plugins.calendarimporter.data.Actions.getAllCalendarFolders(true);
|
||||
|
||||
if(config.item){
|
||||
icsurl = config.item.get('icsurl');
|
||||
@ -110,33 +109,7 @@ Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditPanel = Ext.extend(E
|
||||
user = config.item.get('user');
|
||||
pass = Ext.util.base64.decode(config.item.get('pass'));
|
||||
calendar = config.item.get('calendar');
|
||||
}
|
||||
|
||||
/* add all local calendar folders */
|
||||
var i = 0;
|
||||
myStore.push(new Array(defaultFolder.getDefaultFolderKey(), defaultFolder.getDisplayName()));
|
||||
for(i = 0; i < subFolders.length; i++) {
|
||||
/* Store all subfolders */
|
||||
myStore.push(new Array(subFolders[i].getDisplayName(), subFolders[i].getDisplayName(), false)); // 3rd field = isPublicfolder
|
||||
}
|
||||
|
||||
/* add all shared calendar folders */
|
||||
var pubStore = container.getHierarchyStore().getPublicStore();
|
||||
|
||||
if(typeof pubStore !== "undefined") {
|
||||
try {
|
||||
var pubFolder = pubStore.getDefaultFolder("publicfolders");
|
||||
var pubSubFolders = pubFolder.getChildren();
|
||||
|
||||
for(i = 0; i < pubSubFolders.length; i++) {
|
||||
if(pubSubFolders[i].isContainerClass("IPF.Appointment")){
|
||||
myStore.push(new Array(pubSubFolders[i].getDisplayName(), pubSubFolders[i].getDisplayName() + " [Shared]", true)); // 3rd field = isPublicfolder
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Error opening the shared folder...");
|
||||
console.log(e);
|
||||
}
|
||||
calendarname = config.item.get('calendarname');
|
||||
}
|
||||
|
||||
|
||||
|
@ -58,6 +58,16 @@ Zarafa.plugins.calendarimporter.settings.ui.CalSyncGrid = Ext.extend(Ext.grid.Gr
|
||||
return value ? "true" : "false";
|
||||
},
|
||||
|
||||
/**
|
||||
* Render function
|
||||
* @return {String}
|
||||
* @private
|
||||
*/
|
||||
renderCalendarColumn : function(value, p, record)
|
||||
{
|
||||
return Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(value).display_name;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a column model object, used in {@link #colModel} config
|
||||
* @return {Ext.grid.ColumnModel} column model object
|
||||
@ -71,7 +81,7 @@ Zarafa.plugins.calendarimporter.settings.ui.CalSyncGrid = Ext.extend(Ext.grid.Gr
|
||||
renderer : Zarafa.common.ui.grid.Renderers.text
|
||||
},
|
||||
{
|
||||
dataIndex : 'calendar',
|
||||
dataIndex : 'calendarname',
|
||||
header : _('Destination Calender'),
|
||||
renderer : Zarafa.common.ui.grid.Renderers.text
|
||||
},
|
||||
|
129
js/ui/ContextMenu.js
Normal file
129
js/ui/ContextMenu.js
Normal file
@ -0,0 +1,129 @@
|
||||
/**
|
||||
* ContectMenu.js zarafa calender to ics im/exporter
|
||||
*
|
||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||
* Copyright (C) 2012-2016 Christoph Haas
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
Ext.namespace('Zarafa.plugins.calendarimporter.ui');
|
||||
|
||||
/**
|
||||
* @class Zarafa.plugins.calendarimporter.ui.ContextMenu
|
||||
* @extends Zarafa.hierarchy.ui.ContextMenu
|
||||
* @xtype calendarimporter.hierarchycontextmenu
|
||||
*/
|
||||
Zarafa.plugins.calendarimporter.ui.ContextMenu = Ext.extend(Zarafa.hierarchy.ui.ContextMenu, {
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {Object} config Configuration object
|
||||
*/
|
||||
constructor: function (config) {
|
||||
config = config || {};
|
||||
|
||||
if (config.contextNode) {
|
||||
config.contextTree = config.contextNode.getOwnerTree();
|
||||
}
|
||||
|
||||
Zarafa.plugins.calendarimporter.ui.ContextMenu.superclass.constructor.call(this, config);
|
||||
|
||||
// add item to menu
|
||||
var additionalItems = this.createAdditionalContextMenuItems(config);
|
||||
for (var i = 0; i < additionalItems.length; i++) {
|
||||
config.items[0].push(additionalItems[i]);
|
||||
}
|
||||
|
||||
Zarafa.plugins.calendarimporter.ui.ContextMenu.superclass.constructor.call(this, config); // redo ... otherwise menu does not get published
|
||||
},
|
||||
|
||||
/**
|
||||
* Create the Action context menu items.
|
||||
* @param {Object} config Configuration object for the {@link Zarafa.plugins.calendarimporter.ui.ContextMenu ContextMenu}
|
||||
* @return {Zarafa.core.ui.menu.ConditionalItem[]} The list of Action context menu items
|
||||
* @private
|
||||
*
|
||||
* Note: All handlers are called within the scope of {@link Zarafa.plugins.calendarimporter.ui.ContextMenu HierarchyContextMenu}
|
||||
*/
|
||||
createAdditionalContextMenuItems: function (config) {
|
||||
return [{
|
||||
xtype: 'menuseparator'
|
||||
}, {
|
||||
text : _('Import Calendar'),
|
||||
iconCls : 'icon_calendarimporter_import',
|
||||
handler : this.onContextItemImport,
|
||||
beforeShow: function (item, record) {
|
||||
var access = record.get('access') & Zarafa.core.mapi.Access.ACCESS_MODIFY;
|
||||
if (!access || (record.isIPMSubTree() && !record.getMAPIStore().isDefaultStore())) {
|
||||
item.setDisabled(true);
|
||||
} else {
|
||||
item.setDisabled(false);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
text : _('Export Calendar'),
|
||||
iconCls : 'icon_calendarimporter_export',
|
||||
handler : this.onContextItemExport,
|
||||
beforeShow: function (item, record) {
|
||||
var access = record.get('access') & Zarafa.core.mapi.Access.ACCESS_READ;
|
||||
if (!access || (record.isIPMSubTree() && !record.getMAPIStore().isDefaultStore())) {
|
||||
item.setDisabled(true);
|
||||
} else {
|
||||
item.setDisabled(false);
|
||||
}
|
||||
}
|
||||
}];
|
||||
},
|
||||
|
||||
/**
|
||||
* Fires on selecting 'Open' menu option from {@link Zarafa.plugins.calendarimporter.ui.ContextMenu ContextMenu}
|
||||
* @private
|
||||
*/
|
||||
onContextItemExport: function () {
|
||||
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
||||
successCallback: Zarafa.plugins.calendarimporter.data.Actions.downloadICS,
|
||||
scope : this
|
||||
});
|
||||
|
||||
// request attachment preperation
|
||||
container.getRequest().singleRequest(
|
||||
'calendarmodule',
|
||||
'export',
|
||||
{
|
||||
storeid: this.records.get("store_entryid"),
|
||||
folder : this.records.get("entryid")
|
||||
},
|
||||
responseHandler
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fires on selecting 'Open' menu option from {@link Zarafa.plugins.calendarimporter.ui.ContextMenu ContextMenu}
|
||||
* @private
|
||||
*/
|
||||
onContextItemImport: function () {
|
||||
var componentType = Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents'];
|
||||
var config = {
|
||||
modal : true,
|
||||
folder: this.records.get("entryid")
|
||||
};
|
||||
|
||||
Zarafa.core.data.UIFactory.openLayerComponent(componentType, undefined, config);
|
||||
}
|
||||
});
|
||||
|
||||
Ext.reg('calendarimporter.hierarchycontextmenu', Zarafa.plugins.calendarimporter.ui.ContextMenu);
|
12
manifest.xml
12
manifest.xml
@ -2,7 +2,7 @@
|
||||
<!DOCTYPE plugin SYSTEM "manifest.dtd">
|
||||
<plugin version="2">
|
||||
<info>
|
||||
<version>@_@PLUGIN_VERSION@_@</version>
|
||||
<version>2.2.0</version>
|
||||
<name>calendarimporter</name>
|
||||
<title>ICS Calendar Importer/Exporter</title>
|
||||
<author>Christoph Haas</author>
|
||||
@ -20,13 +20,14 @@
|
||||
<serverfile type="module" module="calendarmodule">php/module.calendar.php</serverfile>
|
||||
</server>
|
||||
<client>
|
||||
<clientfile load="release">js/calendarimporter.js</clientfile>
|
||||
<clientfile load="release">js/calendarimporter-debug.js</clientfile>
|
||||
<clientfile load="debug">js/calendarimporter-debug.js</clientfile>
|
||||
|
||||
<clientfile load="source">js/data/timezones.js</clientfile>
|
||||
<clientfile load="source">js/external/Ext.util.base64.js</clientfile>
|
||||
<clientfile load="source">js/plugin.calendarimporter.js</clientfile>
|
||||
<clientfile load="source">js/data/Actions.js</clientfile>
|
||||
<clientfile load="source">js/data/ResponseHandler.js</clientfile>
|
||||
<clientfile load="source">js/external/Ext.util.base64.js</clientfile>
|
||||
<clientfile load="source">js/ui/ContextMenu.js</clientfile>
|
||||
<clientfile load="source">js/dialogs/ImportContentPanel.js</clientfile>
|
||||
<clientfile load="source">js/dialogs/ImportPanel.js</clientfile>
|
||||
<clientfile load="source">js/dialogs/settings/SettingsWidget.js</clientfile>
|
||||
@ -35,9 +36,10 @@
|
||||
<clientfile load="source">js/dialogs/settings/ui/CalSyncPanel.js</clientfile>
|
||||
<clientfile load="source">js/dialogs/settings/dialogs/CalSyncEditContentPanel.js</clientfile>
|
||||
<clientfile load="source">js/dialogs/settings/dialogs/CalSyncEditPanel.js</clientfile>
|
||||
<clientfile load="source">js/plugin.calendarimporter.js</clientfile>
|
||||
</client>
|
||||
<resources>
|
||||
<resourcefile load="release">resources/css/calendarimporter-min.css</resourcefile>
|
||||
<resourcefile load="release">resources/css/calendarimporter.css</resourcefile>
|
||||
<resourcefile load="debug">resources/css/calendarimporter.css</resourcefile>
|
||||
<resourcefile load="source">resources/css/calendarimporter-main.css</resourcefile>
|
||||
</resources>
|
||||
|
5
php/.gitignore
vendored
Normal file
5
php/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
composer.phar
|
||||
.composer.lock
|
||||
composer.lock
|
||||
vendor
|
||||
vendor/*
|
5
php/composer.json
Normal file
5
php/composer.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"require": {
|
||||
"sabre/vobject": "4.1"
|
||||
}
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* download.php, zarafa calender to ics im/exporter
|
||||
* download.php, zarafa calendar to ics im/exporter
|
||||
*
|
||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||
* Copyright (C) 2012-2014 Christoph Haas
|
||||
* Copyright (C) 2012-2016 Christoph Haas
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -20,25 +21,54 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
$basedir = $_GET["basedir"];
|
||||
$secid = $_GET["secid"];
|
||||
$fileid = $_GET["fileid"];
|
||||
$realname = $_GET["realname"];
|
||||
namespace calendarimporter;
|
||||
|
||||
$secfile = $basedir . "/secid." . $secid;
|
||||
$icsfile = $basedir . "/" . $fileid . "." . $secid;
|
||||
|
||||
// if the secid file exists -> download!
|
||||
if(file_exists($secfile)) {
|
||||
@header("Last-Modified: " . @gmdate("D, d M Y H:i:s",time()) . " GMT");
|
||||
@header("Content-type: text/calendar");
|
||||
header("Content-Length: " . filesize($icsfile));
|
||||
header("Content-Disposition: attachment; filename=" . $realname . ".ics");
|
||||
|
||||
//write ics
|
||||
readfile($icsfile);
|
||||
unlink($secfile);
|
||||
unlink($icsfile);
|
||||
class DownloadHandler
|
||||
{
|
||||
/**
|
||||
* Download the given vcf file.
|
||||
* @return bool
|
||||
*/
|
||||
public static function doDownload()
|
||||
{
|
||||
if (isset($_GET["token"])) {
|
||||
$token = $_GET["token"];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
?>
|
||||
if (isset($_GET["filename"])) {
|
||||
$filename = $_GET["filename"];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate token
|
||||
if (!ctype_alnum($token)) { // token is a md5 hash
|
||||
return false;
|
||||
}
|
||||
|
||||
$file = PLUGIN_CALENDARIMPORTER_TMP_UPLOAD . "ics_" . $token . ".ics";
|
||||
|
||||
if (!file_exists($file)) { // invalid token
|
||||
return false;
|
||||
}
|
||||
|
||||
// set headers here
|
||||
header('Content-Disposition: attachment; filename="' . $filename . '"');
|
||||
|
||||
// no caching
|
||||
header('Expires: 0'); // set expiration time
|
||||
header('Content-Description: File Transfer');
|
||||
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
||||
header('Content-Length: ' . filesize($file));
|
||||
header('Content-Type: application/octet-stream');
|
||||
header('Pragma: public');
|
||||
flush();
|
||||
|
||||
// print the downloaded file
|
||||
readfile($file);
|
||||
ignore_user_abort(true);
|
||||
unlink($file);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,552 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* class.icalparser.php zarafa calender to ics im/exporter
|
||||
* http://code.google.com/p/ics-parser/
|
||||
*
|
||||
* Author: Martin Thoma , Christoph Haas <christoph.h@sprinternet.at>
|
||||
* Copyright (C) 2012-2014 Christoph Haas
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is the iCal-class
|
||||
* Parse ics file content to array.
|
||||
*
|
||||
* @param {string} filename The name of the file which should be parsed
|
||||
* @constructor
|
||||
*/
|
||||
class ICal {
|
||||
/* How many ToDos are in this ical? */
|
||||
public /** @type {int} */ $todo_count = 0;
|
||||
|
||||
/* How many events are in this ical? */
|
||||
public /** @type {int} */ $event_count = 0;
|
||||
|
||||
/* Currently editing an alarm? */
|
||||
private /** @type {boolean} */ $isalarm = false;
|
||||
|
||||
/* The parsed calendar */
|
||||
public /** @type {Array} */ $cal;
|
||||
|
||||
/* Error message store... null default */
|
||||
public /** @type {String} */ $errors;
|
||||
|
||||
/* Which keyword has been added to cal at last? */
|
||||
private /** @type {string} */ $_lastKeyWord;
|
||||
|
||||
/* The default timezone, used to convert UTC Time */
|
||||
private /** @type {string} */ $default_timezone = "Europe/Vienna";
|
||||
|
||||
/* The default timezone, used to convert UTC Time */
|
||||
private /** @type {boolean} */ $timezone_set = false;
|
||||
|
||||
/* Ignore Daylight Saving Time */
|
||||
private /** @type {boolean} */ $ignore_dst = false;
|
||||
|
||||
/**
|
||||
* Creates the iCal-Object
|
||||
*
|
||||
* @param {string} $filename The path to the iCal-file
|
||||
*
|
||||
* @return Object The iCal-Object
|
||||
*/
|
||||
public function __construct($filename, $default_timezone, $timezone = false, $igndst = false) {
|
||||
if (!$filename) {
|
||||
$this->errors = "No filename specified";
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->default_timezone = $default_timezone;
|
||||
|
||||
if(isset($timezone) && $timezone != false) {
|
||||
$this->default_timezone = $timezone;
|
||||
$this->timezone_set = true;
|
||||
}
|
||||
|
||||
if(isset($igndst) && $igndst != false) {
|
||||
$this->ignore_dst = true;
|
||||
}
|
||||
|
||||
$lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
if (stristr($lines[0], 'BEGIN:VCALENDAR') === false) {
|
||||
$this->errors = "Not a valid ical file";
|
||||
return false;
|
||||
} else {
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$line = trim($line);
|
||||
$add = $this->keyValueFromString($line);
|
||||
if ($add === false) {
|
||||
$this->addCalendarComponentWithKeyAndValue($type, false, $line);
|
||||
continue;
|
||||
}
|
||||
|
||||
list($keyword, $dummy, $prop, $propvalue, $value) = $add;
|
||||
|
||||
switch ($line) {
|
||||
// http://www.kanzaki.com/docs/ical/vtodo.html
|
||||
case "BEGIN:VTODO":
|
||||
$this->todo_count++;
|
||||
$type = "VTODO";
|
||||
break;
|
||||
|
||||
case "BEGIN:VALARM":
|
||||
//echo "vevent gematcht";
|
||||
$this->isalarm=true;
|
||||
$type = "VEVENT";
|
||||
break;
|
||||
// http://www.kanzaki.com/docs/ical/vevent.html
|
||||
case "BEGIN:VEVENT":
|
||||
//echo "vevent gematcht";
|
||||
$this->event_count++;
|
||||
$type = "VEVENT";
|
||||
break;
|
||||
|
||||
//all other special strings
|
||||
case "BEGIN:VCALENDAR":
|
||||
case "BEGIN:DAYLIGHT":
|
||||
// http://www.kanzaki.com/docs/ical/vtimezone.html
|
||||
case "BEGIN:VTIMEZONE":
|
||||
case "BEGIN:STANDARD":
|
||||
$type = $value;
|
||||
break;
|
||||
case "END:VTODO": // end special text - goto VCALENDAR key
|
||||
case "END:VEVENT":
|
||||
case "END:VCALENDAR":
|
||||
case "END:DAYLIGHT":
|
||||
case "END:VTIMEZONE":
|
||||
case "END:STANDARD":
|
||||
$type = "VCALENDAR";
|
||||
break;
|
||||
case "END:VALARM":
|
||||
$this->isalarm=false;
|
||||
$type = "VEVENT";
|
||||
break;
|
||||
default:
|
||||
$this->addCalendarComponentWithKeyAndValue($type, $keyword, $value, $prop, $propvalue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $this->cal;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to $this->ical array one value and key.
|
||||
*
|
||||
* @param {string} $component This could be VTODO, VEVENT, VCALENDAR, ...
|
||||
* @param {string} $keyword The keyword, for example DTSTART
|
||||
* @param {string} $value The value, for example 20110105T090000Z
|
||||
*
|
||||
* @return {None}
|
||||
*/
|
||||
public function addCalendarComponentWithKeyAndValue($component, $keyword, $value, $prop = false, $propvalue = false) {
|
||||
if ($keyword == false) { // multiline value
|
||||
$keyword = $this->last_keyword;
|
||||
|
||||
switch ($component) {
|
||||
case 'VEVENT':
|
||||
if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND") or stristr($keyword, "TRIGGER")) {
|
||||
$ts = $this->iCalDateToUnixTimestamp($value, $prop, $propvalue);
|
||||
$value = $ts * 1000;
|
||||
}
|
||||
$value = str_replace("\\n", "\n", $value);
|
||||
|
||||
$value = $this->customFilters($keyword, $value);
|
||||
|
||||
if(!$this->isalarm) {
|
||||
$value = $this->cal[$component][$this->event_count - 1][$keyword].$value;
|
||||
} else {
|
||||
$value = $this->cal[$component][$this->event_count - 1]["VALARM"][$keyword].$value;
|
||||
}
|
||||
break;
|
||||
case 'VTODO' :
|
||||
$value = $this->cal[$component][$this->todo_count - 1]
|
||||
[$keyword].$value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* This should not be neccesary anymore*/
|
||||
//always strip additional content....
|
||||
//if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) {
|
||||
//$keyword = explode(";", $keyword);
|
||||
//$keyword = $keyword[0]; // remove additional content like VALUE=DATE
|
||||
//}
|
||||
|
||||
if ((stristr($keyword, "TIMEZONE") || stristr($keyword, "TZID")) && !$this->timezone_set) { // check if timezone already set...
|
||||
$this->default_timezone = $this->trimTimeZone($value); // store the calendertimezone
|
||||
}
|
||||
|
||||
switch ($component) {
|
||||
case "VTODO":
|
||||
$this->cal[$component][$this->todo_count - 1][$keyword] = $value;
|
||||
//$this->cal[$component][$this->todo_count]['Unix'] = $unixtime;
|
||||
break;
|
||||
case "VEVENT":
|
||||
if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND") or stristr($keyword, "TRIGGER")) {
|
||||
$ts = $this->iCalDateToUnixTimestamp($value, $prop, $propvalue);
|
||||
$value = $ts * 1000;
|
||||
}
|
||||
$value = str_replace("\\n", "\n", $value);
|
||||
|
||||
$value = $this->customFilters($keyword, $value);
|
||||
|
||||
if(!$this->isalarm) {
|
||||
$this->cal[$component][$this->event_count - 1][$keyword] = $value;
|
||||
} else {
|
||||
$this->cal[$component][$this->event_count - 1]["VALARM"][$keyword] = $value;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$this->cal[$component][$keyword] = $value;
|
||||
break;
|
||||
}
|
||||
$this->last_keyword = $keyword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter some chars out of the value.
|
||||
*
|
||||
* @param {string} $keyword keyword to which the filter is applied
|
||||
* @param {string} $value to filter
|
||||
* @return {string} filtered value
|
||||
*/
|
||||
private function customFilters($keyword, $value) {
|
||||
if (stristr($keyword, "SUMMARY")) {
|
||||
$value = str_replace("\n", " ", $value); // we don't need linebreaks in the summary...
|
||||
}
|
||||
|
||||
if (stristr($keyword, "SUMMARY")) {
|
||||
$value = str_replace("\,", ",", $value); // strange escaped comma
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim a Timezone String
|
||||
*
|
||||
* @param {string} $timezone timezone string which should be trimmed
|
||||
* @return {string} trimmed value
|
||||
*/
|
||||
private function trimTimeZone($timezone) {
|
||||
if(preg_match('~([?<=/]*)([^/]*[/|-][^/]*$)~', $timezone, $matches)) { // detects tzurls in tzids
|
||||
if ($matches[2] != "") {
|
||||
return $matches[2]; // 2 = extracted timezone
|
||||
} else {
|
||||
return $timezone;
|
||||
}
|
||||
}
|
||||
|
||||
return $timezone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a key-value pair of a string.
|
||||
*
|
||||
* @param {string} $text which is like "VCALENDAR:Begin" or "LOCATION:"
|
||||
*
|
||||
* @return {array} array("Argument", "Optional Arg/Val", "Optional Arg", "Optional Value", "Value")
|
||||
*/
|
||||
public function keyValueFromString($text) {
|
||||
|
||||
preg_match('/(^[^a-z:;]+)([;]+([a-zA-Z]*)[=]*([^:"]*|"[\w\W]*"))?[:]([\w\W]*)/', $text, $matches);
|
||||
|
||||
// this regex has problems with multiple attributes... ATTENDEE;RSVP=TRUE;ROLE=REQ-PARTICIPANT:mailto:jsmith@example.com
|
||||
// TODO: fix this
|
||||
|
||||
if (count($matches) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$matches = array_splice($matches, 1, 5); // 0 = Arg, 1 = Complete Optional Arg/Val, 2 = Optional Arg, 3 = Optional Val, 4 = Value
|
||||
return $matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return UTC Unix timestamp from ical date time format
|
||||
*
|
||||
* @param {string} $icalDate A Date in the format YYYYMMDD[T]HHMMSS[Z] or
|
||||
* YYYYMMDD[T]HHMMSS
|
||||
*
|
||||
* @return {int}
|
||||
*/
|
||||
private function iCalDateToUTCUnixTimestamp($icalDate, $prop, $propvalue) {
|
||||
|
||||
$timezone = false;
|
||||
$allday = false;
|
||||
|
||||
if($prop) {
|
||||
$pos = strpos("TZIDtzid", $prop);
|
||||
if($pos !== false && $propvalue != false) {
|
||||
$timezone = str_replace('"', '', $propvalue);
|
||||
$timezone = str_replace('\'', '', $timezone);
|
||||
$timezone = $this->trimTimeZone($timezone);
|
||||
}
|
||||
}
|
||||
|
||||
/* timestring format */
|
||||
$utc = strpos("zZ",substr($icalDate, -1)) === false ? false : true;
|
||||
|
||||
$icalDate = str_replace('T', '', $icalDate);
|
||||
$icalDate = str_replace('Z', '', $icalDate);
|
||||
|
||||
$pattern = '/([0-9]{4})'; // 1: YYYY
|
||||
$pattern .= '([0-9]{2})'; // 2: MM
|
||||
$pattern .= '([0-9]{2})'; // 3: DD
|
||||
$pattern .= '([0-9]{0,2})'; // 4: HH
|
||||
$pattern .= '([0-9]{0,2})'; // 5: MM
|
||||
$pattern .= '([0-9]{0,2})/'; // 6: SS
|
||||
preg_match($pattern, $icalDate, $date);
|
||||
|
||||
// Unix timestamp can't represent dates before 1970
|
||||
if ($date[1] <= 1970) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if we have a allday event
|
||||
if((!$date[6] || $date[6] === "") || (!$date[5] || $date[5] === "") || (!$date[4] || $date[4] === "")) {
|
||||
$date[6] = 0;
|
||||
$date[5] = 0;
|
||||
$date[4] = 0;
|
||||
$allday = true;
|
||||
|
||||
$dtz = date_default_timezone_get();
|
||||
date_default_timezone_set('UTC');
|
||||
}
|
||||
|
||||
// Unix timestamps after 03:14:07 UTC 2038-01-19 might cause an overflow
|
||||
// if 32 bit integers are used.
|
||||
$timestamp = mktime((int)$date[4],
|
||||
(int)$date[5],
|
||||
(int)$date[6],
|
||||
(int)$date[2],
|
||||
(int)$date[3],
|
||||
(int)$date[1]);
|
||||
|
||||
if($allday) {
|
||||
date_default_timezone_set($dtz);
|
||||
}
|
||||
|
||||
if(!$utc && !$allday) {
|
||||
$tz = $this->default_timezone;
|
||||
if($timezone != false) {
|
||||
$tz = $timezone;
|
||||
}
|
||||
|
||||
$error = false;
|
||||
$this_tz = false;
|
||||
|
||||
try {
|
||||
$this_tz = new DateTimeZone($tz);
|
||||
} catch(Exception $e) {
|
||||
error_log($e->getMessage());
|
||||
$error = true;
|
||||
}
|
||||
|
||||
if($error) {
|
||||
try { // Try using the default calendar timezone
|
||||
$this_tz = new DateTimeZone($this->default_timezone);
|
||||
} catch(Exception $e) {
|
||||
error_log($e->getMessage());
|
||||
$timestamp_utc = $timestamp; // if that fails, we cannot do anymore
|
||||
}
|
||||
}
|
||||
|
||||
if($this_tz != false) {
|
||||
$tz_now = new DateTime("now", $this_tz);
|
||||
$tz_offset = $this_tz->getOffset($tz_now);
|
||||
$timestamp_utc = $timestamp - $tz_offset;
|
||||
}
|
||||
} else {
|
||||
$timestamp_utc = $timestamp;
|
||||
}
|
||||
|
||||
return array($timestamp_utc,$allday);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a timezone specific timestamp
|
||||
* @param {int} $timestamp_utc UTC Timestamp to convert
|
||||
* @param {string} $timezone Timezone
|
||||
* @return {int}
|
||||
*/
|
||||
private function UTCTimestampToTZTimestamp($timestamp_utc, $timezone, $ignore_dst = false) {
|
||||
$this_tz = false;
|
||||
try { // Try using the default calendar timezone
|
||||
$this_tz = new DateTimeZone($this->default_timezone);
|
||||
} catch(Exception $e) {
|
||||
error_log($e->getMessage());
|
||||
$timestamp_utc = $timestamp; // if that fails, we cannot do anymore
|
||||
}
|
||||
if($this_tz != false) {
|
||||
$transition = $this_tz->getTransitions($timestamp_utc,$timestamp_utc);
|
||||
$trans_offset = $transition[0]['offset'];
|
||||
$isdst = $transition[0]['isdst'];
|
||||
|
||||
$tz_now = new DateTime("now", $this_tz);
|
||||
$tz_offset = $this_tz->getOffset($tz_now);
|
||||
|
||||
if(!$ignore_dst) {
|
||||
$tz_offset = $trans_offset; // normaly use dst
|
||||
}
|
||||
|
||||
return $timestamp_utc + $tz_offset;
|
||||
}
|
||||
return $timestamp_utc; // maybe timezone conversion will fail...
|
||||
}
|
||||
|
||||
/**
|
||||
* Return Timezone specific Unix timestamp from ical date time format
|
||||
*
|
||||
* @param {string} $icalDate A Date in the format YYYYMMDD[T]HHMMSS[Z] or
|
||||
* YYYYMMDD[T]HHMMSS
|
||||
*
|
||||
* @return {int}
|
||||
*/
|
||||
public function iCalDateToUnixTimestamp($icalDate, $prop, $propvalue) {
|
||||
list($timestamp, $allday) = $this->iCalDateToUTCUnixTimestamp($icalDate, $prop, $propvalue);
|
||||
|
||||
if(!$allday) {
|
||||
$timestamp = $this->UTCTimestampToTZTimestamp($timestamp, $this->default_timezone, $this->ignore_dst, $allday);
|
||||
}
|
||||
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of arrays with all events. Every event is an associative
|
||||
* array and each property is an element it.
|
||||
*
|
||||
* @return {array}
|
||||
*/
|
||||
public function events() {
|
||||
$array = $this->cal;
|
||||
return $array['VEVENT'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of calendar types.
|
||||
*
|
||||
* @return {array}
|
||||
*/
|
||||
public function calendar() {
|
||||
$array = $this->cal;
|
||||
return $array['VCALENDAR'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default or set timezone
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
public function timezone() {
|
||||
return $this->default_timezone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean value whether thr current calendar has events or not
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
public function hasEvents() {
|
||||
return ( count($this->events()) > 0 ? true : false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false when the current calendar has no events in range, else the
|
||||
* events.
|
||||
*
|
||||
* Note that this function makes use of a UNIX timestamp. This might be a
|
||||
* problem on January the 29th, 2038.
|
||||
* See http://en.wikipedia.org/wiki/Unix_time#Representing_the_number
|
||||
*
|
||||
* @param {boolean} $rangeStart Either true or false
|
||||
* @param {boolean} $rangeEnd Either true or false
|
||||
*
|
||||
* @return {mixed}
|
||||
*/
|
||||
public function eventsFromRange($rangeStart = false, $rangeEnd = false) {
|
||||
$events = $this->sortEventsWithOrder($this->events(), SORT_ASC);
|
||||
|
||||
if (!$events) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$extendedEvents = array();
|
||||
|
||||
if ($rangeStart !== false) {
|
||||
$rangeStart = new DateTime();
|
||||
}
|
||||
|
||||
if ($rangeEnd !== false or $rangeEnd <= 0) {
|
||||
$rangeEnd = new DateTime('2038/01/18');
|
||||
} else {
|
||||
$rangeEnd = new DateTime($rangeEnd);
|
||||
}
|
||||
|
||||
$rangeStart = $rangeStart->format('U');
|
||||
$rangeEnd = $rangeEnd->format('U');
|
||||
|
||||
|
||||
|
||||
// loop through all events by adding two new elements
|
||||
foreach ($events as $anEvent) {
|
||||
$timestamp = $this->iCalDateToUnixTimestamp($anEvent['DTSTART']);
|
||||
if ($timestamp >= $rangeStart && $timestamp <= $rangeEnd) {
|
||||
$extendedEvents[] = $anEvent;
|
||||
}
|
||||
}
|
||||
|
||||
return $extendedEvents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns sorted events
|
||||
*
|
||||
* @param {array} $events An array with events.
|
||||
* @param {array} $sortOrder Either SORT_ASC, SORT_DESC, SORT_REGULAR,
|
||||
* SORT_NUMERIC, SORT_STRING
|
||||
*
|
||||
* @return {array}
|
||||
*/
|
||||
public function sortEventsWithOrder($events, $sortOrder = SORT_ASC) {
|
||||
$extendedEvents = array();
|
||||
|
||||
// loop through all events by adding two new elements
|
||||
foreach ($events as $anEvent) {
|
||||
if (!array_key_exists('UNIX_TIMESTAMP', $anEvent)) {
|
||||
$anEvent['UNIX_TIMESTAMP'] = $this->iCalDateToUnixTimestamp($anEvent['DTSTART']);
|
||||
}
|
||||
|
||||
if (!array_key_exists('REAL_DATETIME', $anEvent)) {
|
||||
$anEvent['REAL_DATETIME'] = date("d.m.Y", $anEvent['UNIX_TIMESTAMP']);
|
||||
}
|
||||
|
||||
$extendedEvents[] = $anEvent;
|
||||
}
|
||||
|
||||
foreach ($extendedEvents as $key => $value) {
|
||||
$timestamp[$key] = $value['UNIX_TIMESTAMP'];
|
||||
}
|
||||
array_multisort($timestamp, $sortOrder, $extendedEvents);
|
||||
|
||||
return $extendedEvents;
|
||||
}
|
||||
}
|
||||
?>
|
@ -21,21 +21,61 @@
|
||||
*
|
||||
*/
|
||||
|
||||
include_once('mapi/class.recurrence.php');
|
||||
include_once('plugins/calendarimporter/php/ical/class.icalcreator.php');
|
||||
include_once('plugins/calendarimporter/php/ical/class.icalparser.php');
|
||||
include_once('vendor/autoload.php');
|
||||
|
||||
class CalendarModule extends Module {
|
||||
use Sabre\VObject;
|
||||
|
||||
private $DEBUG = false; // enable error_log debugging
|
||||
class CalendarModule extends Module
|
||||
{
|
||||
|
||||
private $DEBUG = true; // enable error_log debugging
|
||||
|
||||
private $busystates = null;
|
||||
|
||||
private $labels = null;
|
||||
|
||||
private $attendeetype = null;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param $id
|
||||
* @param $data
|
||||
*/
|
||||
public function __construct($id, $data) {
|
||||
parent::Module($id, $data);
|
||||
public function __construct($id, $data)
|
||||
{
|
||||
parent::__construct($id, $data);
|
||||
|
||||
// init default timezone
|
||||
date_default_timezone_set(PLUGIN_CALENDARIMPORTER_DEFAULT_TIMEZONE);
|
||||
|
||||
// init mappings
|
||||
$this->busystates = array(
|
||||
"FREE",
|
||||
"TENTATIVE",
|
||||
"BUSY",
|
||||
"OOF"
|
||||
);
|
||||
|
||||
$this->labels = array(
|
||||
"NONE",
|
||||
"IMPORTANT",
|
||||
"WORK",
|
||||
"PERSONAL",
|
||||
"HOLIDAY",
|
||||
"REQUIRED",
|
||||
"TRAVEL REQUIRED",
|
||||
"PREPARATION REQUIERED",
|
||||
"BIRTHDAY",
|
||||
"SPECIAL DATE",
|
||||
"PHONE INTERVIEW"
|
||||
);
|
||||
|
||||
$this->attendeetype = array(
|
||||
"NON-PARTICIPANT", // needed as zarafa starts counting at 1
|
||||
"REQ-PARTICIPANT",
|
||||
"OPT-PARTICIPANT",
|
||||
"NON-PARTICIPANT"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -43,7 +83,8 @@ class CalendarModule extends Module {
|
||||
* Exception part is used for authentication errors also
|
||||
* @return boolean true on success or false on failure.
|
||||
*/
|
||||
public function execute() {
|
||||
public function execute()
|
||||
{
|
||||
$result = false;
|
||||
|
||||
if (!$this->DEBUG) {
|
||||
@ -58,13 +99,16 @@ class CalendarModule extends Module {
|
||||
error_log("exec: " . $actionType);
|
||||
}
|
||||
switch ($actionType) {
|
||||
case "load":
|
||||
$result = $this->loadCalendar($actionType, $actionData);
|
||||
break;
|
||||
case "export":
|
||||
$result = $this->exportCalendar($actionType, $actionData);
|
||||
break;
|
||||
case "import":
|
||||
$result = $this->importCalendar($actionType, $actionData);
|
||||
break;
|
||||
case "attachmentpath":
|
||||
case "importattachment":
|
||||
$result = $this->getAttachmentPath($actionType, $actionData);
|
||||
break;
|
||||
default:
|
||||
@ -91,7 +135,8 @@ class CalendarModule extends Module {
|
||||
* @param $length the lenght of the generated string
|
||||
* @return string a random string
|
||||
*/
|
||||
private function randomstring($length = 6) {
|
||||
private function randomstring($length = 6)
|
||||
{
|
||||
// $chars - all allowed charakters
|
||||
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
||||
|
||||
@ -108,224 +153,60 @@ class CalendarModule extends Module {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the secid file (used to verify the download path)
|
||||
* @param $secid the secid, a random security token
|
||||
* Get a property from the array.
|
||||
* @param $props
|
||||
* @param $propname
|
||||
* @return string
|
||||
*/
|
||||
private function createSecIDFile($secid) {
|
||||
$lockFile = TMP_PATH . "/secid." . $secid;
|
||||
$fh = fopen($lockFile, 'w') or die("can't open secid file");
|
||||
$stringData = date(DATE_RFC822);
|
||||
fwrite($fh, $stringData);
|
||||
fclose($fh);
|
||||
private function getProp($props, $propname)
|
||||
{
|
||||
if (isset($props["props"][$propname])) {
|
||||
return $props["props"][$propname];
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the secid file (used to verify the download path)
|
||||
* @param $time a timestamp
|
||||
* @param $incl_time true if date should include time
|
||||
* @ return date object
|
||||
*/
|
||||
private function getIcalDate($time, $incl_time = true) {
|
||||
return $incl_time ? date('Ymd\THis', $time) : date('Ymd', $time);
|
||||
private function getDurationStringFromMintues($minutes, $pos = false) {
|
||||
$pos = $pos === true ? "+" : "-";
|
||||
$str = $pos . "P";
|
||||
|
||||
|
||||
|
||||
// variables for holding values
|
||||
$mins = intval($minutes);
|
||||
$hours = 0;
|
||||
$days = 0;
|
||||
$weeks = 0;
|
||||
|
||||
// calculations
|
||||
if ( $mins >= 60 ) {
|
||||
$hours = (int)($mins / 60);
|
||||
$mins = $mins % 60;
|
||||
}
|
||||
if ( $hours >= 24 ) {
|
||||
$days = (int)($hours / 24);
|
||||
$hours = $hours % 60;
|
||||
}
|
||||
if ( $days >= 7 ) {
|
||||
$weeks = (int)($days / 7);
|
||||
$days = $days % 7;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds an event to the exported calendar)
|
||||
* @param $vevent pointer to the eventstore
|
||||
* @param $event the event to add
|
||||
*/
|
||||
private function addEvent(&$vevent, $event) {
|
||||
|
||||
$busystate = array("FREE", "TENTATIVE", "BUSY", "OOF");
|
||||
$zlabel = array("NONE", "IMPORTANT", "WORK", "PERSONAL", "HOLIDAY", "REQUIRED", "TRAVEL REQUIRED", "PREPARATION REQUIERED", "BIRTHDAY", "SPECIAL DATE", "PHONE INTERVIEW");
|
||||
|
||||
$vevent->setProperty("LOCATION", $event["location"]); // property name - case independent
|
||||
$vevent->setProperty("SUMMARY", $event["subject"]);
|
||||
$vevent->setProperty("DESCRIPTION", str_replace("\n", "\\n",$event["description"]));
|
||||
$vevent->setProperty("COMMENT", "Exported from Zarafa" );
|
||||
$vevent->setProperty("ORGANIZER", $event["sent_representing_email_address"]);
|
||||
$vevent->setProperty("DTSTART", $this->getIcalDate($event["commonstart"]) . "Z");
|
||||
$vevent->setProperty("DTEND", $this->getIcalDate($event["commonend"]) . "Z");
|
||||
$vevent->setProperty("DTSTAMP", $this->getIcalDate($event["creation_time"]) . "Z");
|
||||
$vevent->setProperty("CREATED", $this->getIcalDate($event["creation_time"]) . "Z");
|
||||
$vevent->setProperty("LAST-MODIFIED", $this->getIcalDate($event["last_modification_time"]) . "Z");
|
||||
$vevent->setProperty("X-MICROSOFT-CDO-BUSYSTATUS", $busystate[$event["busystatus"]]);
|
||||
$vevent->setProperty("X-ZARAFA-LABEL", $zlabel[$event["label"]]);
|
||||
$vevent->setProperty("PRIORITY", $event["importance"]);
|
||||
$vevent->setProperty("CLASS", $event["private"] ? "PRIVATE" : "PUBLIC");
|
||||
|
||||
// ATTENDEES
|
||||
if(count($event["attendees"]) > 0) {
|
||||
foreach($event["attendees"] as $attendee) {
|
||||
$vevent->setProperty("ATTENDEE", $attendee["props"]["smtp_address"]);
|
||||
// format result
|
||||
if ( $weeks ) {
|
||||
$str .= "{$weeks}W";
|
||||
}
|
||||
if ( $days ) {
|
||||
$str .= "{$days}D";
|
||||
}
|
||||
if ( $hours ) {
|
||||
$str .= "{$hours}H";
|
||||
}
|
||||
if ( $mins ) {
|
||||
$str .= "{$mins}M";
|
||||
}
|
||||
|
||||
// REMINDERS
|
||||
if($event["reminder"]) {
|
||||
$valarm = & $vevent->newComponent("valarm"); // create an event alarm
|
||||
$valarm->setProperty("action", "DISPLAY" );
|
||||
$valarm->setProperty("description", $vevent->getProperty("SUMMARY")); // reuse the event summary
|
||||
$valarm->setProperty("trigger", $this->getIcalDate($event["reminder_time"]) . "Z"); // create alarm trigger (in UTC datetime)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the descriptiontext of an event
|
||||
* @param $event
|
||||
* @return array with event description/body
|
||||
*/
|
||||
private function loadEventDescription($event) {
|
||||
$entryid = $this->getActionEntryID($event);
|
||||
$store = $this->getActionStore($event);
|
||||
|
||||
$basedate = null;
|
||||
|
||||
$properties = $GLOBALS['properties']->getAppointmentProperties();
|
||||
$plaintext = true;
|
||||
|
||||
$data = array();
|
||||
|
||||
if($store && $entryid) {
|
||||
$message = $GLOBALS['operations']->openMessage($store, $entryid);
|
||||
|
||||
|
||||
// add all standard properties from the series/normal message
|
||||
$data['item'] = $GLOBALS['operations']->getMessageProps($store, $message, $properties, (isset($plaintext) && $plaintext));
|
||||
|
||||
// if appointment is recurring then only we should get properties of occurence if basedate is supplied
|
||||
if($data['item']['props']['recurring'] === true) {
|
||||
if(isset($basedate) && $basedate) {
|
||||
$recur = new Recurrence($store, $message);
|
||||
|
||||
$exceptionatt = $recur->getExceptionAttachment($basedate);
|
||||
|
||||
// Single occurences are never recurring
|
||||
$data['item']['props']['recurring'] = false;
|
||||
|
||||
if($exceptionatt) {
|
||||
// Existing exception (open existing item, which includes basedate)
|
||||
$exceptionattProps = mapi_getprops($exceptionatt, array(PR_ATTACH_NUM));
|
||||
$exception = mapi_attach_openobj($exceptionatt, 0);
|
||||
|
||||
// overwrite properties with the ones from the exception
|
||||
$exceptionProps = $GLOBALS['operations']->getMessageProps($store, $exception, $properties, (isset($plaintext) && $plaintext));
|
||||
|
||||
/**
|
||||
* If recurring item has set reminder to true then
|
||||
* all occurrences before the 'flagdueby' value(of recurring item)
|
||||
* should not show that reminder is set.
|
||||
*/
|
||||
if (isset($exceptionProps['props']['reminder']) && $data['item']['props']['reminder'] == true) {
|
||||
$flagDueByDay = $recur->dayStartOf($data['item']['props']['flagdueby']);
|
||||
|
||||
if ($flagDueByDay > $basedate) {
|
||||
$exceptionProps['props']['reminder'] = false;
|
||||
}
|
||||
}
|
||||
|
||||
// The properties must be merged, if the recipients or attachments are present in the exception
|
||||
// then that list should be used. Otherwise the list from the series must be applied (this
|
||||
// corresponds with OL2007).
|
||||
// @FIXME getMessageProps should not return empty string if exception doesn't contain body
|
||||
// by this change we can handle a situation where user has set empty string in the body explicitly
|
||||
if (!empty($exceptionProps['props']['body']) || !empty($exceptionProps['props']['html_body'])) {
|
||||
if(!empty($exceptionProps['props']['body'])) {
|
||||
$data['item']['props']['body'] = $exceptionProps['props']['body'];
|
||||
}
|
||||
|
||||
if(!empty($exceptionProps['props']['html_body'])) {
|
||||
$data['item']['props']['html_body'] = $exceptionProps['props']['html_body'];
|
||||
}
|
||||
|
||||
$data['item']['props']['isHTML'] = $exceptionProps['props']['isHTML'];
|
||||
}
|
||||
// remove properties from $exceptionProps so array_merge will not overwrite it
|
||||
unset($exceptionProps['props']['html_body']);
|
||||
unset($exceptionProps['props']['body']);
|
||||
unset($exceptionProps['props']['isHTML']);
|
||||
|
||||
$data['item']['props'] = array_merge($data['item']['props'], $exceptionProps['props']);
|
||||
if (isset($exceptionProps['recipients'])) {
|
||||
$data['item']['recipients'] = $exceptionProps['recipients'];
|
||||
}
|
||||
|
||||
if (isset($exceptionProps['attachments'])) {
|
||||
$data['item']['attachments'] = $exceptionProps['attachments'];
|
||||
}
|
||||
|
||||
// Make sure we are using the passed basedate and not something wrong in the opened item
|
||||
$data['item']['props']['basedate'] = $basedate;
|
||||
} else {
|
||||
// opening an occurence of a recurring series (same as normal open, but add basedate, startdate and enddate)
|
||||
$data['item']['props']['basedate'] = $basedate;
|
||||
$data['item']['props']['startdate'] = $recur->getOccurrenceStart($basedate);
|
||||
$data['item']['props']['duedate'] = $recur->getOccurrenceEnd($basedate);
|
||||
$data['item']['props']['commonstart'] = $data['item']['props']['startdate'];
|
||||
$data['item']['props']['commonend'] = $data['item']['props']['duedate'];
|
||||
unset($data['item']['props']['reminder_time']);
|
||||
|
||||
/**
|
||||
* If recurring item has set reminder to true then
|
||||
* all occurrences before the 'flagdueby' value(of recurring item)
|
||||
* should not show that reminder is set.
|
||||
*/
|
||||
if (isset($exceptionProps['props']['reminder']) && $data['item']['props']['reminder'] == true) {
|
||||
$flagDueByDay = $recur->dayStartOf($data['item']['props']['flagdueby']);
|
||||
|
||||
if ($flagDueByDay > $basedate) {
|
||||
$exceptionProps['props']['reminder'] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Opening a recurring series, get the recurrence information
|
||||
$recur = new Recurrence($store, $message);
|
||||
$recurpattern = $recur->getRecurrence();
|
||||
$tz = $recur->tz; // no function to do this at the moment
|
||||
|
||||
// Add the recurrence pattern to the data
|
||||
if(isset($recurpattern) && is_array($recurpattern)) {
|
||||
$data['item']['props'] += $recurpattern;
|
||||
}
|
||||
|
||||
// Add the timezone information to the data
|
||||
if(isset($tz) && is_array($tz)) {
|
||||
$data['item']['props'] += $tz;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data['item']['props']['body'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the attendees of an event
|
||||
* @param $event
|
||||
* @return array with event attendees
|
||||
*/
|
||||
private function loadAttendees($event) {
|
||||
$entryid = $this->getActionEntryID($event);
|
||||
$store = $this->getActionStore($event);
|
||||
|
||||
$basedate = null;
|
||||
|
||||
$properties = $GLOBALS['properties']->getAppointmentProperties();
|
||||
$plaintext = true;
|
||||
|
||||
$data = array();
|
||||
|
||||
if($store && $entryid) {
|
||||
$message = $GLOBALS['operations']->openMessage($store, $entryid);
|
||||
|
||||
|
||||
// add all standard properties from the series/normal message
|
||||
$data['item'] = $GLOBALS['operations']->getMessageProps($store, $message, $properties, (isset($plaintext) && $plaintext));
|
||||
|
||||
}
|
||||
|
||||
return $data['item']['recipients']['item'];
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -333,61 +214,137 @@ class CalendarModule extends Module {
|
||||
* @param $actionType
|
||||
* @param $actionData
|
||||
*/
|
||||
private function exportCalendar($actionType, $actionData) {
|
||||
$secid = $this->randomstring();
|
||||
$this->createSecIDFile($secid);
|
||||
$tmpname = stripslashes($actionData["calendar"] . ".ics." . $this->randomstring(8));
|
||||
$filename = TMP_PATH . "/" . $tmpname . "." . $secid;
|
||||
|
||||
if(!is_writable(TMP_PATH . "/")) {
|
||||
error_log("could not write to export tmp directory!");
|
||||
private function exportCalendar($actionType, $actionData)
|
||||
{
|
||||
// Get store id
|
||||
$storeid = false;
|
||||
if (isset($actionData["storeid"])) {
|
||||
$storeid = $actionData["storeid"];
|
||||
}
|
||||
|
||||
$tz = date("e"); // use php timezone (maybe set up in php.ini, date.timezone)
|
||||
|
||||
if($this->DEBUG) {
|
||||
error_log("PHP Timezone: " . $tz);
|
||||
// Get records
|
||||
$records = array();
|
||||
if (isset($actionData["records"])) {
|
||||
$records = $actionData["records"];
|
||||
}
|
||||
|
||||
$config = array(
|
||||
"language" => substr($GLOBALS["settings"]->get("zarafa/v1/main/language"),0,2),
|
||||
"directory" => TMP_PATH . "/",
|
||||
"filename" => $tmpname . "." . $secid,
|
||||
"unique_id" => "zarafa-export-plugin",
|
||||
"TZID" => $tz
|
||||
);
|
||||
|
||||
$v = new vcalendar($config);
|
||||
$v->setProperty("method", "PUBLISH"); // required of some calendar software
|
||||
$v->setProperty("x-wr-calname", $actionData["calendar"]); // required of some calendar software
|
||||
$v->setProperty("X-WR-CALDESC", "Exported Zarafa Calendar"); // required of some calendar software
|
||||
$v->setProperty("X-WR-TIMEZONE", $tz);
|
||||
|
||||
$xprops = array("X-LIC-LOCATION" => $tz); // required of some calendar software
|
||||
iCalUtilityFunctions::createTimezone($v, $tz, $xprops); // create timezone object in calendar
|
||||
|
||||
|
||||
foreach($actionData["data"] as $event) {
|
||||
$event["props"]["description"] = $this->loadEventDescription($event);
|
||||
$event["props"]["attendees"] = $this->loadAttendees($event);
|
||||
|
||||
$vevent = & $v->newComponent("vevent"); // create a new event object
|
||||
$this->addEvent($vevent, $event["props"]);
|
||||
// Get folders
|
||||
$folder = false;
|
||||
if (isset($actionData["folder"])) {
|
||||
$folder = $actionData["folder"];
|
||||
}
|
||||
|
||||
$v->saveCalendar();
|
||||
$response = array();
|
||||
$error = false;
|
||||
$error_msg = "";
|
||||
|
||||
// write csv
|
||||
$token = $this->randomstring(16);
|
||||
$file = PLUGIN_CALENDARIMPORTER_TMP_UPLOAD . "ics_" . $token . ".ics";
|
||||
file_put_contents($file, "");
|
||||
|
||||
$store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid));
|
||||
if ($store) {
|
||||
// load folder first
|
||||
if ($folder !== false) {
|
||||
$mapifolder = mapi_msgstore_openentry($store, hex2bin($folder));
|
||||
|
||||
$table = mapi_folder_getcontentstable($mapifolder);
|
||||
$list = mapi_table_queryallrows($table, array(PR_ENTRYID));
|
||||
|
||||
foreach ($list as $item) {
|
||||
$records[] = bin2hex($item[PR_ENTRYID]);
|
||||
}
|
||||
}
|
||||
|
||||
$vcalendar = new VObject\Component\VCalendar();
|
||||
|
||||
// Add static stuff to vcalendar
|
||||
$vcalendar->add('METHOD', 'PUBLISH');
|
||||
$vcalendar->add('X-WR-CALDESC', 'Exported Zarafa Calendar');
|
||||
$vcalendar->add('X-WR-TIMEZONE', date_default_timezone_get());
|
||||
|
||||
// TODO: add VTIMEZONE object to ical.
|
||||
|
||||
for ($index = 0, $count = count($records); $index < $count; $index++) {
|
||||
$message = mapi_msgstore_openentry($store, hex2bin($records[$index]));
|
||||
|
||||
// get message properties.
|
||||
$properties = $GLOBALS['properties']->getAppointmentProperties();
|
||||
$plaintext = true;
|
||||
$messageProps = $GLOBALS['operations']->getMessageProps($store, $message, $properties, $plaintext);
|
||||
|
||||
$vevent = $vcalendar->add('VEVENT', [
|
||||
'SUMMARY' => $this->getProp($messageProps, "subject"),
|
||||
'DTSTART' => date_timestamp_set(new DateTime(), $this->getProp($messageProps, "startdate")),
|
||||
'DTEND' => date_timestamp_set(new DateTime(), $this->getProp($messageProps, "duedate")),
|
||||
'CREATED' => date_timestamp_set(new DateTime(), $this->getProp($messageProps, "creation_time")),
|
||||
'LAST-MODIFIED' => date_timestamp_set(new DateTime(), $this->getProp($messageProps, "last_modification_time")),
|
||||
'PRIORITY' => $this->getProp($messageProps, "importance"),
|
||||
'X-MICROSOFT-CDO-INTENDEDSTATUS' => $this->busystates[intval($this->getProp($messageProps, "busystatus"))], // both seem to be valid...
|
||||
'X-MICROSOFT-CDO-BUSYSTATUS' => $this->busystates[intval($this->getProp($messageProps, "busystatus"))], // both seem to be valid...
|
||||
'X-ZARAFA-LABEL' => $this->labels[intval($this->getProp($messageProps, "label"))],
|
||||
'CLASS' => $this->getProp($messageProps, "private") ? "PRIVATE" : "PUBLIC",
|
||||
'COMMENT' => "eid:" . $records[$index]
|
||||
]);
|
||||
|
||||
// Add organizer
|
||||
$vevent->add('ORGANIZER','mailto:' . $this->getProp($messageProps, "sender_email_address"));
|
||||
$vevent->ORGANIZER['CN'] = $this->getProp($messageProps, "sender_name");
|
||||
|
||||
// Add Attendees
|
||||
if(isset($messageProps["recipients"]) && count($messageProps["recipients"]["item"]) > 0) {
|
||||
foreach($messageProps["recipients"]["item"] as $attendee) {
|
||||
$att = $vevent->add('ATTENDEE', "mailto:" . $this->getProp($attendee, "email_address"));
|
||||
$att["CN"] = $this->getProp($attendee, "display_name");
|
||||
$att["ROLE"] = $this->attendeetype[intval($this->getProp($attendee, "recipient_type"))];
|
||||
}
|
||||
}
|
||||
|
||||
// Add alarms
|
||||
if(!empty($this->getProp($messageProps, "reminder")) && $this->getProp($messageProps, "reminder") == 1) {
|
||||
$valarm = $vevent->add('VALARM', [
|
||||
'ACTION' => 'DISPLAY',
|
||||
'DESCRIPTION' => $this->getProp($messageProps, "subject") // reuse the event summary
|
||||
]);
|
||||
|
||||
// Add trigger
|
||||
$durationValue = $this->getDurationStringFromMintues($this->getProp($messageProps, "reminder_minutes"), false);
|
||||
$valarm->add('TRIGGER', $durationValue); // default trigger type is duration (see 4.8.6.3)
|
||||
|
||||
/*
|
||||
$valarm->add('TRIGGER', date_timestamp_set(new DateTime(), $this->getProp($messageProps, "reminder_time"))); // trigger type "DATE-TIME"
|
||||
$valarm->TRIGGER['VALUE'] = 'DATE-TIME';
|
||||
*/
|
||||
}
|
||||
|
||||
// Add location
|
||||
if(!empty($this->getProp($messageProps, "location"))) {
|
||||
$vevent->add('LOCATION',$this->getProp($messageProps, "location"));
|
||||
}
|
||||
|
||||
// Add description
|
||||
$body = $this->getProp($messageProps, "isHTML") ? $this->getProp($messageProps, "html_body") : $this->getProp($messageProps, "body");
|
||||
if(!empty($body)) {
|
||||
$vevent->add('DESCRIPTION',$body);
|
||||
}
|
||||
}
|
||||
|
||||
// write combined ics file
|
||||
file_put_contents($file, file_get_contents($file) . $vcalendar->serialize());
|
||||
}
|
||||
|
||||
if (count($records) > 0) {
|
||||
$response['status'] = true;
|
||||
$response['fileid'] = $tmpname; // number of entries that will be exported
|
||||
$response['basedir'] = TMP_PATH;
|
||||
$response['secid'] = $secid;
|
||||
$response['realname'] = $actionData["calendar"];
|
||||
$response['download_token'] = $token;
|
||||
$response['filename'] = count($records) . "events.ics";
|
||||
} else {
|
||||
$response['status'] = false;
|
||||
$response['message'] = "No events found. Export skipped!";
|
||||
}
|
||||
|
||||
$this->addActionData($actionType, $response);
|
||||
$GLOBALS["bus"]->addData($this->getResponseData());
|
||||
|
||||
if($this->DEBUG) {
|
||||
error_log("export done, bus data written!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -395,40 +352,111 @@ class CalendarModule extends Module {
|
||||
* @param $actionType
|
||||
* @param $actionData
|
||||
*/
|
||||
private function importCalendar($actionType, $actionData) {
|
||||
if($this->DEBUG) {
|
||||
error_log("PHP Timezone: " . $tz);
|
||||
private function importCalendar($actionType, $actionData)
|
||||
{
|
||||
// Get uploaded vcf path
|
||||
$icsfile = false;
|
||||
if (isset($actionData["ics_filepath"])) {
|
||||
$icsfile = $actionData["ics_filepath"];
|
||||
}
|
||||
|
||||
if(is_readable ($actionData["ics_filepath"])) {
|
||||
$ical = new ICal($actionData["ics_filepath"], $GLOBALS["settings"]->get("zarafa/v1/plugins/calendarimporter/default_timezone"), $actionData["timezone"], $actionData["ignore_dst"]); // Parse it!
|
||||
// Get store id
|
||||
$storeid = false;
|
||||
if (isset($actionData["storeid"])) {
|
||||
$storeid = $actionData["storeid"];
|
||||
}
|
||||
|
||||
if(isset($ical->errors)) {
|
||||
$response['status'] = false;
|
||||
$response['message']= $ical->errors;
|
||||
} else if(!$ical->hasEvents()) {
|
||||
$response['status'] = false;
|
||||
$response['message']= "No events in ics file";
|
||||
} else {
|
||||
$response['status'] = true;
|
||||
$response['parsed_file']= $actionData["ics_filepath"];
|
||||
$response['parsed'] = array (
|
||||
'timezone' => $ical->timezone(),
|
||||
'calendar' => $ical->calendar(),
|
||||
'events' => $ical->events()
|
||||
// Get folder entryid
|
||||
$folderid = false;
|
||||
if (isset($actionData["folderid"])) {
|
||||
$folderid = $actionData["folderid"];
|
||||
}
|
||||
|
||||
// Get uids
|
||||
$uids = array();
|
||||
if (isset($actionData["uids"])) {
|
||||
$uids = $actionData["uids"];
|
||||
}
|
||||
|
||||
$response = array();
|
||||
$error = false;
|
||||
$error_msg = "";
|
||||
|
||||
// parse the ics file a last time...
|
||||
$parser = null;
|
||||
try {
|
||||
$parser = VObject\Reader::read(
|
||||
fopen($icsfile,'r')
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
$error = true;
|
||||
$error_msg = $e->getMessage();
|
||||
}
|
||||
|
||||
$events = array();
|
||||
if (count($parser->VEVENT) > 0) {
|
||||
$events = $this->parseCalendarToArray($parser);
|
||||
$store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid));
|
||||
$folder = mapi_msgstore_openentry($store, hex2bin($folderid));
|
||||
|
||||
$importall = false;
|
||||
if (count($uids) == count($events)) {
|
||||
$importall = true;
|
||||
}
|
||||
|
||||
$propValuesMAPI = array();
|
||||
$properties = $GLOBALS['properties']->getAppointmentProperties();
|
||||
// extend properties...
|
||||
$properties["body"] = PR_BODY;
|
||||
|
||||
$count = 0;
|
||||
|
||||
// iterate through all events and import them :)
|
||||
foreach ($events as $event) {
|
||||
if (isset($event["startdate"]) && ($importall || in_array($event["internal_fields"]["event_uid"], $uids))) {
|
||||
|
||||
$message = mapi_folder_createmessage($folder);
|
||||
|
||||
// parse the arraykeys
|
||||
foreach ($event as $key => $value) {
|
||||
if ($key !== "internal_fields") {
|
||||
if(isset($properties[$key])) {
|
||||
$propValuesMAPI[$properties[$key]] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$propValuesMAPI[$properties["commonstart"]] = $propValuesMAPI[$properties["startdate"]];
|
||||
$propValuesMAPI[$properties["commonend"]] = $propValuesMAPI[$properties["duedate"]];
|
||||
$propValuesMAPI[$properties["duration"]] = ($propValuesMAPI[$properties["duedate"]] - $propValuesMAPI[$properties["startdate"]]) / 60; // Minutes needed
|
||||
$propValuesMAPI[$properties["reminder"]] = false; // needed, overwritten if there is a timer
|
||||
|
||||
$propValuesMAPI[$properties["message_class"]] = "IPM.Appointment";
|
||||
$propValuesMAPI[$properties["icon_index"]] = "1024";
|
||||
|
||||
// TODO: set attendees and alarms
|
||||
|
||||
mapi_setprops($message, $propValuesMAPI);
|
||||
mapi_savechanges($message);
|
||||
if ($this->DEBUG) {
|
||||
error_log("New event added: \"" . $event["subject"] . "\".\n");
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
$response['status'] = true;
|
||||
$response['count'] = $count;
|
||||
$response['message'] = "";
|
||||
|
||||
} else {
|
||||
$response['status'] = false;
|
||||
$response['message']= "File could not be read by server";
|
||||
$response['count'] = 0;
|
||||
$response['message'] = $error ? $error_msg : "ICS file empty!";
|
||||
}
|
||||
|
||||
$this->addActionData($actionType, $response);
|
||||
$GLOBALS["bus"]->addData($this->getResponseData());
|
||||
|
||||
if($this->DEBUG) {
|
||||
error_log("parsing done, bus data written!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -437,7 +465,8 @@ class CalendarModule extends Module {
|
||||
* @param $actionData
|
||||
* @private
|
||||
*/
|
||||
private function getAttachmentPath($actionType, $actionData) {
|
||||
private function getAttachmentPath($actionType, $actionData)
|
||||
{
|
||||
// Get store id
|
||||
$storeid = false;
|
||||
if (isset($actionData["store"])) {
|
||||
@ -474,8 +503,7 @@ class CalendarModule extends Module {
|
||||
// Check if attachNum isset
|
||||
if ($attachNum) {
|
||||
// Loop through the attachNums, message in message in message ...
|
||||
for($i = 0; $i < (count($attachNum) - 1); $i++)
|
||||
{
|
||||
for ($i = 0; $i < (count($attachNum) - 1); $i++) {
|
||||
// Open the attachment
|
||||
$tempattach = mapi_message_openattach($message, (int)$attachNum[$i]);
|
||||
if ($tempattach) {
|
||||
@ -501,11 +529,15 @@ class CalendarModule extends Module {
|
||||
// Set filename
|
||||
if (isset($props[PR_ATTACH_LONG_FILENAME])) {
|
||||
$filename = $props[PR_ATTACH_LONG_FILENAME];
|
||||
} else if(isset($props[PR_ATTACH_FILENAME])) {
|
||||
} else {
|
||||
if (isset($props[PR_ATTACH_FILENAME])) {
|
||||
$filename = $props[PR_ATTACH_FILENAME];
|
||||
} else if(isset($props[PR_DISPLAY_NAME])) {
|
||||
} else {
|
||||
if (isset($props[PR_DISPLAY_NAME])) {
|
||||
$filename = $props[PR_DISPLAY_NAME];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set content type
|
||||
if (isset($props[PR_ATTACH_MIME_TAG])) {
|
||||
@ -569,6 +601,129 @@ class CalendarModule extends Module {
|
||||
$GLOBALS["bus"]->addData($this->getResponseData());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function that parses the uploaded ics file and posts it via json
|
||||
* @param $actionType
|
||||
* @param $actionData
|
||||
*/
|
||||
private function loadCalendar($actionType, $actionData)
|
||||
{
|
||||
$error = false;
|
||||
$error_msg = "";
|
||||
|
||||
if (is_readable($actionData["ics_filepath"])) {
|
||||
$parser = null;
|
||||
|
||||
try {
|
||||
$parser = VObject\Reader::read(
|
||||
fopen($actionData["ics_filepath"],'r')
|
||||
);
|
||||
//error_log(print_r($parser->VTIMEZONE, true));
|
||||
} catch (Exception $e) {
|
||||
$error = true;
|
||||
$error_msg = $e->getMessage();
|
||||
}
|
||||
if ($error) {
|
||||
$response['status'] = false;
|
||||
$response['message'] = $error_msg;
|
||||
} else {
|
||||
if (count($parser->VEVENT) == 0) {
|
||||
$response['status'] = false;
|
||||
$response['message'] = "No event in ics file";
|
||||
} else {
|
||||
$response['status'] = true;
|
||||
$response['parsed_file'] = $actionData["ics_filepath"];
|
||||
$response['parsed'] = array(
|
||||
'events' => $this->parseCalendarToArray($parser),
|
||||
'timezone' => isset($parser->VTIMEZONE->TZID) ? (string)$parser->VTIMEZONE->TZID : (string)$parser->{'X-WR-TIMEZONE'},
|
||||
'calendar' => (string)$parser->PRODID
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$response['status'] = false;
|
||||
$response['message'] = "File could not be read by server";
|
||||
}
|
||||
|
||||
$this->addActionData($actionType, $response);
|
||||
$GLOBALS["bus"]->addData($this->getResponseData());
|
||||
|
||||
if ($this->DEBUG) {
|
||||
error_log("parsing done, bus data written!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a array with contacts
|
||||
*
|
||||
* @param {VObject} $calendar ics parser object
|
||||
* @return array parsed events
|
||||
* @private
|
||||
*/
|
||||
private function parseCalendarToArray($calendar)
|
||||
{
|
||||
$events = array();
|
||||
foreach ($calendar->VEVENT as $Index => $vEvent) {
|
||||
// Sabre\VObject\Parser\XML\Element\VEvent
|
||||
$properties = array();
|
||||
|
||||
//uid - used for front/backend communication
|
||||
$properties["internal_fields"] = array();
|
||||
$properties["internal_fields"]["event_uid"] = base64_encode($Index . $vEvent->UID);
|
||||
|
||||
$properties["startdate"] = (string)$vEvent->DTSTART->getDateTime()->getTimestamp();
|
||||
$properties["duedate"] = (string)$vEvent->DTEND->getDateTime()->getTimestamp();
|
||||
$properties["location"] = (string)$vEvent->LOCATION;
|
||||
$properties["subject"] = (string)$vEvent->SUMMARY;
|
||||
$properties["body"] = (string)$vEvent->DESCRIPTION;
|
||||
$properties["comment"] = (string)$vEvent->COMMENT;
|
||||
$properties["timezone"] = (string)$vEvent->DTSTART["TZID"];
|
||||
$properties["organizer"] = (string)$vEvent->ORGANIZER;
|
||||
$properties["busystatus"] = array_search((string)$vEvent->{'X-MICROSOFT-CDO-INTENDEDSTATUS'}, $this->busystates); // X-MICROSOFT-CDO-BUSYSTATUS
|
||||
$properties["transp"] = (string)$vEvent->TRANSP;
|
||||
//$properties["trigger"] = (string)$vEvent->COMMENT;
|
||||
$properties["priority"] = (string)$vEvent->PRIORITY;
|
||||
$properties["private"] = ((string)$vEvent->CLASS) == "PRIVATE" ? true : false;
|
||||
if(!empty((string)$vEvent->{'X-ZARAFA-LABEL'})) {
|
||||
$properties["label"] = array_search((string)$vEvent->{'X-ZARAFA-LABEL'}, $this->labels);
|
||||
}
|
||||
$properties["last_modification_time"] = (string)$vEvent->{'LAST-MODIFIED'}->getDateTime()->getTimestamp();
|
||||
$properties["creation_time"] = (string)$vEvent->CREATED->getDateTime()->getTimestamp();
|
||||
$properties["rrule"] = (string)$vEvent->RRULE;
|
||||
|
||||
// Attendees
|
||||
$properties["attendees"] = array();
|
||||
if(isset($vEvent->ATTENDEE) && count($vEvent->ATTENDEE) > 0) {
|
||||
foreach($vEvent->ATTENDEE as $attendee) {
|
||||
$properties["attendees"][] = array(
|
||||
"name" => (string)$attendee["CN"],
|
||||
"mail" => (string)$attendee,
|
||||
"status" => (string)$attendee["PARTSTAT"],
|
||||
"role" => (string)$attendee["ROLE"]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Alarms
|
||||
$properties["alarms"] = array();
|
||||
if(isset($vEvent->VALARM) && count($vEvent->VALARM) > 0) {
|
||||
foreach($vEvent->VALARM as $alarm) {
|
||||
$properties["alarms"][] = array(
|
||||
"description" => (string)$alarm->DESCRIPTION,
|
||||
"trigger" => (string)$alarm->TRIGGER,
|
||||
"type" => (string)$alarm->TRIGGER["VALUE"]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
array_push($events, $properties);
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
?>
|
||||
|
@ -19,25 +19,31 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*
|
||||
*/
|
||||
require_once __DIR__ . "/download.php";
|
||||
|
||||
/**
|
||||
* calendarimporter Plugin
|
||||
*
|
||||
* With this plugin you can import a ics file to your zarafa calendar
|
||||
*
|
||||
*/
|
||||
class Plugincalendarimporter extends Plugin {
|
||||
class Plugincalendarimporter extends Plugin
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
function Plugincalendarimporter() {}
|
||||
function __construct() {}
|
||||
|
||||
/**
|
||||
* Function initializes the Plugin and registers all hooks
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function init() {
|
||||
function init()
|
||||
{
|
||||
$this->registerHook('server.core.settings.init.before');
|
||||
$this->registerHook('server.index.load.custom');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -47,11 +53,17 @@ class Plugincalendarimporter extends Plugin {
|
||||
* @param mixed $data object(s) related to the hook
|
||||
* @return void
|
||||
*/
|
||||
function execute($eventID, &$data) {
|
||||
function execute($eventID, &$data)
|
||||
{
|
||||
switch ($eventID) {
|
||||
case 'server.core.settings.init.before' :
|
||||
$this->injectPluginSettings($data);
|
||||
break;
|
||||
case 'server.index.load.custom':
|
||||
if ($data['name'] == 'download_ics') {
|
||||
calendarimporter\DownloadHandler::doDownload();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,14 +72,14 @@ class Plugincalendarimporter extends Plugin {
|
||||
* settings.
|
||||
* @param Array $data Reference to the data of the triggered hook
|
||||
*/
|
||||
function injectPluginSettings(&$data) {
|
||||
function injectPluginSettings(&$data)
|
||||
{
|
||||
$data['settingsObj']->addSysAdminDefaults(Array(
|
||||
'zarafa' => Array(
|
||||
'v1' => Array(
|
||||
'plugins' => Array(
|
||||
'calendarimporter' => Array(
|
||||
'enable' => PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE,
|
||||
'enable_export' => PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE_EXPORT,
|
||||
'enable_sync' => PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE_SYNC,
|
||||
'default_calendar' => PLUGIN_CALENDARIMPORTER_DEFAULT,
|
||||
'default_timezone' => PLUGIN_CALENDARIMPORTER_DEFAULT_TIMEZONE
|
||||
@ -78,4 +90,5 @@ class Plugincalendarimporter extends Plugin {
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -2,5 +2,29 @@
|
||||
background: url(../images/import_icon.png) no-repeat !important;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 18px!important;
|
||||
}
|
||||
|
||||
.icon_calendarimporter_export {
|
||||
background: url(../images/download.png) no-repeat;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.icon_calendarimporter_import {
|
||||
background: url(../images/upload.png) no-repeat;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.zarafa-caiplg-container {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.zarafa-caiplg-button .x-btn-small {
|
||||
width: 80%;
|
||||
height: 30px;
|
||||
margin-left: 10%;
|
||||
margin-right: 10%;
|
||||
margin-top: 10px;
|
||||
}
|
BIN
resources/images/download.png
Executable file
BIN
resources/images/download.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 224 B |
BIN
resources/images/download.xcf
Executable file
BIN
resources/images/download.xcf
Executable file
Binary file not shown.
BIN
resources/images/upload.png
Normal file
BIN
resources/images/upload.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 213 B |
BIN
resources/images/upload.xcf
Executable file
BIN
resources/images/upload.xcf
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user