Merge branch 'tine20.com/2012.10' into 2013.03
authorPhilipp Schüle <p.schuele@metaways.de>
Thu, 23 May 2013 15:26:36 +0000 (17:26 +0200)
committerPhilipp Schüle <p.schuele@metaways.de>
Thu, 23 May 2013 15:26:36 +0000 (17:26 +0200)
1032 files changed:
scripts/packaging/Univention/debian/changelog
scripts/packaging/build-tine20-packages.sh
scripts/packaging/debian/changelog
scripts/packaging/debian/control
scripts/packaging/fedora/SPECS/tine20.spec
tests/js_client/checklists/tests_js_client_2013.03.1.ods [new file with mode: 0644]
tests/setup/Setup/Backend/OracleTest.php
tests/setup/Setup/ControllerTest.php
tests/tine20/ActiveSync/Controller/EmailTests.php
tests/tine20/Addressbook/Backend/LdapTest.php
tests/tine20/Addressbook/JsonTest.php
tests/tine20/Admin/JsonTest.php
tests/tine20/Calendar/Controller/EventGrantsTests.php
tests/tine20/Calendar/Controller/EventNotificationsTests.php
tests/tine20/Calendar/Controller/EventTests.php
tests/tine20/Calendar/Controller/MSEventFacadeTest.php
tests/tine20/Calendar/Controller/RecurTest.php
tests/tine20/Calendar/Convert/Event/VCalendar/GenericTest.php
tests/tine20/Calendar/Convert/Event/VCalendar/ThunderbirdTest.php
tests/tine20/Calendar/Frontend/WebDAV/EventTest.php
tests/tine20/Calendar/Import/ICalTest.php
tests/tine20/Calendar/Import/files/lightning_snooze.ics [new file with mode: 0644]
tests/tine20/Calendar/JsonTests.php
tests/tine20/Calendar/Setup/DemoDataTests.php
tests/tine20/Calendar/TestCase.php
tests/tine20/Courses/JsonTest.php
tests/tine20/Crm/Export/CsvTest.php
tests/tine20/Crm/JsonTest.php
tests/tine20/Felamimail/AllTests.php
tests/tine20/Felamimail/Controller/AccountTest.php
tests/tine20/Felamimail/Controller/MessageTest.php
tests/tine20/Felamimail/JsonTest.php
tests/tine20/Felamimail/Model/AccountTest.php
tests/tine20/Felamimail/Model/MessageTest.php
tests/tine20/Felamimail/files/facebook_notification.eml [new file with mode: 0644]
tests/tine20/Felamimail/files/text_html_urls.eml [new file with mode: 0644]
tests/tine20/Filemanager/AllTests.php
tests/tine20/Filemanager/Frontend/AllTests.php
tests/tine20/Filemanager/Frontend/JsonTests.php
tests/tine20/HumanResources/CliTests.php
tests/tine20/HumanResources/JsonTests.php
tests/tine20/HumanResources/TestCase.php
tests/tine20/Inventory/AllTests.php
tests/tine20/Inventory/Import/AllTests.php [new file with mode: 0644]
tests/tine20/Inventory/Import/CsvTest.php [new file with mode: 0644]
tests/tine20/Inventory/Import/files/inv_tine_import.csv [new file with mode: 0644]
tests/tine20/Inventory/Import/files/inv_tine_import_csv.xml [new file with mode: 0644]
tests/tine20/Inventory/Import/files/inv_tine_import_csv_nohook.xml [new file with mode: 0644]
tests/tine20/Inventory/Import/files/inv_tine_import_datetimes.csv [new file with mode: 0644]
tests/tine20/Inventory/Import/files/testScript.php [new file with mode: 0755]
tests/tine20/Phone/ControllerTest.php
tests/tine20/Sales/JsonTest.php
tests/tine20/Tasks/ControllerTest.php
tests/tine20/Tasks/JsonTest.php
tests/tine20/TestServer.php
tests/tine20/Timetracker/JsonTest.php
tests/tine20/Tinebase/AllTests.php
tests/tine20/Tinebase/ApplicationTest.php
tests/tine20/Tinebase/AuthTest.php
tests/tine20/Tinebase/ContainerTest.php
tests/tine20/Tinebase/ControllerTest.php
tests/tine20/Tinebase/CustomFieldTest.php
tests/tine20/Tinebase/DateTimeTest.php
tests/tine20/Tinebase/FileSystem/StreamWrapperTest.php
tests/tine20/Tinebase/FileSystemTest.php
tests/tine20/Tinebase/Frontend/CliTest.php
tests/tine20/Tinebase/Frontend/DemoDataCliTest.php [new file with mode: 0644]
tests/tine20/Tinebase/Frontend/Json/PersistentFilterTest.php
tests/tine20/Tinebase/Frontend/JsonTest.php
tests/tine20/Tinebase/GroupTest.php
tests/tine20/Tinebase/NotificationTest.php
tests/tine20/Tinebase/Record/RecordSetTest.php
tests/tine20/Tinebase/Record/RecordTest.php
tests/tine20/Tinebase/TagsTest.php
tests/tine20/Tinebase/TempFileTest.php [new file with mode: 0644]
tests/tine20/Tinebase/Timemachine/ModificationLogTest.php
tests/tine20/Tinebase/User/EmailUser/Imap/CyrusTest.php
tests/tine20/Tinebase/User/EmailUser/Imap/DbmailTest.php
tests/tine20/Tinebase/User/EmailUser/Imap/DovecotTest.php
tests/tine20/Tinebase/User/EmailUser/Imap/LdapDbmailSchemaTest.php
tests/tine20/Tinebase/User/EmailUser/Smtp/LdapDbmailSchemaTest.php
tests/tine20/Tinebase/User/EmailUser/Smtp/PostfixTest.php
tests/tine20/Tinebase/UserTest.php
tests/tine20/Tinebase/files/brokenname.txt [new file with mode: 0644]
tests/tine20/Voipmanager/JsonTest.php
tine20/ActiveSync/Config.php
tine20/ActiveSync/Setup/Update/Release5.php
tine20/ActiveSync/Setup/Update/Release6.php
tine20/ActiveSync/Setup/Update/Release7.php [new file with mode: 0644]
tine20/ActiveSync/Setup/setup.xml
tine20/ActiveSync/js/Model.js
tine20/ActiveSync/translations/cs.po
tine20/ActiveSync/translations/da.po
tine20/ActiveSync/translations/de.po
tine20/ActiveSync/translations/es.po
tine20/ActiveSync/translations/es_MX.po
tine20/ActiveSync/translations/et.po
tine20/ActiveSync/translations/fa_IR.po
tine20/ActiveSync/translations/fi.po
tine20/ActiveSync/translations/fr.po
tine20/ActiveSync/translations/hr_HR.po
tine20/ActiveSync/translations/hu.po
tine20/ActiveSync/translations/it.po
tine20/ActiveSync/translations/ko_KR.po [new file with mode: 0644]
tine20/ActiveSync/translations/lt.po
tine20/ActiveSync/translations/nl_NL.po
tine20/ActiveSync/translations/pl.po
tine20/ActiveSync/translations/pt_BR.po
tine20/ActiveSync/translations/ru.po
tine20/ActiveSync/translations/sk.po
tine20/ActiveSync/translations/sv_SE.po
tine20/ActiveSync/translations/template.pot
tine20/ActiveSync/translations/tr_TR.po
tine20/ActiveSync/translations/vi.po
tine20/ActiveSync/translations/zh_CN.po
tine20/ActiveSync/translations/zh_TW.po
tine20/Addressbook/Acl/Rights.php
tine20/Addressbook/Controller/Contact.php
tine20/Addressbook/Convert/Contact/VCard/Abstract.php
tine20/Addressbook/Convert/Contact/VCard/Sogo.php
tine20/Addressbook/Model/Contact.php
tine20/Addressbook/Model/ListHiddenFilter.php
tine20/Addressbook/Setup/DemoData.php [new file with mode: 0644]
tine20/Addressbook/Setup/DemoData/base64images.txt [new file with mode: 0644]
tine20/Addressbook/Setup/DemoData/out1000.csv [new file with mode: 0644]
tine20/Addressbook/Setup/Initialize.php
tine20/Addressbook/Setup/Update/Release5.php
tine20/Addressbook/Setup/Update/Release6.php
tine20/Addressbook/Setup/Update/Release7.php [new file with mode: 0644]
tine20/Addressbook/Setup/setup.xml
tine20/Addressbook/css/Addressbook.css
tine20/Addressbook/js/ContactEditDialog.js
tine20/Addressbook/js/ContactGrid.js
tine20/Addressbook/js/Model.js
tine20/Addressbook/js/SearchCombo.js
tine20/Addressbook/translations/bg.po
tine20/Addressbook/translations/ca.po
tine20/Addressbook/translations/cs.po
tine20/Addressbook/translations/da.po
tine20/Addressbook/translations/de.po
tine20/Addressbook/translations/es.po
tine20/Addressbook/translations/es_MX.po
tine20/Addressbook/translations/et.po
tine20/Addressbook/translations/fa_IR.po
tine20/Addressbook/translations/fi.po
tine20/Addressbook/translations/fr.po
tine20/Addressbook/translations/hr_HR.po
tine20/Addressbook/translations/hu.po
tine20/Addressbook/translations/it.po
tine20/Addressbook/translations/ja.po
tine20/Addressbook/translations/ko_KR.po [new file with mode: 0644]
tine20/Addressbook/translations/lt.po
tine20/Addressbook/translations/nb.po
tine20/Addressbook/translations/nl_NL.po
tine20/Addressbook/translations/pl.po
tine20/Addressbook/translations/pt_BR.po
tine20/Addressbook/translations/ru.po
tine20/Addressbook/translations/sk.po
tine20/Addressbook/translations/sv_SE.po
tine20/Addressbook/translations/template.pot
tine20/Addressbook/translations/tr_TR.po
tine20/Addressbook/translations/vi.po
tine20/Addressbook/translations/zh_CN.po
tine20/Addressbook/translations/zh_TW.po
tine20/Admin/Controller.php
tine20/Admin/Controller/Customfield.php
tine20/Admin/Controller/Tags.php
tine20/Admin/Frontend/Json.php
tine20/Admin/Setup/DemoData.php
tine20/Admin/Setup/DemoData/COPYRIGHT [new file with mode: 0644]
tine20/Admin/Setup/DemoData/persona_jmcblack.jpg [new file with mode: 0644]
tine20/Admin/Setup/DemoData/persona_jsmith.jpg [new file with mode: 0644]
tine20/Admin/Setup/DemoData/persona_pwulf.jpg [new file with mode: 0644]
tine20/Admin/Setup/DemoData/persona_sclever.jpg [new file with mode: 0644]
tine20/Admin/Setup/Update/Release6.php [new file with mode: 0644]
tine20/Admin/Setup/setup.xml
tine20/Admin/js/Admin.js
tine20/Admin/js/Groups.js
tine20/Admin/js/Models.js
tine20/Admin/js/Roles.js
tine20/Admin/js/TagEditDialog.js
tine20/Admin/translations/bg.po
tine20/Admin/translations/ca.po
tine20/Admin/translations/cs.po
tine20/Admin/translations/da.po
tine20/Admin/translations/de.po
tine20/Admin/translations/es.po
tine20/Admin/translations/es_MX.po
tine20/Admin/translations/et.po
tine20/Admin/translations/fa_IR.po
tine20/Admin/translations/fi.po
tine20/Admin/translations/fr.po
tine20/Admin/translations/hr_HR.po
tine20/Admin/translations/hu.po
tine20/Admin/translations/it.po
tine20/Admin/translations/ja.po
tine20/Admin/translations/ko_KR.po [new file with mode: 0644]
tine20/Admin/translations/lt.po
tine20/Admin/translations/nb.po
tine20/Admin/translations/nl_NL.po
tine20/Admin/translations/pl.po
tine20/Admin/translations/pt_BR.po
tine20/Admin/translations/ru.po
tine20/Admin/translations/sk.po
tine20/Admin/translations/sv_SE.po
tine20/Admin/translations/template.pot
tine20/Admin/translations/tr_TR.po
tine20/Admin/translations/vi.po
tine20/Admin/translations/zh_CN.po
tine20/Admin/translations/zh_TW.po
tine20/Calendar/Acl/Rights.php
tine20/Calendar/Backend/Sql.php
tine20/Calendar/Backend/Sql/Attendee.php
tine20/Calendar/Calendar.jsb2
tine20/Calendar/Controller.php
tine20/Calendar/Controller/Alarm.php
tine20/Calendar/Controller/Event.php
tine20/Calendar/Controller/EventNotifications.php
tine20/Calendar/Controller/MSEventFacade.php
tine20/Calendar/Controller/Resource.php
tine20/Calendar/Convert/Event/Json.php
tine20/Calendar/Convert/Event/VCalendar/Abstract.php
tine20/Calendar/Convert/Resource/Json.php [new file with mode: 0644]
tine20/Calendar/Exception/IcalParser.php
tine20/Calendar/Frontend/Json.php
tine20/Calendar/Frontend/WebDAV/Event.php
tine20/Calendar/Import/Ical.php
tine20/Calendar/Model/Attender.php
tine20/Calendar/Model/AttenderFilter.php
tine20/Calendar/Model/Event.php
tine20/Calendar/Model/GrantFilter.php
tine20/Calendar/Model/PeriodFilter.php
tine20/Calendar/Model/Resource.php
tine20/Calendar/Model/ResourceFilter.php
tine20/Calendar/Model/Rrule.php
tine20/Calendar/Setup/DemoData.php
tine20/Calendar/Setup/Update/Release6.php
tine20/Calendar/Setup/Update/Release7.php [new file with mode: 0644]
tine20/Calendar/Setup/setup.xml
tine20/Calendar/css/Calendar.css
tine20/Calendar/js/AttendeeFilterGrid.js [new file with mode: 0644]
tine20/Calendar/js/AttendeeFilterModel.js
tine20/Calendar/js/AttendeeGridPanel.js
tine20/Calendar/js/CalendarPanel.js
tine20/Calendar/js/DaysView.js
tine20/Calendar/js/EventUI.js
tine20/Calendar/js/MainScreenCenterPanel.js
tine20/Calendar/js/Model.js
tine20/Calendar/js/MonthView.js
tine20/Calendar/js/Printer/Base.js
tine20/Calendar/js/Printer/DaysView.js
tine20/Calendar/js/Printer/MonthView.js
tine20/Calendar/js/ResourceEditDialog.js
tine20/Calendar/js/WestPanel.js
tine20/Calendar/translations/bg.po
tine20/Calendar/translations/ca.po
tine20/Calendar/translations/cs.po
tine20/Calendar/translations/da.po
tine20/Calendar/translations/de.po
tine20/Calendar/translations/es.po
tine20/Calendar/translations/es_MX.po
tine20/Calendar/translations/et.po
tine20/Calendar/translations/fa_IR.po
tine20/Calendar/translations/fi.po
tine20/Calendar/translations/fr.po
tine20/Calendar/translations/hr_HR.po
tine20/Calendar/translations/hu.po
tine20/Calendar/translations/it.po
tine20/Calendar/translations/ja.po
tine20/Calendar/translations/ko_KR.po [new file with mode: 0644]
tine20/Calendar/translations/lt.po
tine20/Calendar/translations/nb.po
tine20/Calendar/translations/nl_NL.po
tine20/Calendar/translations/pl.po
tine20/Calendar/translations/pt_BR.po
tine20/Calendar/translations/ru.po
tine20/Calendar/translations/sk.po
tine20/Calendar/translations/sv_SE.po
tine20/Calendar/translations/template.pot
tine20/Calendar/translations/tr_TR.po
tine20/Calendar/translations/vi.po
tine20/Calendar/translations/zh_CN.po
tine20/Calendar/translations/zh_TW.po
tine20/Courses/Model/Course.php
tine20/Courses/Setup/Update/Release6.php
tine20/Courses/Setup/Update/Release7.php [new file with mode: 0644]
tine20/Courses/Setup/setup.xml
tine20/Courses/translations/de.po
tine20/Courses/translations/es_MX.po
tine20/Courses/translations/et.po
tine20/Courses/translations/fi.po
tine20/Courses/translations/hr_HR.po
tine20/Courses/translations/hu.po
tine20/Courses/translations/it.po
tine20/Courses/translations/ko_KR.po [new file with mode: 0644]
tine20/Courses/translations/nb.po
tine20/Courses/translations/pl.po
tine20/Courses/translations/ru.po
tine20/Courses/translations/sv_SE.po
tine20/Courses/translations/tr_TR.po
tine20/Courses/translations/vi.po
tine20/Courses/translations/zh_TW.po
tine20/Crm/Acl/Rights.php
tine20/Crm/Config.php
tine20/Crm/Controller.php
tine20/Crm/Controller/Lead.php
tine20/Crm/Frontend/Cli.php [new file with mode: 0644]
tine20/Crm/Model/Config.php
tine20/Crm/Model/Lead.php
tine20/Crm/Setup/DemoData.php [new file with mode: 0644]
tine20/Crm/Setup/Update/Release2.php
tine20/Crm/Setup/Update/Release6.php
tine20/Crm/Setup/Update/Release7.php [new file with mode: 0644]
tine20/Crm/Setup/setup.xml
tine20/Crm/js/Model.js
tine20/Crm/translations/bg.po
tine20/Crm/translations/ca.po
tine20/Crm/translations/cs.po
tine20/Crm/translations/da.po
tine20/Crm/translations/de.po
tine20/Crm/translations/es.po
tine20/Crm/translations/es_MX.po
tine20/Crm/translations/et.po
tine20/Crm/translations/fa_IR.po
tine20/Crm/translations/fi.po
tine20/Crm/translations/fr.po
tine20/Crm/translations/hr_HR.po
tine20/Crm/translations/hu.po
tine20/Crm/translations/it.po
tine20/Crm/translations/ja.po
tine20/Crm/translations/ko_KR.po [new file with mode: 0644]
tine20/Crm/translations/lt.po
tine20/Crm/translations/nb.po
tine20/Crm/translations/nl_NL.po
tine20/Crm/translations/pl.po
tine20/Crm/translations/pt_BR.po
tine20/Crm/translations/ru.po
tine20/Crm/translations/sk.po
tine20/Crm/translations/sv_SE.po
tine20/Crm/translations/template.pot
tine20/Crm/translations/tr_TR.po
tine20/Crm/translations/vi.po
tine20/Crm/translations/zh_CN.po
tine20/Crm/translations/zh_TW.po
tine20/ExampleApplication/Setup/setup.xml
tine20/Felamimail/Backend/Cache/Sql/Message.php
tine20/Felamimail/Backend/Folder.php
tine20/Felamimail/Controller/Account.php
tine20/Felamimail/Controller/Message.php
tine20/Felamimail/Controller/Message/Send.php
tine20/Felamimail/Controller/Sieve.php
tine20/Felamimail/Frontend/Json.php
tine20/Felamimail/HTMLPurifier/URIFilter/TransformURI.php [new file with mode: 0644]
tine20/Felamimail/Model/Account.php
tine20/Felamimail/Model/Message.php
tine20/Felamimail/Model/MessageFilter.php
tine20/Felamimail/Model/Sieve/Vacation.php
tine20/Felamimail/Preference.php
tine20/Felamimail/Setup/Update/Release3.php
tine20/Felamimail/Setup/Update/Release6.php
tine20/Felamimail/Setup/Update/Release7.php [new file with mode: 0644]
tine20/Felamimail/Setup/setup.xml
tine20/Felamimail/Sieve/Backend/Sql.php
tine20/Felamimail/Transport.php
tine20/Felamimail/css/Felamimail.css
tine20/Felamimail/js/ContactGrid.js
tine20/Felamimail/js/Felamimail.js
tine20/Felamimail/js/GridPanel.js
tine20/Felamimail/js/MessageDisplayDialog.js
tine20/Felamimail/js/MessageEditDialog.js
tine20/Felamimail/js/Model.js
tine20/Felamimail/js/RecipientGrid.js
tine20/Felamimail/js/sieve/RulesGridPanel.js
tine20/Felamimail/translations/bg.po
tine20/Felamimail/translations/ca.po
tine20/Felamimail/translations/cs.po
tine20/Felamimail/translations/da.po
tine20/Felamimail/translations/de.po
tine20/Felamimail/translations/es.po
tine20/Felamimail/translations/es_MX.po
tine20/Felamimail/translations/et.po
tine20/Felamimail/translations/fa_IR.po
tine20/Felamimail/translations/fi.po
tine20/Felamimail/translations/fr.po
tine20/Felamimail/translations/hr_HR.po
tine20/Felamimail/translations/hu.po
tine20/Felamimail/translations/it.po
tine20/Felamimail/translations/ko_KR.po [new file with mode: 0644]
tine20/Felamimail/translations/lt.po
tine20/Felamimail/translations/nb.po
tine20/Felamimail/translations/nl_NL.po
tine20/Felamimail/translations/pl.po
tine20/Felamimail/translations/pt_BR.po
tine20/Felamimail/translations/ru.po
tine20/Felamimail/translations/sk.po
tine20/Felamimail/translations/sv_SE.po
tine20/Felamimail/translations/template.pot
tine20/Felamimail/translations/tr_TR.po
tine20/Felamimail/translations/vi.po
tine20/Felamimail/translations/zh_CN.po
tine20/Felamimail/translations/zh_TW.po
tine20/Filemanager/Controller/Node.php
tine20/Filemanager/Setup/Update/Release6.php
tine20/Filemanager/Setup/Update/Release7.php [new file with mode: 0644]
tine20/Filemanager/Setup/setup.xml
tine20/Filemanager/js/Model.js
tine20/Filemanager/js/NodeEditDialog.js
tine20/Filemanager/translations/cs.po
tine20/Filemanager/translations/da.po
tine20/Filemanager/translations/de.po
tine20/Filemanager/translations/es.po
tine20/Filemanager/translations/es_MX.po
tine20/Filemanager/translations/et.po
tine20/Filemanager/translations/fa_IR.po
tine20/Filemanager/translations/fi.po
tine20/Filemanager/translations/fr.po
tine20/Filemanager/translations/hr_HR.po
tine20/Filemanager/translations/hu.po
tine20/Filemanager/translations/it.po
tine20/Filemanager/translations/ko_KR.po [new file with mode: 0644]
tine20/Filemanager/translations/lt.po
tine20/Filemanager/translations/nl_NL.po
tine20/Filemanager/translations/pl.po
tine20/Filemanager/translations/pt_BR.po
tine20/Filemanager/translations/ru.po
tine20/Filemanager/translations/sk.po
tine20/Filemanager/translations/sv_SE.po
tine20/Filemanager/translations/template.pot
tine20/Filemanager/translations/tr_TR.po
tine20/Filemanager/translations/vi.po
tine20/Filemanager/translations/zh_CN.po
tine20/Filemanager/translations/zh_TW.po
tine20/HumanResources/Backend/CostCenter.php [new file with mode: 0644]
tine20/HumanResources/Config.php
tine20/HumanResources/Controller/Contract.php
tine20/HumanResources/Controller/CostCenter.php [new file with mode: 0644]
tine20/HumanResources/Controller/Employee.php
tine20/HumanResources/Controller/WorkingTime.php
tine20/HumanResources/Frontend/Cli.php
tine20/HumanResources/Frontend/Json.php
tine20/HumanResources/HumanResources.jsb2
tine20/HumanResources/Model/Contract.php
tine20/HumanResources/Model/CostCenter.php [new file with mode: 0644]
tine20/HumanResources/Model/CostCenterFilter.php [new file with mode: 0644]
tine20/HumanResources/Model/Employee.php
tine20/HumanResources/Model/EmployeeEmployedFilter.php [new file with mode: 0644]
tine20/HumanResources/Model/EmployeeFilter.php
tine20/HumanResources/Model/FreeTime.php
tine20/HumanResources/Model/WorkingTime.php
tine20/HumanResources/Model/WorkingTimeFilter.php
tine20/HumanResources/Setup/DemoData.php [new file with mode: 0644]
tine20/HumanResources/Setup/Initialize.php
tine20/HumanResources/Setup/Update/Release6.php
tine20/HumanResources/Setup/Update/Release7.php [new file with mode: 0644]
tine20/HumanResources/Setup/setup.xml
tine20/HumanResources/css/HumanResources.css
tine20/HumanResources/js/ContractGridPanel.js
tine20/HumanResources/js/CostCenterGridPanel.js [new file with mode: 0644]
tine20/HumanResources/js/DatePicker.js
tine20/HumanResources/js/EmployeeEditDialog.js
tine20/HumanResources/js/FreeTimeEditDialog.js
tine20/HumanResources/js/FreeTimeGridPanel.js
tine20/HumanResources/js/Models.js
tine20/HumanResources/js/WorkingTimeEditDialog.js [new file with mode: 0644]
tine20/HumanResources/translations/bg.po
tine20/HumanResources/translations/ca.po
tine20/HumanResources/translations/cs.po
tine20/HumanResources/translations/da.po
tine20/HumanResources/translations/de.po
tine20/HumanResources/translations/en.po
tine20/HumanResources/translations/es.po
tine20/HumanResources/translations/es_MX.po
tine20/HumanResources/translations/et.po
tine20/HumanResources/translations/fa_IR.po
tine20/HumanResources/translations/fi.po
tine20/HumanResources/translations/fr.po
tine20/HumanResources/translations/hr_HR.po
tine20/HumanResources/translations/hu.po
tine20/HumanResources/translations/it.po
tine20/HumanResources/translations/ja.po
tine20/HumanResources/translations/ko_KR.po [new file with mode: 0644]
tine20/HumanResources/translations/lt.po
tine20/HumanResources/translations/nb.po
tine20/HumanResources/translations/nl_NL.po
tine20/HumanResources/translations/pl.po
tine20/HumanResources/translations/pt_BR.po
tine20/HumanResources/translations/ru.po
tine20/HumanResources/translations/sk.po
tine20/HumanResources/translations/sv_SE.po
tine20/HumanResources/translations/template.pot
tine20/HumanResources/translations/tr_TR.po
tine20/HumanResources/translations/vi.po
tine20/HumanResources/translations/zh_CN.po
tine20/HumanResources/translations/zh_TW.po
tine20/Inventory/Controller.php
tine20/Inventory/Controller/InventoryItem.php
tine20/Inventory/Export/Csv.php [new file with mode: 0644]
tine20/Inventory/Export/Ods.php [new file with mode: 0644]
tine20/Inventory/Export/Xls.php [new file with mode: 0644]
tine20/Inventory/Export/definitions/i_default_ods.xml [new file with mode: 0644]
tine20/Inventory/Export/definitions/i_default_xls.xml [new file with mode: 0644]
tine20/Inventory/Frontend/Cli.php [new file with mode: 0755]
tine20/Inventory/Frontend/Http.php [new file with mode: 0755]
tine20/Inventory/Frontend/Json.php
tine20/Inventory/Import/Csv.php [new file with mode: 0644]
tine20/Inventory/Import/definitions/inv_tine_import_csv.xml [new file with mode: 0644]
tine20/Inventory/Import/examples/inv_tine_import.csv [new file with mode: 0644]
tine20/Inventory/Model/InventoryItem.php
tine20/Inventory/Model/InventoryItemFilter.php
tine20/Inventory/Setup/Initialize.php
tine20/Inventory/Setup/Update/Release6.php
tine20/Inventory/Setup/Update/Release7.php [new file with mode: 0644]
tine20/Inventory/Setup/setup.xml
tine20/Inventory/js/InventoryItemEditDialog.js
tine20/Inventory/js/InventoryItemGridPanel.js
tine20/Inventory/translations/bg.po
tine20/Inventory/translations/ca.po
tine20/Inventory/translations/cs.po
tine20/Inventory/translations/da.po
tine20/Inventory/translations/de.po
tine20/Inventory/translations/en.po
tine20/Inventory/translations/es.po
tine20/Inventory/translations/es_MX.po
tine20/Inventory/translations/et.po
tine20/Inventory/translations/fa_IR.po
tine20/Inventory/translations/fi.po
tine20/Inventory/translations/fr.po
tine20/Inventory/translations/hr_HR.po
tine20/Inventory/translations/hu.po
tine20/Inventory/translations/it.po
tine20/Inventory/translations/ja.po
tine20/Inventory/translations/ko_KR.po [new file with mode: 0644]
tine20/Inventory/translations/lt.po
tine20/Inventory/translations/nb.po
tine20/Inventory/translations/nl_NL.po
tine20/Inventory/translations/pl.po
tine20/Inventory/translations/pt_BR.po
tine20/Inventory/translations/ru.po
tine20/Inventory/translations/sk.po
tine20/Inventory/translations/sv_SE.po
tine20/Inventory/translations/template.pot
tine20/Inventory/translations/tr_TR.po
tine20/Inventory/translations/vi.po
tine20/Inventory/translations/zh_CN.po
tine20/Inventory/translations/zh_TW.po
tine20/Phone/Controller.php
tine20/Phone/Setup/Update/Release6.php [new file with mode: 0644]
tine20/Phone/Setup/setup.xml
tine20/Phone/js/Models.js
tine20/Phone/js/Phone.js
tine20/Phone/translations/bg.po
tine20/Phone/translations/ca.po
tine20/Phone/translations/cs.po
tine20/Phone/translations/da.po
tine20/Phone/translations/de.po
tine20/Phone/translations/es.po
tine20/Phone/translations/es_MX.po
tine20/Phone/translations/et.po
tine20/Phone/translations/fa_IR.po
tine20/Phone/translations/fi.po
tine20/Phone/translations/fr.po
tine20/Phone/translations/hr_HR.po
tine20/Phone/translations/hu.po
tine20/Phone/translations/it.po
tine20/Phone/translations/ko_KR.po [new file with mode: 0644]
tine20/Phone/translations/lt.po
tine20/Phone/translations/nb.po
tine20/Phone/translations/nl_NL.po
tine20/Phone/translations/pl.po
tine20/Phone/translations/pt_BR.po
tine20/Phone/translations/ru.po
tine20/Phone/translations/sk.po
tine20/Phone/translations/sv_SE.po
tine20/Phone/translations/template.pot
tine20/Phone/translations/tr_TR.po
tine20/Phone/translations/vi.po
tine20/Phone/translations/zh_CN.po
tine20/Phone/translations/zh_TW.po
tine20/Projects/Acl/Rights.php [new file with mode: 0644]
tine20/Projects/Frontend/Cli.php
tine20/Projects/Model/Project.php
tine20/Projects/Setup/Update/Release6.php
tine20/Projects/Setup/Update/Release7.php [new file with mode: 0644]
tine20/Projects/Setup/setup.xml
tine20/Projects/js/ProjectEditDialog.js
tine20/Projects/translations/cs.po
tine20/Projects/translations/da.po
tine20/Projects/translations/de.po
tine20/Projects/translations/es.po
tine20/Projects/translations/es_MX.po
tine20/Projects/translations/et.po
tine20/Projects/translations/fa_IR.po
tine20/Projects/translations/fi.po
tine20/Projects/translations/fr.po
tine20/Projects/translations/hr_HR.po
tine20/Projects/translations/hu.po
tine20/Projects/translations/it.po
tine20/Projects/translations/ko_KR.po [new file with mode: 0644]
tine20/Projects/translations/lt.po
tine20/Projects/translations/nb.po
tine20/Projects/translations/nl_NL.po
tine20/Projects/translations/pl.po
tine20/Projects/translations/pt_BR.po
tine20/Projects/translations/ru.po
tine20/Projects/translations/sk.po
tine20/Projects/translations/sv_SE.po
tine20/Projects/translations/template.pot
tine20/Projects/translations/tr_TR.po
tine20/Projects/translations/vi.po
tine20/Projects/translations/zh_CN.po
tine20/Projects/translations/zh_TW.po
tine20/RELEASENOTES
tine20/Sales/Config.php
tine20/Sales/Controller.php
tine20/Sales/Controller/Contract.php
tine20/Sales/Frontend/Cli.php [new file with mode: 0644]
tine20/Sales/Model/Contract.php
tine20/Sales/Model/Product.php
tine20/Sales/Setup/DemoData.php [new file with mode: 0644]
tine20/Sales/Setup/Update/Release5.php
tine20/Sales/Setup/Update/Release6.php
tine20/Sales/Setup/Update/Release7.php [new file with mode: 0644]
tine20/Sales/Setup/setup.xml
tine20/Sales/js/Models.js
tine20/Sales/translations/bg.po
tine20/Sales/translations/ca.po
tine20/Sales/translations/cs.po
tine20/Sales/translations/da.po
tine20/Sales/translations/de.po
tine20/Sales/translations/es.po
tine20/Sales/translations/es_MX.po
tine20/Sales/translations/et.po
tine20/Sales/translations/fa_IR.po
tine20/Sales/translations/fi.po
tine20/Sales/translations/fr.po
tine20/Sales/translations/hr_HR.po
tine20/Sales/translations/hu.po
tine20/Sales/translations/it.po
tine20/Sales/translations/ko_KR.po [new file with mode: 0644]
tine20/Sales/translations/lt.po
tine20/Sales/translations/nb.po
tine20/Sales/translations/nl_NL.po
tine20/Sales/translations/pl.po
tine20/Sales/translations/pt_BR.po
tine20/Sales/translations/ru.po
tine20/Sales/translations/sk.po
tine20/Sales/translations/sv_SE.po
tine20/Sales/translations/template.pot
tine20/Sales/translations/tr_TR.po
tine20/Sales/translations/vi.po
tine20/Sales/translations/zh_CN.po
tine20/Sales/translations/zh_TW.po
tine20/Setup/Auth.php
tine20/Setup/Backend/Abstract.php
tine20/Setup/Backend/Oracle.php
tine20/Setup/Controller.php
tine20/Setup/translations/bg.po
tine20/Setup/translations/ca.po
tine20/Setup/translations/cs.po
tine20/Setup/translations/da.po
tine20/Setup/translations/de.po
tine20/Setup/translations/es.po
tine20/Setup/translations/es_MX.po
tine20/Setup/translations/et.po
tine20/Setup/translations/fa_IR.po
tine20/Setup/translations/fi.po
tine20/Setup/translations/fr.po
tine20/Setup/translations/hr_HR.po
tine20/Setup/translations/hu.po
tine20/Setup/translations/it.po
tine20/Setup/translations/ko_KR.po [new file with mode: 0644]
tine20/Setup/translations/lt.po
tine20/Setup/translations/nb.po
tine20/Setup/translations/nl_NL.po
tine20/Setup/translations/pl.po
tine20/Setup/translations/pt_BR.po
tine20/Setup/translations/ru.po
tine20/Setup/translations/sk.po
tine20/Setup/translations/sv_SE.po
tine20/Setup/translations/template.pot
tine20/Setup/translations/tr_TR.po
tine20/Setup/translations/vi.po
tine20/Setup/translations/zh_CN.po
tine20/Setup/translations/zh_TW.po
tine20/Setup/views/jsclient.php
tine20/SimpleFAQ/Config.php [new file with mode: 0644]
tine20/SimpleFAQ/Controller.php
tine20/SimpleFAQ/translations/es_MX.po
tine20/SimpleFAQ/translations/et.po
tine20/SimpleFAQ/translations/fi.po
tine20/SimpleFAQ/translations/fr.po
tine20/SimpleFAQ/translations/hr_HR.po
tine20/SimpleFAQ/translations/hu.po
tine20/SimpleFAQ/translations/it.po
tine20/SimpleFAQ/translations/ko_KR.po [new file with mode: 0644]
tine20/SimpleFAQ/translations/nl_NL.po
tine20/SimpleFAQ/translations/pl.po
tine20/SimpleFAQ/translations/ru.po
tine20/SimpleFAQ/translations/sv_SE.po
tine20/SimpleFAQ/translations/tr_TR.po
tine20/SimpleFAQ/translations/vi.po
tine20/SimpleFAQ/translations/zh_TW.po
tine20/Sipgate/Preference.php
tine20/Sipgate/js/Models.js
tine20/Sipgate/translations/cs.po
tine20/Sipgate/translations/da.po
tine20/Sipgate/translations/de.po
tine20/Sipgate/translations/es.po
tine20/Sipgate/translations/es_MX.po
tine20/Sipgate/translations/et.po
tine20/Sipgate/translations/fa_IR.po
tine20/Sipgate/translations/fi.po
tine20/Sipgate/translations/fr.po
tine20/Sipgate/translations/hr_HR.po
tine20/Sipgate/translations/hu.po
tine20/Sipgate/translations/it.po
tine20/Sipgate/translations/ko_KR.po [new file with mode: 0644]
tine20/Sipgate/translations/lt.po
tine20/Sipgate/translations/nl_NL.po
tine20/Sipgate/translations/pl.po
tine20/Sipgate/translations/pt_BR.po
tine20/Sipgate/translations/ru.po
tine20/Sipgate/translations/sk.po
tine20/Sipgate/translations/sv_SE.po
tine20/Sipgate/translations/template.pot
tine20/Sipgate/translations/tr_TR.po
tine20/Sipgate/translations/vi.po
tine20/Sipgate/translations/zh_CN.po
tine20/Sipgate/translations/zh_TW.po
tine20/Tasks/Acl/Rights.php
tine20/Tasks/Controller/Task.php
tine20/Tasks/Model/Task.php
tine20/Tasks/Setup/Update/Release6.php [new file with mode: 0644]
tine20/Tasks/Setup/Update/Release7.php [new file with mode: 0644]
tine20/Tasks/Setup/setup.xml
tine20/Tasks/translations/bg.po
tine20/Tasks/translations/ca.po
tine20/Tasks/translations/cs.po
tine20/Tasks/translations/da.po
tine20/Tasks/translations/de.po
tine20/Tasks/translations/es.po
tine20/Tasks/translations/es_MX.po
tine20/Tasks/translations/et.po
tine20/Tasks/translations/fa_IR.po
tine20/Tasks/translations/fi.po
tine20/Tasks/translations/fr.po
tine20/Tasks/translations/hr_HR.po
tine20/Tasks/translations/hu.po
tine20/Tasks/translations/it.po
tine20/Tasks/translations/ja.po
tine20/Tasks/translations/ko_KR.po [new file with mode: 0644]
tine20/Tasks/translations/lt.po
tine20/Tasks/translations/nb.po
tine20/Tasks/translations/nl_NL.po
tine20/Tasks/translations/pl.po
tine20/Tasks/translations/pt_BR.po
tine20/Tasks/translations/ru.po
tine20/Tasks/translations/sk.po
tine20/Tasks/translations/sv_SE.po
tine20/Tasks/translations/template.pot
tine20/Tasks/translations/tr_TR.po
tine20/Tasks/translations/vi.po
tine20/Tasks/translations/zh_CN.po
tine20/Tasks/translations/zh_TW.po
tine20/Timetracker/Acl/Rights.php
tine20/Timetracker/Frontend/Json.php
tine20/Timetracker/Model/Timeaccount.php
tine20/Timetracker/Model/TimeaccountFilter.php
tine20/Timetracker/Model/Timesheet.php
tine20/Timetracker/Setup/Update/Release3.php
tine20/Timetracker/Setup/Update/Release6.php [new file with mode: 0644]
tine20/Timetracker/Setup/Update/Release7.php [new file with mode: 0644]
tine20/Timetracker/Setup/setup.xml
tine20/Timetracker/js/Models.js
tine20/Timetracker/translations/bg.po
tine20/Timetracker/translations/ca.po
tine20/Timetracker/translations/cs.po
tine20/Timetracker/translations/da.po
tine20/Timetracker/translations/de.po
tine20/Timetracker/translations/es.po
tine20/Timetracker/translations/es_MX.po
tine20/Timetracker/translations/et.po
tine20/Timetracker/translations/fa_IR.po
tine20/Timetracker/translations/fi.po
tine20/Timetracker/translations/fr.po
tine20/Timetracker/translations/hr_HR.po
tine20/Timetracker/translations/hu.po
tine20/Timetracker/translations/it.po
tine20/Timetracker/translations/ko_KR.po [new file with mode: 0644]
tine20/Timetracker/translations/lt.po
tine20/Timetracker/translations/nb.po
tine20/Timetracker/translations/nl_NL.po
tine20/Timetracker/translations/pl.po
tine20/Timetracker/translations/pt_BR.po
tine20/Timetracker/translations/ru.po
tine20/Timetracker/translations/sk.po
tine20/Timetracker/translations/sv_SE.po
tine20/Timetracker/translations/template.pot
tine20/Timetracker/translations/tr_TR.po
tine20/Timetracker/translations/vi.po
tine20/Timetracker/translations/zh_CN.po
tine20/Timetracker/translations/zh_TW.po
tine20/Tinebase/AccessLog.php
tine20/Tinebase/Acl/Rights/Abstract.php
tine20/Tinebase/Acl/Roles.php
tine20/Tinebase/ActionQueue/Backend/Redis.php
tine20/Tinebase/Application.php
tine20/Tinebase/Auth.php
tine20/Tinebase/Backend/Sql/Abstract.php
tine20/Tinebase/Config.php
tine20/Tinebase/Config/Abstract.php
tine20/Tinebase/Container.php
tine20/Tinebase/Controller.php
tine20/Tinebase/Controller/Abstract.php
tine20/Tinebase/Controller/Record/Abstract.php
tine20/Tinebase/Convert/Json.php
tine20/Tinebase/Core.php
tine20/Tinebase/CustomField.php
tine20/Tinebase/EmailUser.php
tine20/Tinebase/EmailUser/Imap/Cyrus.php
tine20/Tinebase/EmailUser/Imap/Dbmail.php
tine20/Tinebase/EmailUser/Imap/Dovecot.php
tine20/Tinebase/EmailUser/Smtp/Postfix.php
tine20/Tinebase/EmailUser/Sql.php
tine20/Tinebase/FileSystem.php
tine20/Tinebase/FileSystem/StreamWrapper.php
tine20/Tinebase/Frontend/Cli.php
tine20/Tinebase/Frontend/Cli/Abstract.php
tine20/Tinebase/Frontend/Http.php
tine20/Tinebase/Frontend/Json.php
tine20/Tinebase/Frontend/Json/Abstract.php
tine20/Tinebase/Frontend/Json/PersistentFilter.php
tine20/Tinebase/Group.php
tine20/Tinebase/Group/Sql.php
tine20/Tinebase/ImageHelper.php
tine20/Tinebase/Import/Abstract.php
tine20/Tinebase/Import/Csv/Abstract.php
tine20/Tinebase/ImportExportDefinition.php
tine20/Tinebase/Model/Alarm.php
tine20/Tinebase/Model/Container.php
tine20/Tinebase/Model/Department.php
tine20/Tinebase/Model/Filter/CustomField.php
tine20/Tinebase/Model/Filter/Relation.php
tine20/Tinebase/Model/ImportExportDefinition.php
tine20/Tinebase/Model/ModificationLog.php
tine20/Tinebase/Model/ModificationLogFilter.php
tine20/Tinebase/Model/Note.php
tine20/Tinebase/Model/PersistentFilter.php
tine20/Tinebase/Model/PersistentObserver.php
tine20/Tinebase/Model/Relation.php
tine20/Tinebase/Model/State.php
tine20/Tinebase/Model/StateFilter.php [new file with mode: 0644]
tine20/Tinebase/Model/Tag.php
tine20/Tinebase/Model/TempFileFilter.php [new file with mode: 0644]
tine20/Tinebase/Model/Tree/FileObject.php
tine20/Tinebase/Model/Tree/Node.php
tine20/Tinebase/Notification/Backend/Smtp.php
tine20/Tinebase/PersistentFilter.php
tine20/Tinebase/Preference/Abstract.php
tine20/Tinebase/Record/Abstract.php
tine20/Tinebase/Record/Diff.php [new file with mode: 0644]
tine20/Tinebase/Record/RecordSet.php
tine20/Tinebase/Record/RecordSetDiff.php [new file with mode: 0644]
tine20/Tinebase/Relations.php
tine20/Tinebase/Scheduler/Task.php
tine20/Tinebase/Setup/DemoData/Abstract.php
tine20/Tinebase/Setup/Initialize.php
tine20/Tinebase/Setup/Update/Release0.php
tine20/Tinebase/Setup/Update/Release1.php
tine20/Tinebase/Setup/Update/Release2.php
tine20/Tinebase/Setup/Update/Release6.php
tine20/Tinebase/Setup/Update/Release7.php [new file with mode: 0644]
tine20/Tinebase/Setup/setup.xml
tine20/Tinebase/Smtp.php
tine20/Tinebase/State.php
tine20/Tinebase/Tags.php
tine20/Tinebase/TempFile.php
tine20/Tinebase/Timemachine/ModificationLog.php
tine20/Tinebase/Tinebase.jsb2
tine20/Tinebase/Translation.php
tine20/Tinebase/Tree/FileObject.php
tine20/Tinebase/Tree/Node.php
tine20/Tinebase/User.php
tine20/Tinebase/UserProfile.php
tine20/Tinebase/css/ux/form/ImageField.css
tine20/Tinebase/js/ApplicationStarter.js
tine20/Tinebase/js/ExceptionDialog.js
tine20/Tinebase/js/ExceptionHandler.js
tine20/Tinebase/js/LoginPanel.js
tine20/Tinebase/js/MainMenu.js
tine20/Tinebase/js/MainScreen.js
tine20/Tinebase/js/Models.js
tine20/Tinebase/js/RecentsManager.js [new file with mode: 0644]
tine20/Tinebase/js/common.js
tine20/Tinebase/js/configManager.js [new file with mode: 0644]
tine20/Tinebase/js/data/Record.js
tine20/Tinebase/js/data/RecordProxy.js
tine20/Tinebase/js/ux/file/BrowsePlugin.js
tine20/Tinebase/js/ux/file/Upload.js
tine20/Tinebase/js/ux/form/ColumnFormPanel.js
tine20/Tinebase/js/ux/form/ComboBoxRecentsPlugin.js [new file with mode: 0644]
tine20/Tinebase/js/ux/form/ImageField.js
tine20/Tinebase/js/widgets/ActionUpdater.js
tine20/Tinebase/js/widgets/ContentTypeTreePanel.js
tine20/Tinebase/js/widgets/MainScreen.js
tine20/Tinebase/js/widgets/account/PickerGridPanel.js
tine20/Tinebase/js/widgets/customfields/FilterModel.js
tine20/Tinebase/js/widgets/dialog/DuplicateResolveGridPanel.js
tine20/Tinebase/js/widgets/dialog/EditDialog.js
tine20/Tinebase/js/widgets/dialog/ImportDialog.js
tine20/Tinebase/js/widgets/dialog/MultipleEditDialogPlugin.js
tine20/Tinebase/js/widgets/dialog/TokenModeEditDialogPlugin.js
tine20/Tinebase/js/widgets/grid/FilterModel.js
tine20/Tinebase/js/widgets/grid/FilterPanel.js
tine20/Tinebase/js/widgets/grid/GridPanel.js
tine20/Tinebase/js/widgets/grid/LinkGridPanel.js
tine20/Tinebase/js/widgets/grid/PickerGridPanel.js
tine20/Tinebase/js/widgets/grid/QuickaddGridPanel.js
tine20/Tinebase/js/widgets/grid/RendererManager.js
tine20/Tinebase/js/widgets/keyfield/Filter.js
tine20/Tinebase/js/widgets/mainscreen/WestPanel.js
tine20/Tinebase/js/widgets/persistentfilter/EditPersistentFilterPanel.js
tine20/Tinebase/js/widgets/persistentfilter/PickerPanel.js
tine20/Tinebase/js/widgets/relation/GenericPickerGridPanel.js
tine20/Tinebase/js/widgets/tags/TagsPanel.js
tine20/Tinebase/translations/bg.po
tine20/Tinebase/translations/ca.po
tine20/Tinebase/translations/cs.po
tine20/Tinebase/translations/da.po
tine20/Tinebase/translations/de.po
tine20/Tinebase/translations/es.po
tine20/Tinebase/translations/es_MX.po
tine20/Tinebase/translations/et.po
tine20/Tinebase/translations/fa_IR.po
tine20/Tinebase/translations/fi.po
tine20/Tinebase/translations/fr.po
tine20/Tinebase/translations/hr_HR.po
tine20/Tinebase/translations/hu.po
tine20/Tinebase/translations/it.po
tine20/Tinebase/translations/ja.po
tine20/Tinebase/translations/ko_KR.po [new file with mode: 0644]
tine20/Tinebase/translations/lt.po
tine20/Tinebase/translations/nb.po
tine20/Tinebase/translations/nl_NL.po
tine20/Tinebase/translations/pl.po
tine20/Tinebase/translations/pt_BR.po
tine20/Tinebase/translations/ru.po
tine20/Tinebase/translations/sk.po
tine20/Tinebase/translations/sv_SE.po
tine20/Tinebase/translations/template.pot
tine20/Tinebase/translations/tr_TR.po
tine20/Tinebase/translations/vi.po
tine20/Tinebase/translations/zh_CN.po
tine20/Tinebase/translations/zh_TW.po
tine20/Tinebase/views/jsclient.php
tine20/Voipmanager/Backend/Snom/Phone.php
tine20/Voipmanager/Controller/Asterisk/SipPeer.php
tine20/Voipmanager/Controller/Snom/Phone.php
tine20/Voipmanager/Frontend/Cli.php [new file with mode: 0644]
tine20/Voipmanager/Frontend/Json.php
tine20/Voipmanager/Model/Snom/Line.php
tine20/Voipmanager/Setup/DemoData.php [new file with mode: 0644]
tine20/Voipmanager/Setup/Update/Release6.php [new file with mode: 0644]
tine20/Voipmanager/Setup/setup.xml
tine20/Voipmanager/js/Models.js
tine20/Voipmanager/js/Snom/LineGridPanel.js
tine20/Voipmanager/translations/bg.po
tine20/Voipmanager/translations/ca.po
tine20/Voipmanager/translations/cs.po
tine20/Voipmanager/translations/da.po
tine20/Voipmanager/translations/de.po
tine20/Voipmanager/translations/es.po
tine20/Voipmanager/translations/es_MX.po
tine20/Voipmanager/translations/et.po
tine20/Voipmanager/translations/fa_IR.po
tine20/Voipmanager/translations/fi.po
tine20/Voipmanager/translations/fr.po
tine20/Voipmanager/translations/hr_HR.po
tine20/Voipmanager/translations/hu.po
tine20/Voipmanager/translations/it.po
tine20/Voipmanager/translations/ja.po
tine20/Voipmanager/translations/ko_KR.po [new file with mode: 0644]
tine20/Voipmanager/translations/lt.po
tine20/Voipmanager/translations/nb.po
tine20/Voipmanager/translations/nl_NL.po
tine20/Voipmanager/translations/pl.po
tine20/Voipmanager/translations/pt_BR.po
tine20/Voipmanager/translations/ru.po
tine20/Voipmanager/translations/sk.po
tine20/Voipmanager/translations/sv_SE.po
tine20/Voipmanager/translations/template.pot
tine20/Voipmanager/translations/tr_TR.po
tine20/Voipmanager/translations/vi.po
tine20/Voipmanager/translations/zh_CN.po
tine20/Voipmanager/translations/zh_TW.po
tine20/Zend/Db/Adapter/Oracle.php
tine20/Zend/Mail/Protocol/Sieve.php
tine20/bootstrap.php
tine20/build.xml
tine20/langHelper.php
tine20/library/ExtJS/adapter/ext/ext-base-debug.js
tine20/library/ExtJS/adapter/ext/ext-base.js
tine20/library/ExtJS/ext-all-debug.js
tine20/library/ExtJS/ext-all.js
tine20/library/HTMLPurifier/HTMLPurifier.composer.php [new file with mode: 0644]
tine20/library/HTMLPurifier/HTMLPurifier.includes.php
tine20/library/HTMLPurifier/HTMLPurifier.php
tine20/library/HTMLPurifier/HTMLPurifier.safe-includes.php
tine20/library/HTMLPurifier/HTMLPurifier/AttrDef/CSS/Background.php
tine20/library/HTMLPurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php
tine20/library/HTMLPurifier/HTMLPurifier/AttrDef/HTML/Color.php
tine20/library/HTMLPurifier/HTMLPurifier/AttrTransform/Nofollow.php
tine20/library/HTMLPurifier/HTMLPurifier/AttrTransform/TargetBlank.php
tine20/library/HTMLPurifier/HTMLPurifier/Bootstrap.php
tine20/library/HTMLPurifier/HTMLPurifier/CSSDefinition.php
tine20/library/HTMLPurifier/HTMLPurifier/Config.php
tine20/library/HTMLPurifier/HTMLPurifier/ConfigSchema/schema.ser
tine20/library/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt [new file with mode: 0644]
tine20/library/HTMLPurifier/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt [new file with mode: 0644]
tine20/library/HTMLPurifier/HTMLPurifier/ElementDef.php
tine20/library/HTMLPurifier/HTMLPurifier/Encoder.php
tine20/library/HTMLPurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php
tine20/library/HTMLPurifier/HTMLPurifier/HTMLModule/Bdo.php
tine20/library/HTMLPurifier/HTMLPurifier/HTMLModule/Name.php
tine20/library/HTMLPurifier/HTMLPurifier/HTMLModule/SafeScripting.php [new file with mode: 0644]
tine20/library/HTMLPurifier/HTMLPurifier/HTMLModule/Scripting.php
tine20/library/HTMLPurifier/HTMLPurifier/HTMLModuleManager.php
tine20/library/HTMLPurifier/HTMLPurifier/Injector/RemoveEmpty.php
tine20/library/HTMLPurifier/HTMLPurifier/Strategy/FixNesting.php
tine20/library/HTMLPurifier/HTMLPurifier/URIDefinition.php
tine20/library/HTMLPurifier/HTMLPurifier/URIScheme/data.php
tine20/library/Syncroton/lib/Syncroton/Server.php

index 828f6ab..86dc3b0 100644 (file)
@@ -1,8 +1,38 @@
-tine20 (2012.10.4-0) natty; urgency=low
+tine20 (2013.03.4-0) natty; urgency=low
 
-  * New upstream release Joey SR 4 (2012.10.4)
+  * New upstream release "Kristina" Service Release 3
 
- -- Philipp Schüle <p.schuele@metaways.de>  Thu, 21 Feb 2013 16:13:24 +0100
+ -- Philipp Schüle <p.schuele@metaways.de>  Thu, 23 May 2013 10:16:21 +0200
+
+tine20 (2013.03.3-0) natty; urgency=low
+
+  * New upstream release "Kristina" Service Release 2
+
+ -- Philipp Schüle <p.schuele@metaways.de>  Thu, 25 Apr 2013 11:30:21 +0200
+
+tine20 (2013.03.1-0) natty; urgency=low
+
+  * New upstream release "Kristina"
+
+ -- Philipp Schüle <p.schuele@metaways.de>  Thu, 27 Feb 2013 15:57:20 +0100
+
+tine20 (2013.03.1~rc1-0) natty; urgency=low
+
+  * New RC 1 upstream release of "Kristina"
+
+ -- Philipp Schüle <p.schuele@metaways.de>  Thu, 14 Feb 2013 17:16:19 +0100
+
+tine20 (2013.03.1~beta1-0) natty; urgency=low
+
+  * New beta upstream release of "Kristina"
+
+ -- Philipp Schüle <p.schuele@metaways.de>  Thu, 14 Feb 2013 11:50:19 +0100
+
+tine20 (2013.03.1~alpha1-0) natty; urgency=low
+
+  * New alpha upstream release of "Kristina"
+
+ -- Philipp Schüle <p.schuele@metaways.de>  Thu, 07 Feb 2013 11:31:17 +0100
 
 tine20 (2012.10.3-0) natty; urgency=low
 
index b39a9a4..3af033f 100755 (executable)
@@ -3,15 +3,15 @@
 # Version: $Id$
 
 # examples
-# $ ./build-tine20-packages.sh -s "http://git.tine20.org/git/tine20" -b master -r "2011_01_beta3-1" -c "Neele"
-# $ ./build-tine20-packages.sh -s "http://git.tine20.org/git/tine20" -b 2011-01 -r "2011-01-3" -c "Neele"
+# $ ./build-tine20-packages.sh -s "http://git.tine20.org/git/tine20" -b master -r "2011_01_beta3-1" -c "Kristina"
+# $ ./build-tine20-packages.sh -s "http://git.tine20.org/git/tine20" -b 2011-01 -r "2011-01-3" -c "Kristina"
 
 ## GLOBAL VARIABLES ##
 BASEDIR="./tine20build"
 TEMPDIR="$BASEDIR/temp"
 MISCPACKAGESDIR="$BASEDIR/packages/misc"
 
-CODENAME="Joey"
+CODENAME="Kristina"
 GITURL="http://git.tine20.org/git/tine20"
 
 RELEASE=""
@@ -150,6 +150,13 @@ function activateReleaseMode()
     sed -i -e "s/Tine.clientVersion.releaseTime[^;]*/Tine.clientVersion.releaseTime = '$DATETIME'/" $TEMPDIR/tine20/Tinebase/js/tineInit.js
 }
 
+function buildLangStats()
+{
+    echo -n "building lang stats ... "
+    php -f $TEMPDIR/tine20/langHelper.php -- --statistics
+    echo "done"
+}
+
 function buildClient()
 {
     echo -n "building javascript clients ... "
@@ -223,6 +230,9 @@ function createArchives()
                     # cleanup jsb2tk
                     (cd $TEMPDIR/tine20/library/jsb2tk;  rm -rf JSBuilder2 tests)
                     
+                    # save langStats
+                    (mv $TEMPDIR/tine20/langstatistics.json $TEMPDIR/tine20/Tinebase/translations/langstatistics.json)
+                    
                     echo -n "building "
                     local FILES="Addressbook Admin Setup Tinebase Zend images library styles docs config.inc.php.dist index.php langHelper.php LICENSE PRIVACY README RELEASENOTES CREDITS setup.php tine20.php bootstrap.php worker.php"
                     (cd $TEMPDIR/tine20; tar cjf ../../packages/tine20/$RELEASE/tine20-${UCFILE}_$RELEASE.tar.bz2 $FILES)
@@ -373,6 +383,7 @@ createDirectories
 checkout "$GITURL" "$GITBRANCH"
 setupPackageDir
 activateReleaseMode
+buildLangStats
 buildClient
 createArchives
 createSpecialArchives
index a259746..35fa551 100644 (file)
@@ -1,9 +1,45 @@
-tine20 (2012.10.4-0) natty; urgency=low
+tine20 (2013.03.4-0) natty; urgency=low
 
-  * New upstream release Joey SR 4 (2012.10.4)
+  * New upstream release "Kristina" Service Release 3
 
- -- Philipp Schüle <p.schuele@metaways.de>  Thu, 21 Feb 2013 16:13:24 +0100
+ -- Philipp Schüle <p.schuele@metaways.de>  Thu, 23 May 2013 10:16:21 +0200
 
+tine20 (2013.03.3-0) natty; urgency=low
+
+  * New upstream release "Kristina" Service Release 2
+
+ -- Philipp Schüle <p.schuele@metaways.de>  Thu, 25 Apr 2013 11:30:21 +0200
+
+tine20 (2013.03.2-0) natty; urgency=low
+
+  * New upstream release "Kristina" Service Release 1
+
+ -- Cornelius Weiß <c.weiss@metaways.de>  Thu, 28 Mar 2013 15:30:00 +0100
+
+tine20 (2013.03.1-0) natty; urgency=low
+
+  * New upstream release "Kristina"
+
+ -- Philipp Schüle <p.schuele@metaways.de>  Thu, 27 Feb 2013 15:57:20 +0100
+
+tine20 (2013.03.1~rc1-0) natty; urgency=low
+
+  * New RC 1 upstream release of "Kristina"
+
+ -- Philipp Schüle <p.schuele@metaways.de>  Thu, 14 Feb 2013 17:16:19 +0100
+
+tine20 (2013.03.1~beta1-0) natty; urgency=low
+
+  * New beta upstream release of "Kristina"
+
+ -- Philipp Schüle <p.schuele@metaways.de>  Thu, 14 Feb 2013 11:49:18 +0100
+
+tine20 (2013.03.1~alpha1-0) natty; urgency=low
+
+  * New alpha upstream release of "Kristina"
+
+ -- Philipp Schüle <p.schuele@metaways.de>  Thu, 07 Feb 2013 11:31:17 +0100
 tine20 (2012.10.3-0) natty; urgency=low
 
   * New upstream release Joey SR 3 (2012.10.3)
index f199058..05808ab 100644 (file)
@@ -42,9 +42,8 @@ Depends: ${misc:Depends},
  php5-mysql | php5-mysqli | php5-pgsql,
  php5-mcrypt, 
  php5-gd,
- php-apc,
  makepasswd
-Recommends: mysql-client | postgresql-client (>= 9.1)
+Recommends: mysql-client | postgresql-client (>= 9.1), php-apc
 Description: Tine 2.0 webserver integration package
  This package integrates Tine 2.0 with the webserver, by installing all needed
  dependencies to make Tine 2.0 available via HTTP(S).
index 06fb7f1..f1485ca 100644 (file)
@@ -25,8 +25,8 @@
 # Wbxml/        - not found in Fedora
 # Zend/         - there is php-ZendFramework, strip it out
 
-%global vyear 2012
-%global vmonth 10
+%global vyear 2013
+%global vmonth 03
 %global vmin 4
 
 Name:           tine20
@@ -301,6 +301,15 @@ fi
 %files webstack
 
 %changelog
+* Thu May 23 2013 Philipp Schüle <p.schuele@metaways.de> - 2013.03.4-1
+- New upstream release Kristina Service Release 3
+
+* Thu Apr 25 2013 Philipp Schüle <p.schuele@metaways.de> - 2013.03.3-1
+- New upstream release Kristina Service Release 2
+
+* Thu Feb 07 2013 Philipp Schüle <p.schuele@metaways.de> - 2013.03.1~alpha1-1
+- New upstream release Kristina Alpha 1
+
 * Wed Jan 04 2013 Lars Kneschke <l.kneschke@metaways.de> - 2012.10.3-1
 - New upstream release Joey SR 3 (2012.10.3)
 
diff --git a/tests/js_client/checklists/tests_js_client_2013.03.1.ods b/tests/js_client/checklists/tests_js_client_2013.03.1.ods
new file mode 100644 (file)
index 0000000..74b083a
Binary files /dev/null and b/tests/js_client/checklists/tests_js_client_2013.03.1.ods differ
index 21fe775..47250fa 100644 (file)
@@ -322,11 +322,5 @@ class Setup_Backend_OracleTest extends Setup_Backend_AbstractTest
         $dbProxy->setNamedParamPrefix($_prefix);
         
         return $dbProxy;
-    }    
-}        
-
-
-                
-if (PHPUnit_MAIN_METHOD == 'Setup_Backend_MysqlTest::main') {
-    Setup_Backend_OracleTest::main();
+    }
 }
index c114c13..c9a1b67 100644 (file)
@@ -125,20 +125,20 @@ class Setup_ControllerTest extends PHPUnit_Framework_TestCase
     public function testSaveAuthenticationRedirectSettings()
     {
         $originalRedirectSettings = array(
-          Tinebase_Config::REDIRECTURL => Tinebase_Config::getInstance()->getConfig(Tinebase_Config::REDIRECTURL, NULL, '')->value,
-          Tinebase_Config::REDIRECTTOREFERRER => Tinebase_Config::getInstance()->getConfig(Tinebase_Config::REDIRECTTOREFERRER, NULL, '')->value
+          Tinebase_Config::REDIRECTURL => Tinebase_Config::getInstance()->get(Tinebase_Config::REDIRECTURL, ''),
+          Tinebase_Config::REDIRECTTOREFERRER => Tinebase_Config::getInstance()->get(Tinebase_Config::REDIRECTTOREFERRER, '')
         );
-        
+         
         $newRedirectSettings = array(
           Tinebase_Config::REDIRECTURL => 'http://tine20.org',
-          Tinebase_Config::REDIRECTTOREFERRER => '1'
+          Tinebase_Config::REDIRECTTOREFERRER => 1
         );
         
         $this->_uit->saveAuthentication(array('redirectSettings' => $newRedirectSettings));
         
         $storedRedirectSettings = array(
-          Tinebase_Config::REDIRECTURL => Tinebase_Config::getInstance()->getConfig(Tinebase_Config::REDIRECTURL, NULL, '')->value,
-          Tinebase_Config::REDIRECTTOREFERRER => Tinebase_Config::getInstance()->getConfig(Tinebase_Config::REDIRECTTOREFERRER, NULL, '')->value
+          Tinebase_Config::REDIRECTURL => Tinebase_Config::getInstance()->get(Tinebase_Config::REDIRECTURL, ''),
+          Tinebase_Config::REDIRECTTOREFERRER => Tinebase_Config::getInstance()->get(Tinebase_Config::REDIRECTTOREFERRER, '')
         );
         
         $this->assertEquals($storedRedirectSettings, $newRedirectSettings);
@@ -147,14 +147,14 @@ class Setup_ControllerTest extends PHPUnit_Framework_TestCase
         //test empty redirectUrl
         $newRedirectSettings = array(
           Tinebase_Config::REDIRECTURL => '',
-          Tinebase_Config::REDIRECTTOREFERRER => '0'
+          Tinebase_Config::REDIRECTTOREFERRER => 0
         );
         
         $this->_uit->saveAuthentication(array('redirectSettings' => $newRedirectSettings));
         
         $storedRedirectSettings = array(
-          Tinebase_Config::REDIRECTURL => Tinebase_Config::getInstance()->getConfig(Tinebase_Config::REDIRECTURL, NULL, '')->value,
-          Tinebase_Config::REDIRECTTOREFERRER => Tinebase_Config::getInstance()->getConfig(Tinebase_Config::REDIRECTTOREFERRER, NULL, '')->value
+          Tinebase_Config::REDIRECTURL => Tinebase_Config::getInstance()->get(Tinebase_Config::REDIRECTURL, ''),
+          Tinebase_Config::REDIRECTTOREFERRER => Tinebase_Config::getInstance()->get(Tinebase_Config::REDIRECTTOREFERRER, '')
         );
         
         $this->assertEquals($storedRedirectSettings, $newRedirectSettings);
index 395cc3a..4399e41 100644 (file)
@@ -74,7 +74,7 @@ class ActiveSync_Controller_EmailTests extends PHPUnit_Framework_TestCase
      */
     protected function setUp()
     {
-        $imapConfig = Tinebase_Config::getInstance()->getConfigAsArray(Tinebase_Config::IMAP);
+        $imapConfig = Tinebase_Config::getInstance()->get(Tinebase_Config::IMAP, new Tinebase_Config_Struct())->toArray();
         if (empty($imapConfig) || !array_key_exists('useSystemAccount', $imapConfig) || $imapConfig['useSystemAccount'] != true) {
             $this->markTestSkipped('IMAP backend not configured');
         }
index f0d89ee..958f1ad 100644 (file)
  */
 require_once dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'TestHelper.php';
 
-if (!defined('PHPUnit_MAIN_METHOD')) {
-    define('PHPUnit_MAIN_METHOD', 'Addressbook_Backend_LdapTest::main');
-}
-
 /**
  * Test class for Tinebase_User
  */
@@ -73,10 +69,4 @@ class Addressbook_Backend_LdapTest extends PHPUnit_Framework_TestCase
     {
         $this->_backend->getAll();
     }
-    
-}       
-    
-
-if (PHPUnit_MAIN_METHOD == 'Addressbook_Backend_LdapTest::main') {
-    Addressbook_Backend_LdapTest::main();
 }
index ee42415..58b9f6a 100644 (file)
@@ -377,7 +377,7 @@ class Addressbook_JsonTest extends PHPUnit_Framework_TestCase
         $this->assertEquals($record['url'],'http://www.phpunit.de','DefaultField "url" was not updated as expected');
         
         // check 'changed' systemnote
-        $this->_checkChangedNote($record['id'], 'adr_one_region ( -> PHPUNIT_multipleUpdate) url ( -> http://www.phpunit.de) customfields ([] -> {');
+        $this->_checkChangedNote($record['id'], 'adr_one_region ( -> PHPUNIT_multipleUpdate) url ( -> http://www.phpunit.de) customfields ( -> {');
         
         // check invalid data
         
@@ -400,21 +400,10 @@ class Addressbook_JsonTest extends PHPUnit_Framework_TestCase
     protected function _createCustomfield($cfName = NULL)
     {
         $cfName = ($cfName !== NULL) ? $cfName : Tinebase_Record_Abstract::generateUID();
-        
-        $cfc = new Tinebase_Model_CustomField_Config(array(
-            'application_id'    => Tinebase_Application::getInstance()->getApplicationByName('Addressbook')->getId(),
-            'name'              => $cfName,
-            'model'             => 'Addressbook_Model_Contact',
-            'definition'        => array(
-                'label' => Tinebase_Record_Abstract::generateUID(),
-                'type'  => 'string',
-                'uiconfig' => array(
-                    'xtype'  => Tinebase_Record_Abstract::generateUID(),
-                    'length' => 10,
-                    'group'  => 'unittest',
-                    'order'  => 100,
-                )
-            )
+        $cfc = Tinebase_CustomFieldTest::getCustomField(array(
+            'application_id' => Tinebase_Application::getInstance()->getApplicationByName('Addressbook')->getId(),
+            'model'          => 'Addressbook_Model_Contact',
+            'name'           => $cfName,
         ));
         
         $createdCustomField = Tinebase_CustomField::getInstance()->addCustomField($cfc);
@@ -477,7 +466,11 @@ class Addressbook_JsonTest extends PHPUnit_Framework_TestCase
         $result = $this->_instance->saveContact($contact);
         
         $this->assertEquals($tagName, $result['tags'][0]['name']);
-        $this->_checkChangedNote($result['id'], array('tags ([] -> {"added":[{"id":', '"type":"personal"', ',"name":"' . $tagName . '","description":"testModlog","color":"#009B31"'));
+        $this->_checkChangedNote($result['id'], array(
+            '[] -> {"model":"Tinebase_Model_Tag","added":[{"id":"',
+            '"type":"personal"',
+            ',"name":"' . $tagName . '","description":"testModlog","color":"#009B31"'
+        ));
         
         return $result;
     }
@@ -504,9 +497,9 @@ class Addressbook_JsonTest extends PHPUnit_Framework_TestCase
     {
         $contact = $this->testTagsModlog();
         $contact['tags'] = array();
-        sleep(1);
+        sleep(1); // make sure that the second change always gets last when fetching notes
         $result = $this->_instance->saveContact($contact);
-        $this->_checkChangedNote($result['id'], array('tags ([{"id":', ' -> {"removed":[{'), 4);
+        $this->_checkChangedNote($result['id'], array('-> {"model":"Tinebase_Model_Tag","added":[],"removed":[{"id":"'), 4);
     }
     
     /**
@@ -577,7 +570,7 @@ class Addressbook_JsonTest extends PHPUnit_Framework_TestCase
         $this->assertEquals($contact['id'], $updatedContact['id'], 'updated produced a new contact');
         $this->assertEquals('PHPUNIT UPDATE', $updatedContact['n_family'], 'updating data failed');
 
-        if (Tinebase_Config::getInstance()->getConfig(Tinebase_Config::MAPPANEL, NULL, TRUE)->value) {
+        if (Tinebase_Config::getInstance()->get(Tinebase_Config::MAPPANEL, TRUE)) {
             // check geo data
             $this->assertEquals('9.99489300545466', $updatedContact['adr_one_lon'], 'wrong geodata (lon)');
             $this->assertEquals('53.5444258235736', $updatedContact['adr_one_lat'], 'wrong geodata (lat)');
@@ -630,8 +623,6 @@ class Addressbook_JsonTest extends PHPUnit_Framework_TestCase
             'value'    =>  Tinebase_Core::getUser()->accountDisplayName
         )));
         $sharedTagName = $this->_createAndAttachTag($filter);
-        // need to sleep for 1 second because modlog does not allow to change the same attribute twice in the same second ...
-        sleep(1);
         $personalTagName = $this->_createAndAttachTag($filter, Tinebase_Model_Tag::TYPE_PERSONAL);
 
         // export first and create files array
@@ -895,9 +886,6 @@ class Addressbook_JsonTest extends PHPUnit_Framework_TestCase
             'index'             => 1,
         ));
         
-        // need to sleep for 1 second because modlog does not allow to change the same attribute twice in the same second ...
-        sleep(1);
-        
         $result = $this->_importHelper(array('dryrun' => 0), $clientRecords);
         $this->assertEquals(1, $result['totalcount'], 'Should merge fritz: ' . print_r($result['exceptions'], TRUE));
         $this->assertEquals(2, count($result['results'][0]['tags']), 'Should merge tags');
@@ -1440,7 +1428,6 @@ class Addressbook_JsonTest extends PHPUnit_Framework_TestCase
                     'description' => 'testImport',
                     'color' => '#009B31',
         ));
-        sleep(1);
         $tag = Tinebase_Tags::getInstance()->attachTagToMultipleRecords($filter, $tag);
         $filter = array(array(
             'field'    => 'tag',
index c568e97..e28ec08 100644 (file)
@@ -872,7 +872,7 @@ class Admin_JsonTest extends PHPUnit_Framework_TestCase
     public function testContainerNotification()
     {
         // prepare smtp transport
-        $smtpConfig = Tinebase_Config::getInstance()->getConfigAsArray(Tinebase_Config::SMTP);
+        $smtpConfig = Tinebase_Config::getInstance()->get(Tinebase_Config::SMTP, new Tinebase_Config_Struct())->toArray();
         if (empty($smtpConfig)) {
              $this->markTestSkipped('No SMTP config found: this is needed to send notifications.');
         }
index 6d2786d..22533dc 100644 (file)
@@ -4,7 +4,7 @@
  * 
  * @package     Calendar
  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
- * @copyright   Copyright (c) 2009 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2009-2013 Metaways Infosystems GmbH (http://www.metaways.de)
  * @author      Cornelius Weiss <c.weiss@metaways.de>
  */
 
  */
 require_once dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'TestHelper.php';
 
-if (!defined('PHPUnit_MAIN_METHOD')) {
-    define('PHPUnit_MAIN_METHOD', 'Calendar_Controller_EventGrantsTests::main');
-}
-
 /**
  * Test class for Calendar_Controller_Event
  * 
@@ -163,8 +159,8 @@ class Calendar_Controller_EventGrantsTests extends Calendar_TestCase
         
         $loadedEvent = $this->_uit->get($persistentEvent->getId());
         $this->assertEquals($persistentEvent->summary, $loadedEvent->summary);
-        $this->assertTrue((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_EDIT});
-        $this->assertFalse((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_DELETE});
+        $this->assertTrue((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_EDIT}, Tinebase_Model_Grants::GRANT_EDIT);
+        $this->assertTrue((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_DELETE}, Tinebase_Model_Grants::GRANT_DELETE);
     }
     
     /**
@@ -178,8 +174,6 @@ class Calendar_Controller_EventGrantsTests extends Calendar_TestCase
         $loadedEvent = $this->_uit->get($persistentEvent->getId());
         
         $this->assertEquals($persistentEvent->summary, $loadedEvent->summary);
-        $this->assertTrue((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_EDIT});
-        $this->assertFalse((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_DELETE});
     }
     
     /**
@@ -198,8 +192,6 @@ class Calendar_Controller_EventGrantsTests extends Calendar_TestCase
         $this->assertEquals(1, count($loadedEvent), 'event not found with search action!');
         $this->assertTrue((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_READ}, 'event not readable');
         $this->assertEquals($persistentEvent->summary, $loadedEvent->summary);
-        $this->assertTrue((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_EDIT});
-        $this->assertFalse((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_DELETE});
     }
     
     /**
@@ -218,9 +210,9 @@ class Calendar_Controller_EventGrantsTests extends Calendar_TestCase
         
         $this->assertFalse(empty($event), 'no event found, but freebusy info should be');
         $this->assertTrue(empty($event->summary), 'event with freebusy only is not cleaned up');
-        $this->assertFalse((bool)$event->{Tinebase_Model_Grants::GRANT_READ});
-        $this->assertFalse((bool)$event->{Tinebase_Model_Grants::GRANT_EDIT});
-        $this->assertFalse((bool)$event->{Tinebase_Model_Grants::GRANT_DELETE});
+        $this->assertFalse((bool)$event->{Tinebase_Model_Grants::GRANT_READ}, Tinebase_Model_Grants::GRANT_READ);
+        $this->assertFalse((bool)$event->{Tinebase_Model_Grants::GRANT_EDIT}, Tinebase_Model_Grants::GRANT_EDIT);
+        $this->assertFalse((bool)$event->{Tinebase_Model_Grants::GRANT_DELETE}, Tinebase_Model_Grants::GRANT_DELETE);
         
         // direct get of freebusy only events is not allowed
         $this->setExpectedException('Tinebase_Exception_AccessDenied');
@@ -236,8 +228,8 @@ class Calendar_Controller_EventGrantsTests extends Calendar_TestCase
         $persistentEvent = $this->_createEventInPersonasCalendar('jmcblack', 'jmcblack', 'jmcblack', Calendar_Model_Event::CLASS_PRIVATE);
         $loadedEvent = $this->_uit->get($persistentEvent->getId());
         $this->assertEquals($persistentEvent->summary, $loadedEvent->summary);
-        $this->assertTrue((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_READ});
-        $this->assertFalse((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_DELETE});
+        $this->assertTrue((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_READ}, Tinebase_Model_Grants::GRANT_READ);
+        $this->assertFalse((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_DELETE}, Tinebase_Model_Grants::GRANT_DELETE);
     }
     
     /**
@@ -274,9 +266,9 @@ class Calendar_Controller_EventGrantsTests extends Calendar_TestCase
         $persistentEvent = $this->_createEventInPersonasCalendar('rwright', NULL, 'rwright', Calendar_Model_Event::CLASS_PRIVATE);
         $loadedEvent = $this->_uit->get($persistentEvent->getId());
         $this->assertEquals($persistentEvent->summary, $loadedEvent->summary);
-        $this->assertTrue((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_READ});
-        $this->assertTrue((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_EDIT});
-        $this->assertFalse((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_DELETE});
+        $this->assertTrue((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_READ}, Tinebase_Model_Grants::GRANT_READ);
+        $this->assertTrue((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_EDIT}, Tinebase_Model_Grants::GRANT_EDIT);
+        $this->assertTrue((bool)$loadedEvent->{Tinebase_Model_Grants::GRANT_DELETE}, Tinebase_Model_Grants::GRANT_DELETE);
     }
     
     /**
@@ -449,6 +441,8 @@ class Calendar_Controller_EventGrantsTests extends Calendar_TestCase
     
     public function testCreateRecurExceptionWithEditGrantOnly()
     {
+        $this->markTestIncomplete('temporarily disabled until fixed');
+        
         // set testuser to have editgrant for sclever
         Tinebase_Container::getInstance()->setGrants($this->_personasDefaultCals['sclever'], new Tinebase_Record_RecordSet('Tinebase_Model_Grants', array(array(
             'account_id'    => $this->_personas['sclever']->getId(),
@@ -482,9 +476,10 @@ class Calendar_Controller_EventGrantsTests extends Calendar_TestCase
         
         $this->assertEquals(1, count($events), 'failed to search fb event');
         
-        
         Calendar_Model_Rrule::mergeRecurrenceSet($events, $updatedEvent->dtstart, $updatedEvent->dtstart->getClone()->addDay(7));
         
+        $this->assertEquals(8, count($events), 'failed to merge recurrence set');
+        
         $events[3]->summary = 'exception';
         $exception = $this->_uit->createRecurException($events[3]);
         
@@ -694,8 +689,3 @@ class Calendar_Controller_EventGrantsTests extends Calendar_TestCase
         }
     }
 }
-    
-
-if (PHPUnit_MAIN_METHOD == 'Calendar_Controller_EventGrantsTests::main') {
-    Calendar_Controller_EventGrantsTests::main();
-}
index 7aac7e9..39ea0c6 100644 (file)
@@ -55,7 +55,7 @@ class Calendar_Controller_EventNotificationsTests extends Calendar_TestCase
     {
         parent::setUp();
         
-        $smtpConfig = Tinebase_Config::getInstance()->getConfigAsArray(Tinebase_Config::SMTP);
+        $smtpConfig = Tinebase_Config::getInstance()->get(Tinebase_Config::SMTP, new Tinebase_Config_Struct())->toArray();
         if (empty($smtpConfig)) {
              $this->markTestSkipped('No SMTP config found: this is needed to send notifications.');
         }
@@ -712,6 +712,32 @@ class Calendar_Controller_EventNotificationsTests extends Calendar_TestCase
         $this->assertEquals('2012-04-02 06:30:00', $alarm->alarm_time->toString());
     }
     
+    public function testAlarmSkipDeclined()
+    {
+        $event = $this->_getEvent();
+        $event->attendee = $this->_getPersonaAttendee('sclever, pwulf');
+        $event->organizer = $this->_personasContacts['sclever']->getId();
+        
+        $event->dtstart = Tinebase_DateTime::now()->addMinute(25);
+        $event->dtend = clone $event->dtstart;
+        $event->dtend->addMinute(30);
+        $event->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm', array(
+            new Tinebase_Model_Alarm(array(
+                'minutes_before' => 30
+            ), TRUE)
+        ));
+        
+        $persistentEvent = $this->_eventController->create($event);
+        $sclever = Calendar_Model_Attender::getAttendee($persistentEvent->attendee, $event->attendee[0]);
+        $sclever->status = Calendar_Model_Attender::STATUS_DECLINED;
+        $this->_eventController->attenderStatusUpdate($persistentEvent, $sclever, $sclever->status_authkey);
+        
+        self::flushMailer();
+        Tinebase_Alarm::getInstance()->sendPendingAlarms("Tinebase_Event_Async_Minutely");
+        $this->_assertMail('pwulf', 'Alarm');
+        $this->assertEquals(1, count(self::getMessages()));
+    }
+    
     /**
      * get test alarm emails
      * 
index f3fc508..83cbe20 100644 (file)
@@ -708,7 +708,7 @@ class Calendar_Controller_EventTests extends Calendar_TestCase
         $user = $loadedEvent->attendee
             ->filter('user_type', Calendar_Model_Attender::USERTYPE_GROUPMEMBER)
             ->filter('user_id', $newUser->contact_id);
-        $this->assertEquals(1, count($user), 'added user is not attender of event, but should be');
+        $this->assertEquals(1, count($user), 'added user is not attender of event, but should be. user: ' . print_r($newUser->toArray(), TRUE));
         
         // cleanup user
         Admin_Controller_User::getInstance()->delete($newUser->getId());
@@ -721,7 +721,7 @@ class Calendar_Controller_EventTests extends Calendar_TestCase
         $user = $loadedEvent->attendee
             ->filter('user_type', Calendar_Model_Attender::USERTYPE_GROUPMEMBER)
             ->filter('user_id', $newUser->contact_id);
-        $this->assertEquals(0, count($user), 'added user is attender of event, but should be');
+        $this->assertEquals(0, count($user), 'added user is attender of event, but should be (after deleting user)');
     }
     
     /**
@@ -850,7 +850,6 @@ class Calendar_Controller_EventTests extends Calendar_TestCase
         $this->assertEquals('2009-04-30 13:30:00', Calendar_Model_Rrule::getRruleFromString($updatedEvent->rrule)->until->get(Tinebase_Record_Abstract::ISO8601LONG), 'until in rrule must not be changed');
         $this->assertEquals('2009-04-30 13:30:00', $updatedEvent->rrule_until->get(Tinebase_Record_Abstract::ISO8601LONG), 'rrule_until must not be changed');
         
-        sleep(1); // wait for modlog
         $updatedEvent->dtstart->subHour(5);
         $updatedEvent->dtend->subHour(5);
         $secondUpdatedEvent = $this->_controller->update($updatedEvent);
@@ -859,6 +858,9 @@ class Calendar_Controller_EventTests extends Calendar_TestCase
         $this->assertEquals('2009-04-08 13:00:00', substr($secondUpdatedException->recurid, -19), 'failed to update persistent exception (sub)');
     }
     
+    /**
+     * testUpdateRecurDtstartOverDst
+     */
     public function testUpdateRecurDtstartOverDst()
     {
         // note: 2009-03-29 Europe/Berlin switched to DST
@@ -898,7 +900,7 @@ class Calendar_Controller_EventTests extends Calendar_TestCase
         $until->addDay(5); //08
         
         $currentPersistentEvent = $this->_controller->get($persistentEvent);
-        $persistentEvent->last_modified_time = $currentPersistentEvent->last_modified_time;
+        $persistentEvent->seq = 2; // satisfy modlog
         $updatedPersistenEvent = $this->_controller->update($persistentEvent);
         
         $persistentEvents = $this->_controller->search(new Calendar_Model_EventFilter(array(
@@ -906,7 +908,6 @@ class Calendar_Controller_EventTests extends Calendar_TestCase
             array('field' => 'uid', 'operator' => 'equals', 'value' => $persistentEvent->uid)
         )));
         
-        //print_r($persistentEvents->toArray());
         // we don't 'see' the persistent exception from 28/
         $this->assertEquals(2, count($persistentEvents));
                 
index 35219db..0009d1a 100644 (file)
@@ -158,7 +158,7 @@ class Calendar_Controller_MSEventFacadeTest extends Calendar_TestCase
             $alarms->setId(NULL);
         }
         
-        $this->_fixConcurrencyTimestamp($event);
+        $this->_fixConcurrency($event);
         $event = $this->_uit->update($event);
         $this->_assertTestEvent($event);
         
@@ -179,13 +179,13 @@ class Calendar_Controller_MSEventFacadeTest extends Calendar_TestCase
     }
     
     /**
-     * adjusts last_modified_time for event to prevent concurrency errors
+     * adjusts seq for event to prevent concurrency errors
      * 
      * @param Calendar_Model_Event $event
      */
-    protected function _fixConcurrencyTimestamp($event)
+    protected function _fixConcurrency($event)
     {
-        $event->last_modified_time = ($event->exdate && count($event->exdate) > 1) ? $event->exdate[1]->last_modified_time : Tinebase_DateTime::now();
+        $event->seq = 2;
     }
     
     /**
@@ -219,7 +219,7 @@ class Calendar_Controller_MSEventFacadeTest extends Calendar_TestCase
     {
         $event = $this->testCreate();
 
-        $this->_fixConcurrencyTimestamp($event);
+        $this->_fixConcurrency($event);
         $event->exdate = NULL;
         $updatedEvent = $this->_uit->update($event);
         
@@ -245,7 +245,7 @@ class Calendar_Controller_MSEventFacadeTest extends Calendar_TestCase
         $newDeletedInstance->is_deleted = TRUE;
         $event->exdate->addRecord($newDeletedInstance);
         
-        $this->_fixConcurrencyTimestamp($event);
+        $this->_fixConcurrency($event);
         $updatedEvent = $this->_uit->update($event);
         
         $this->assertEquals(4, $updatedEvent->exdate->count());
@@ -260,7 +260,7 @@ class Calendar_Controller_MSEventFacadeTest extends Calendar_TestCase
         $persistentException->dtend->addHour(2);
         $persistentException->summary = 'updated exception';
         
-        $this->_fixConcurrencyTimestamp($event);
+        $this->_fixConcurrency($event);
         $updatedEvent = $this->_uit->update($event);
         
         $this->assertEquals(2, $updatedEvent->exdate->count());
@@ -305,7 +305,7 @@ class Calendar_Controller_MSEventFacadeTest extends Calendar_TestCase
         $updatedAlarm = $updatedEvent->exdate[0]->alarms->getFirstRecord();
         
         $diff = $persistentAlarm->diff($updatedAlarm);
-        $this->assertTrue(empty($diff));
+        $this->assertTrue($diff->isEmpty());
     }
     
     public function testAttendeeStatusUpdate()
@@ -353,7 +353,7 @@ class Calendar_Controller_MSEventFacadeTest extends Calendar_TestCase
     
     /**
      * sclever declines event exception.
-     * => from her iTIP perspective, with the filter, this is an fallout than
+     * => from her iTIP perspective, with the filter, this is an fallout
      */
     public function testPerspectiveExceptionFallout()
     {
@@ -381,14 +381,14 @@ class Calendar_Controller_MSEventFacadeTest extends Calendar_TestCase
                 )
         ))));
         
-        $this->_fixConcurrencyTimestamp($event);
+        $this->_fixConcurrency($event);
         $event = $this->_uit->update($event);
         
         $event = $this->_uit->get($event->getId());
         $this->_uit->setCalendarUser($currUser);
         
         $persistentException = $event->exdate->filter('is_deleted', 0)->getFirstRecord();
-        $this->assertNull($persistentException);
+        $this->assertNull($persistentException, 'exdate without sclever should be marked as deleted: ' . (($persistentException) ? print_r($persistentException->toArray()) : ''));
     }
     
     public function testMissingEmailAttendee()
index d6e4d5c..0db1536 100644 (file)
@@ -395,7 +395,6 @@ class Calendar_Controller_RecurTest extends Calendar_TestCase
         ));
         
         $persistentEvent = $this->_controller->create($event);
-        sleep(1); // wait for modlog
         
         $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
         $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($persistentEvent, $exceptions, $from, $until);
index 1dffbb1..7360b1c 100644 (file)
@@ -89,7 +89,7 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
      */
     protected function _convertHelper($filename)
     {
-        $vcalendar = $this->_getVCalendar($filename);
+        $vcalendar = Calendar_Frontend_WebDAV_EventTest::getVCalendar($filename);
         $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_GENERIC);
         $event = $converter->toTine20Model($vcalendar);
         
@@ -103,7 +103,7 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
      */
     public function testConvertToTine20ModelFromICloud()
     {
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../../Import/files/calendarserver_external_invitation.ics');
+        $vcalendar = Calendar_Frontend_WebDAV_EventTest::getVCalendar(dirname(__FILE__) . '/../../../Import/files/calendarserver_external_invitation.ics');
         $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_GENERIC);
         $event = $converter->toTine20Model($vcalendar);
     
@@ -124,7 +124,7 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
      */
     public function testConvertToTine20ModelFromLotusNotes()
     {
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../../Import/files/lotusnotes_external_invitation.ics');
+        $vcalendar = Calendar_Frontend_WebDAV_EventTest::getVCalendar(dirname(__FILE__) . '/../../../Import/files/lotusnotes_external_invitation.ics');
         $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_GENERIC);
         $event = $converter->toTine20Model($vcalendar);
     
@@ -143,7 +143,7 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
     */
     public function testConvertToTine20ModelWithBadTZ()
     {
-        $vcalendarStream = $this->_getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning_badTZ.ics', 'r');
+        $vcalendarStream = Calendar_Frontend_WebDAV_EventTest::getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning_badTZ.ics', 'r');
         $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_GENERIC);
         $event = $converter->toTine20Model($vcalendarStream);
         
@@ -157,13 +157,12 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
      */
     public function testConvertToTine20ModelWithGroupInvitation()
     {
-        $smtpConfig = Tinebase_Config::getInstance()->getConfigAsArray(Tinebase_Model_Config::SMTP, 'Tinebase');
-        
+        $smtpConfig = Tinebase_Config::getInstance()->get(Tinebase_Model_Config::SMTP, new Tinebase_Config_Struct())->toArray();
         if (!isset($smtpConfig['primarydomain'])) {
             $this->markTestSkipped('no primary smtp domain configured');
         }
         
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning.ics');
+        $vcalendar = Calendar_Frontend_WebDAV_EventTest::getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning.ics');
     
         $vcalendar = preg_replace('/lars@kneschke.de/', 'users@' . $smtpConfig['primarydomain'], $vcalendar);
     
@@ -183,7 +182,7 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
     */
     public function testConvertToTine20ModelWithStatus()
     {
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning.ics', 'r');
+        $vcalendar = Calendar_Frontend_WebDAV_EventTest::getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning.ics', 'r');
         $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_GENERIC);
         
         $vcalendar = str_replace('LOCATION:Hamburg', 'STATUS:CONFIRMED', $vcalendar);
@@ -205,7 +204,7 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
      */
     public function _testConvertFromIcalToTine20Model()
     {
-        $vcalendarStream = $this->_getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning.ics', 'r');
+        $vcalendarStream = Calendar_Frontend_WebDAV_EventTest::getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning.ics', 'r');
     
         $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_GENERIC);
     
@@ -230,7 +229,7 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
      */
     public function testConvertAllDayEventToTine20Model()
     {
-        $vcalendarStream = $this->_getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning_allday.ics', 'r');
+        $vcalendarStream = Calendar_Frontend_WebDAV_EventTest::getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning_allday.ics', 'r');
     
         $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_GENERIC);
     
@@ -255,7 +254,7 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
      */
     public function testConvertRepeatingDailyEventToTine20Model()
     {
-        $vcalendarStream = $this->_getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning_repeating_daily.ics', 'r');
+        $vcalendarStream = Calendar_Frontend_WebDAV_EventTest::getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning_repeating_daily.ics', 'r');
     
         $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_GENERIC);
     
@@ -280,7 +279,7 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
      */
     public function testConvertRepeatingAllDayDailyEventToTine20Model()
     {
-        $vcalendarStream = $this->_getVCalendar(dirname(__FILE__) . '/../../../Import/files/apple_caldendar_repeating_allday.ics', 'r');
+        $vcalendarStream = Calendar_Frontend_WebDAV_EventTest::getVCalendar(dirname(__FILE__) . '/../../../Import/files/apple_caldendar_repeating_allday.ics', 'r');
     
         $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_GENERIC);
     
@@ -335,7 +334,7 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
     {
         $event = $this->testConvertRepeatingDailyEventToTine20Model();
         
-        $vcalendarStream = $this->_getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning_repeating_daily.ics', 'r');
+        $vcalendarStream = Calendar_Frontend_WebDAV_EventTest::getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning_repeating_daily.ics', 'r');
     
         $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_GENERIC);
         
@@ -358,7 +357,7 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
      */
     public function testConvertToTine20ModelWithUpdate()
     {
-        $vcalendarStream = $this->_getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning.ics', 'r');
+        $vcalendarStream = Calendar_Frontend_WebDAV_EventTest::getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning.ics', 'r');
         
         $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_GENERIC);
         
@@ -367,7 +366,7 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
         // status_authkey must be kept after second convert
         $event->attendee[0]->quantity = 10;
         
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning.ics');
+        $vcalendar = Calendar_Frontend_WebDAV_EventTest::getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning.ics');
         // remove alarm part from vcalendar
         $vcalendar = preg_replace('/BEGIN:VALARM.*END:VALARM(\n|\r\n)/s', null, $vcalendar);
         
@@ -564,7 +563,7 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
     
     public function testConvertToTine20ModelWithCustomAlarm()
     {
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../../Import/files/event_with_custom_alarm.ics');
+        $vcalendar = Calendar_Frontend_WebDAV_EventTest::getVCalendar(dirname(__FILE__) . '/../../../Import/files/event_with_custom_alarm.ics');
         
         $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_GENERIC);
         
@@ -579,21 +578,6 @@ class Calendar_Convert_Event_VCalendar_GenericTest extends PHPUnit_Framework_Tes
         $this->assertEquals('2012-02-14 17:00:00', $alarm->alarm_time->toString());
     }
     
-   /**
-    * return vcalendar as string and replace organizers email address with emailaddess of current user
-    *
-    * @param string $_filename  file to open
-    * @return string
-    */
-    protected function _getVCalendar($_filename)
-    {
-        $vcalendar = file_get_contents($_filename);
-    
-        $vcalendar = preg_replace('/l.kneschke@metaway\n s.de/', Tinebase_Core::getUser()->accountEmailAddress, $vcalendar);
-    
-        return $vcalendar;
-    }
-
     /**
      * testConvertFromGoogleToTine20Model
      * 
index 00ede8c..80cf187 100644 (file)
@@ -4,7 +4,7 @@
  * 
  * @package     Calendar
  * @license     http://www.gnu.org/licenses/agpl.html
- * @copyright   Copyright (c) 2011-2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2011-2013 Metaways Infosystems GmbH (http://www.metaways.de)
  * @author      Lars Kneschke <l.kneschke@metaways.de>
  */
 
@@ -72,4 +72,19 @@ class Calendar_Convert_Event_VCalendar_ThunderbirdTest extends PHPUnit_Framework
         $this->assertEquals('l.kneschke@metaways.de',            $organizer->email);
         $this->assertGreaterThan(0, count($event->attendee->filter('user_id', $event->organizer)), 'Organizer must be attendee too');
     }
+
+    /**
+     * testXMozSnooze
+     * 
+     * @see 0007682: CalDav - Tine - Thunderbird - Palm Pre
+     */
+    public function testXMozSnooze()
+    {
+        $vcalendarStream = Calendar_Frontend_WebDAV_EventTest::getVCalendar(dirname(__FILE__) . '/../../../Import/files/lightning_snooze.ics');
+        $converter = Calendar_Convert_Event_VCalendar_Factory::factory(Calendar_Convert_Event_VCalendar_Factory::CLIENT_THUNDERBIRD);
+        
+        $event = $converter->toTine20Model($vcalendarStream);
+        $this->assertTrue(isset($event->attendee[0]->alarm_snooze_time));
+        $this->assertEquals('2013-04-12 06:24:46', $event->attendee[0]->alarm_snooze_time->toString());
+    }
 }
index 4ce6db7..e7dbd0c 100644 (file)
@@ -73,7 +73,7 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
             $_SERVER['HTTP_USER_AGENT'] = 'FooBar User Agent';
         }
         
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning.ics');
+        $vcalendar = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning.ics');
         
         $id = Tinebase_Record_Abstract::generateUID();
         $event = Calendar_Frontend_WebDAV_Event::create($this->objects['initialContainer'], "$id.ics", $vcalendar);
@@ -125,7 +125,7 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
         
         $existingEvent = $this->testCreateEventWithInternalOrganizer();
         $existingRecord = $existingEvent->getRecord();
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning.ics');
+        $vcalendar = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning.ics');
         
         $event = Calendar_Frontend_WebDAV_Event::create($this->objects['initialContainer'], $existingEvent->getRecord()->uid . '.ics', $vcalendar);
         
@@ -149,7 +149,7 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
             $_SERVER['HTTP_USER_AGENT'] = 'FooBar User Agent';
         }
     
-        $vcalendarStream = $this->_getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning_repeating_daily.ics');
+        $vcalendarStream = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning_repeating_daily.ics');
         
         $id = Tinebase_Record_Abstract::generateUID();
         $event = Calendar_Frontend_WebDAV_Event::create($this->objects['initialContainer'], "$id.ics", $vcalendarStream);
@@ -190,13 +190,13 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
         
         $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.21) Gecko/20110831 Lightning/1.0b2 Thunderbird/3.1.13';
         
-        $vcalendarStream = $this->_getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning_repeating_weekly.ics');
+        $vcalendarStream = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning_repeating_weekly.ics');
         $id = '353de608-4b50-41e6-9f6c-35889584fe8d';
         $event = Calendar_Frontend_WebDAV_Event::create($this->objects['initialContainer'], "$id.ics", $vcalendarStream);
         $existingEvent = $event->getRecord();
         
         // put exception
-        $vcalendarStreamException = $this->_getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning_repeating_weekly_exception.ics');
+        $vcalendarStreamException = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning_repeating_weekly_exception.ics');
         $event = new Calendar_Frontend_WebDAV_Event($this->objects['initialContainer'], $existingEvent);
         $event->put($vcalendarStreamException);
         
@@ -210,7 +210,7 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
     {
         $_SERVER['HTTP_USER_AGENT'] = 'CalendarStore/5.0 (1127); iCal/5.0 (1535); Mac OS X/10.7.1 (11B26)';
         
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../Import/files/event_with_persona_attendee.ics');
+        $vcalendar = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/event_with_persona_attendee.ics');
         
 //         $prefs = new Calendar_Preference();
 //         $prefs->setValueForUser(Calendar_Preference::DEFAULTCALENDAR, '', $this->_personas['pwulf']->getId());
@@ -228,7 +228,7 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
     {
         $_SERVER['HTTP_USER_AGENT'] = 'CalendarStore/5.0 (1127); iCal/5.0 (1535); Mac OS X/10.7.1 (11B26)';
         
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../Import/files/iphone.ics');
+        $vcalendar = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/iphone.ics');
         
         
         $id = Tinebase_Record_Abstract::generateUID();
@@ -247,14 +247,14 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
     {
         // create event in shared calendar test user is attendee
         $_SERVER['HTTP_USER_AGENT'] = 'CalendarStore/5.0 (1127); iCal/5.0 (1535); Mac OS X/10.7.1 (11B26)';
-        $vcalendarStream = $this->_getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning_repeating_daily.ics');
+        $vcalendarStream = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning_repeating_daily.ics');
         $id = Tinebase_Record_Abstract::generateUID();
         $event = Calendar_Frontend_WebDAV_Event::create($this->objects['sharedContainer'], "$id.ics", $vcalendarStream);
         
         // decline exception -> no implicit fallout as exception is still in initialContainer via displaycal
         $exception = $event->getRecord()->exdate->filter('is_deleted', 0)->getFirstRecord();
         $exception->attendee[0]->status = Calendar_Model_Attender::STATUS_DECLINED;
-        Calendar_Controller_Event::getInstance()->update($exception);
+        $updatedException = Calendar_Controller_Event::getInstance()->update($exception);
         $event = new Calendar_Frontend_WebDAV_Event($this->objects['initialContainer'], $event->getRecord()->getId());
         $vcalendar = stream_get_contents($event->get());
         $this->assertContains('DTSTART;VALUE=DATE-TIME;TZID=Europe/Berlin:20111008T130000', $vcalendar, 'exception must not be implicitly deleted');
@@ -262,10 +262,10 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
         // delete attendee from exception -> implicit fallout exception is not longer in displaycal
         $exception = $event->getRecord()->exdate->filter('is_deleted', 0)->getFirstRecord();
         $exception->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender');
-        Calendar_Controller_Event::getInstance()->update($exception);
+        $updatedException = Calendar_Controller_Event::getInstance()->update($exception);
         $event = new Calendar_Frontend_WebDAV_Event($this->objects['initialContainer'], $event->getRecord()->getId());
         $vcalendar = stream_get_contents($event->get());
-        $this->assertContains('EXDATE;VALUE=DATE-TIME:20111008T080000Z', $vcalendar, 'exception must be implicitly deleted');
+        $this->assertContains('EXDATE;VALUE=DATE-TIME:20111008T080000Z', $vcalendar, 'exception must be implicitly deleted from event ' . print_r($event->getRecord()->toArray(), TRUE));
         
         // save back event -> implicit delete must not be deleted on server
         $event->put($vcalendar);
@@ -417,7 +417,7 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
     {
         $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.21) Gecko/20110831 Lightning/1.0b2 Thunderbird/3.1.13';
         
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning.ics');
+        $vcalendar = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning.ics');
         
         $id = Tinebase_Record_Abstract::generateUID();
         $event = Calendar_Frontend_WebDAV_Event::create($this->objects['sharedContainer'], "$id.ics", $vcalendar);
@@ -444,12 +444,12 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
     {
         $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.21) Gecko/20110831 Lightning/1.0b2 Thunderbird/3.1.13';
         
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning.ics');
+        $vcalendar = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning.ics');
         
         $id = Tinebase_Record_Abstract::generateUID();
         $event = Calendar_Frontend_WebDAV_Event::create($this->objects['initialContainer'], "$id.ics", $vcalendar);
         
-        // move event origin to shared (origin and display where the same)
+        // move event origin to shared (origin and display were the same)
         Calendar_Frontend_WebDAV_Event::create($this->objects['sharedContainer'], "$id.ics", stream_get_contents($event->get()));
         $oldEvent = new Calendar_Frontend_WebDAV_Event($this->objects['initialContainer'], "$id.ics");
         $oldEvent->delete();
@@ -459,7 +459,7 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
         
         $ownAttendee = Calendar_Model_Attender::getOwnAttender($loadedEvent->getRecord()->attendee);
         $this->assertEquals($this->objects['initialContainer']->getId(), $ownAttendee->displaycontainer_id, 'display container must not change');
-        $this->assertEquals(Calendar_Model_Attender::STATUS_ACCEPTED, $ownAttendee->status, 'event must not be declined');
+        $this->assertEquals(Calendar_Model_Attender::STATUS_ACCEPTED, $ownAttendee->status, 'event must not be declined: ' . print_r($ownAttendee->toArray(), TRUE));
     }
     
     /**
@@ -469,7 +469,7 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
     {
         $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.21) Gecko/20110831 Lightning/1.0b2 Thunderbird/3.1.13';
         
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning.ics');
+        $vcalendar = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning.ics');
         
         $id = Tinebase_Record_Abstract::generateUID();
         $event = Calendar_Frontend_WebDAV_Event::create($this->objects['sharedContainer'], "$id.ics", $vcalendar);
@@ -501,7 +501,7 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
     {
         $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.21) Gecko/20110831 Lightning/1.0b2 Thunderbird/3.1.13';
         
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning.ics');
+        $vcalendar = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning.ics');
         
         $id = Tinebase_Record_Abstract::generateUID();
         $event = Calendar_Frontend_WebDAV_Event::create($this->objects['sharedContainer'], "$id.ics", $vcalendar);
@@ -541,7 +541,7 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
     {
         $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.21) Gecko/20110831 Lightning/1.0b2 Thunderbird/3.1.13';
         
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../Import/files/event_with_custom_alarm.ics');
+        $vcalendar = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/event_with_custom_alarm.ics');
         
         $id = Tinebase_Record_Abstract::generateUID();
         $event = Calendar_Frontend_WebDAV_Event::create($this->objects['sharedContainer'], "$id.ics", $vcalendar);
@@ -558,7 +558,7 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
     {
         $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.21) Gecko/20110831 Lightning/1.0b2 Thunderbird/3.1.13';
         
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../Import/files/event_with_custom_alarm.ics');
+        $vcalendar = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/event_with_custom_alarm.ics');
         
         $id = Tinebase_Record_Abstract::generateUID();
         $event = Calendar_Frontend_WebDAV_Event::create($this->objects['sharedContainer'], "$id.ics", $vcalendar);
@@ -590,7 +590,7 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
     {
         $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.21) Gecko/20110831 Lightning/1.0b2 Thunderbird/3.1.13';
         
-        $vcalendar = $this->_getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning.ics');
+        $vcalendar = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning.ics');
         
         $id = Tinebase_Record_Abstract::generateUID();
         $event = Calendar_Frontend_WebDAV_Event::create($this->objects['initialContainer'], "$id.ics", $vcalendar);
@@ -641,14 +641,14 @@ class Calendar_Frontend_WebDAV_EventTest extends Calendar_TestCase
      * @param string $_filename  file to open
      * @return string
      */
-    protected function _getVCalendar($_filename)
+    public static function getVCalendar($_filename)
     {
         $vcalendar = file_get_contents($_filename);
         
         $unittestUserEmail = Tinebase_Core::getUser()->accountEmailAddress;
         $vcalendar = preg_replace(
             array(
-                '/l.kneschke@metaway\n s.de/', 
+                '/l.kneschke@metaway\n s.de/',
                 '/unittest@\n tine20.org/',
                 '/un\n ittest@tine20.org/',
                 '/unittest@tine20.org/',
index e06080f..e13f53f 100644 (file)
@@ -101,7 +101,7 @@ class Calendar_Import_ICalTest extends Calendar_TestCase
     }
     
     /**
-     * test for gracefull shutdown if ical is malformated
+     * test for graceful shutdown if ical is malformatted
      */
     public function testImportHordeBroken()
     {
@@ -109,8 +109,12 @@ class Calendar_Import_ICalTest extends Calendar_TestCase
             'importContainerId' => $this->_testCalendar->getId(),
         ));
         
-        $this->setExpectedException('Calendar_Exception_IcalParser');
-        $importer->importFile(dirname(__FILE__) . '/files/horde_broken.ics');
+        try {
+            $importer->importFile(dirname(__FILE__) . '/files/horde_broken.ics');
+            $this->fail('expected Calendar_Exception_IcalParser');
+        } catch (Calendar_Exception_IcalParser $ceip) {
+            $this->assertEquals('Sabre_VObject_ParseException', get_class($ceip->getParseError()));
+        }
     }
     
     public function testImportOutlook12()
diff --git a/tests/tine20/Calendar/Import/files/lightning_snooze.ics b/tests/tine20/Calendar/Import/files/lightning_snooze.ics
new file mode 100644 (file)
index 0000000..e5934ad
--- /dev/null
@@ -0,0 +1,99 @@
+BEGIN:VCALENDAR
+
+PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
+
+VERSION:2.0
+
+BEGIN:VTIMEZONE
+
+TZID:Europe/Berlin
+
+X-LIC-LOCATION:Europe/Berlin
+
+BEGIN:DAYLIGHT
+
+TZOFFSETFROM:+0100
+
+TZOFFSETTO:+0200
+
+TZNAME:CEST
+
+DTSTART:19700329T020000
+
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
+
+END:DAYLIGHT
+
+BEGIN:STANDARD
+
+TZOFFSETFROM:+0200
+
+TZOFFSETTO:+0100
+
+TZNAME:CET
+
+DTSTART:19701025T030000
+
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+
+END:STANDARD
+
+END:VTIMEZONE
+
+BEGIN:VEVENT
+
+CREATED:20121016T163000Z
+
+LAST-MODIFIED:20130412T061946Z
+
+DTSTAMP:20130412T061946Z
+
+UID:947343558335652482543811918684669918465z
+
+SUMMARY:Basketball
+
+STATUS:CONFIRMED
+
+ORGANIZER;CN="Simpson, Bart";EMAIL=b.simpson@simpson-springfield.de:mailto:b.s
+
+ impson@simpson-springfield.de
+
+ATTENDEE;RSVP=FALSE;CN="Simpson, Bart";PARTSTAT=ACCEPTED;CUTYPE=INDIVIDUAL
+
+ ;ROLE=REQ-PARTICIPANT;EMAIL=unittest@tine20.org:mailto:unittest@tine20.org
+
+RRULE:FREQ=WEEKLY;UNTIL=20130313T175959Z;BYDAY=TU
+
+X-MOZ-LASTACK:20130412T061946Z
+
+DTSTART;TZID=Europe/Berlin:20121016T183000
+
+DTEND;TZID=Europe/Berlin:20121016T190000
+
+SEQUENCE:55
+
+CLASS:PUBLIC
+
+LOCATION:GYM ND
+
+TRANSP:OPAQUE
+
+X-TINE20-CONTAINER:11
+
+X-MOZ-SNOOZE-TIME-1363109400000000:20130412T062446Z
+
+X-MOZ-GENERATION:1
+
+BEGIN:VALARM
+
+ACTION:DISPLAY
+
+TRIGGER;VALUE=DURATION:-PT15M
+
+DESCRIPTION:Basketball
+
+END:VALARM
+
+END:VEVENT
+
+END:VCALENDAR
\ No newline at end of file
index 54ac766..650f7b5 100644 (file)
@@ -4,7 +4,7 @@
  * 
  * @package     Calendar
  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
- * @copyright   Copyright (c) 2009-2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2009-2013 Metaways Infosystems GmbH (http://www.metaways.de)
  * @author      Cornelius Weiss <c.weiss@metaways.de>
  */
 
@@ -49,13 +49,15 @@ class Calendar_JsonTests extends Calendar_TestCase
     
     /**
      * testCreateEvent
+     * 
+     * @param $now should the current date be used
      */
-    public function testCreateEvent()
+    public function testCreateEvent($now = FALSE)
     {
         $scleverDisplayContainerId = Tinebase_Core::getPreference('Calendar')->getValueForUser(Calendar_Preference::DEFAULTCALENDAR, $this->_personas['sclever']->getId());
         $contentSeqBefore = Tinebase_Container::getInstance()->getContentSequence($scleverDisplayContainerId);
         
-        $eventData = $this->_getEvent()->toArray();
+        $eventData = $this->_getEvent($now)->toArray();
         
         $tag = Tinebase_Tags::getInstance()->createTag(new Tinebase_Model_Tag(array(
             'name' => 'phpunit-' . substr(Tinebase_Record_Abstract::generateUID(), 0, 10),
@@ -84,7 +86,7 @@ class Calendar_JsonTests extends Calendar_TestCase
     
     public function testStripWindowsLinebreaks()
     {
-        $e = $this->_getEvent();
+        $e = $this->_getEvent(TRUE);
         $e->description = 'Hello my friend,' . chr(13) . chr(10) .'bla bla bla.'  . chr(13) . chr(10) .'good bye.';
         $persistentEventData = $this->_uit->saveEvent($e->toArray());
         $loadedEventData = $this->_uit->getEvent($persistentEventData['id']);
@@ -97,12 +99,8 @@ class Calendar_JsonTests extends Calendar_TestCase
     public function testCreateEventWithNonExistantAttender()
     {
         $testEmail = 'unittestnotexists@example.org';
-        $eventData = $this->_getEvent()->toArray();
-        $eventData['attendee'][] = array(
-            'user_id'        => $testEmail,
-            'user_type'      => Calendar_Model_Attender::USERTYPE_USER,
-            'role'           => Calendar_Model_Attender::ROLE_REQUIRED,
-        );
+        $eventData = $this->_getEvent(TRUE)->toArray();
+        $eventData['attendee'][] = $this->_getUserTypeAttender($testEmail);
         
         $persistentEventData = $this->_uit->saveEvent($eventData);
         $found = FALSE;
@@ -116,13 +114,28 @@ class Calendar_JsonTests extends Calendar_TestCase
     }
     
     /**
+     * get single attendee array
+     * 
+     * @param string $email
+     * @return array
+     */
+    protected function _getUserTypeAttender($email = 'unittestnotexists@example.org')
+    {
+        return array(
+            'user_id'        => $email,
+            'user_type'      => Calendar_Model_Attender::USERTYPE_USER,
+            'role'           => Calendar_Model_Attender::ROLE_REQUIRED,
+        );
+    }
+    
+    /**
      * test create event with alarm
      *
      * @todo add testUpdateEventWithAlarm
      */
     public function testCreateEventWithAlarm()
     {
-        $eventData = $this->_getEventWithAlarm()->toArray();
+        $eventData = $this->_getEventWithAlarm(TRUE)->toArray();
         $persistentEventData = $this->_uit->saveEvent($eventData);
         $loadedEventData = $this->_uit->getEvent($persistentEventData['id']);
         
@@ -173,7 +186,6 @@ class Calendar_JsonTests extends Calendar_TestCase
         $event->dtend->addHour(5);
         $event->description = 'are you kidding?';
         
-        
         $eventData = $event->toArray();
         foreach ($eventData['attendee'] as $key => $attenderData) {
             if ($eventData['attendee'][$key]['user_id'] != $this->_testUserContact->getId()) {
@@ -205,19 +217,33 @@ class Calendar_JsonTests extends Calendar_TestCase
      */
     public function testSearchEvents()
     {
-        $eventData = $this->testCreateEvent();
-        
-        $filter = array(
-            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_testCalendar->getId()),
-        );
+        $eventData = $this->testCreateEvent(TRUE); 
         
+        $filter = $this->_getEventFilterArray();
         $searchResultData = $this->_uit->searchEvents($filter, array());
         $resultEventData = $searchResultData['results'][0];
         
         $this->_assertJsonEvent($eventData, $resultEventData, 'failed to search event');
         return $searchResultData;
     }
-
+    
+    /**
+     * get filter array with container and period filter
+     * 
+     * @param string|int $containerId
+     * @return multitype:multitype:string Ambigous <number, multitype:>  multitype:string multitype:string
+     */
+    protected function _getEventFilterArray($containerId = NULL)
+    {
+        $containerId = ($containerId) ? $containerId : $this->_testCalendar->getId();
+        return array(
+            array('field' => 'container_id', 'operator' => 'equals', 'value' => $containerId),
+            array('field' => 'period', 'operator' => 'within', 'value' =>
+                array("from" => '2009-03-20 06:15:00', "until" => Tinebase_DateTime::now()->addDay(1)->toString())
+            )
+        );
+    }
+    
     /**
      * testSearchEvents with period filter
      * 
@@ -241,6 +267,24 @@ class Calendar_JsonTests extends Calendar_TestCase
         
         $this->_assertJsonEvent($eventData, $resultEventData, 'failed to search event');
     }
+    
+    /**
+     * #7688: Internal Server Error on calendar search
+     * 
+     * add period filter if none is given
+     * 
+     * https://forge.tine20.org/mantisbt/view.php?id=7688
+     */
+    public function testSearchEventsWithOutPeriodFilter()
+    {
+        $eventData = $this->testCreateRecurEvent();
+        $filter = array(array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_testCalendar->getId()));
+        
+        $searchResultData = $this->_uit->searchEvents($filter, array());
+        $returnedFilter = $searchResultData['filter'];
+        $this->assertEquals(2, count($returnedFilter), 'Two filters shoud have been returned!');
+        $this->assertTrue($returnedFilter[1]['field'] == 'period' || $returnedFilter[0]['field'] == 'period', 'One returned filter shoud be a period filter');
+    }
 
     /**
      * testSearchEvents with organizer = me filter
@@ -249,20 +293,19 @@ class Calendar_JsonTests extends Calendar_TestCase
      */
     public function testSearchEventsWithOrganizerMeFilter()
     {
-        $eventData = $this->testCreateEvent();
+        $eventData = $this->testCreateEvent(TRUE);
         
-        $filter = array(
-            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_testCalendar->getId()),
-            array('field' => 'organizer', 'operator' => 'equals', 'value' => Addressbook_Model_Contact::CURRENTCONTACT),
-        );
+        $filter = $this->_getEventFilterArray();
+        $filter[] = array('field' => 'organizer', 'operator' => 'equals', 'value' => Addressbook_Model_Contact::CURRENTCONTACT);
         
         $searchResultData = $this->_uit->searchEvents($filter, array());
         $resultEventData = $searchResultData['results'][0];
         $this->_assertJsonEvent($eventData, $resultEventData, 'failed to search event');
         
         // check organizer filter resolving
-        $this->assertTrue(is_array($searchResultData['filter'][1]['value']), 'organizer should be resolved: ' . print_r($searchResultData['filter'][1], TRUE));
-        $this->assertEquals(Tinebase_Core::getUser()->contact_id, $searchResultData['filter'][1]['value']['id']);
+        $organizerfilter = $searchResultData['filter'][2];
+        $this->assertTrue(is_array($organizerfilter['value']), 'organizer should be resolved: ' . print_r($organizerfilter, TRUE));
+        $this->assertEquals(Tinebase_Core::getUser()->contact_id, $organizerfilter['value']['id']);
     }
     
     /**
@@ -271,14 +314,10 @@ class Calendar_JsonTests extends Calendar_TestCase
      */
     public function testSearchEventsWithAlarm()
     {
-        $eventData = $this->_getEventWithAlarm()->toArray();
+        $eventData = $this->_getEventWithAlarm(TRUE)->toArray();
         $persistentEventData = $this->_uit->saveEvent($eventData);
         
-        $filter = array(
-            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_testCalendar->getId()),
-        );
-        
-        $searchResultData = $this->_uit->searchEvents($filter, array());
+        $searchResultData = $this->_uit->searchEvents($this->_getEventFilterArray(), array());
         $resultEventData = $searchResultData['results'][0];
         
         $this->_assertJsonEvent($persistentEventData, $resultEventData, 'failed to search event with alarm');
@@ -416,7 +455,7 @@ class Calendar_JsonTests extends Calendar_TestCase
             array('field' => 'period',       'operator' => 'within', 'value' => array('from' => $from, 'until' => $until)),
         );
         
-        $searchResultData = $this->_uit->searchEvents($filter, array());
+        $searchResultData = $this->_uit->searchEvents($filter, array('sort' => 'dtstart'));
         
         // we deleted one and cropped
         $this->assertEquals(3, count($searchResultData['results']));
@@ -427,6 +466,8 @@ class Calendar_JsonTests extends Calendar_TestCase
         }
         $this->assertTrue(array_key_exists('2009-04-01 06:00:00', $summaryMap));
         $this->assertEquals($persistentException['summary'], $summaryMap['2009-04-01 06:00:00']);
+        
+        return $searchResultData;
     }
     
     /**
@@ -505,7 +546,7 @@ class Calendar_JsonTests extends Calendar_TestCase
         $someRecurInstance['dtstart'] = '2009-04-08 10:00:00';
         $someRecurInstance['dtend']   = '2009-04-08 12:30:00';
         
-        $someRecurInstance['last_modified_time'] = $recurResult['creation_time'];
+        $someRecurInstance['seq'] = 2;
         $this->_uit->updateRecurSeries($someRecurInstance, FALSE, FALSE);
         
         $from = $recurSet[0]['dtstart'];
@@ -532,8 +573,8 @@ class Calendar_JsonTests extends Calendar_TestCase
         
         $fishings = array_keys($summaryMap, 'go fishing');
         $this->assertEquals(5, count($fishings));
-        foreach($fishings as $dtstart) {
-            $this->assertEquals('10:00:00', substr($dtstart, -8));
+        foreach ($fishings as $dtstart) {
+            $this->assertEquals('10:00:00', substr($dtstart, -8), 'all fishing events should start at 10:00');
         }
     }
     
@@ -589,15 +630,13 @@ class Calendar_JsonTests extends Calendar_TestCase
      */
     public function testMeAsAttenderFilter()
     {
-        $eventData = $this->testCreateEvent();
+        $eventData = $this->testCreateEvent(TRUE);
         
-        $filter = array(
-            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_testCalendar->getId()),
-            array('field' => 'attender'    , 'operator' => 'equals', 'value' => array(
-                'user_type' => Calendar_Model_Attender::USERTYPE_USER,
-                'user_id'   => Addressbook_Model_Contact::CURRENTCONTACT,
-            ))
-        );
+        $filter = $this->_getEventFilterArray();
+        $filter[] = array('field' => 'attender'    , 'operator' => 'equals', 'value' => array(
+            'user_type' => Calendar_Model_Attender::USERTYPE_USER,
+            'user_id'   => Addressbook_Model_Contact::CURRENTCONTACT,
+        ));
         
         $searchResultData = $this->_uit->searchEvents($filter, array());
         $resultEventData = $searchResultData['results'][0];
@@ -605,10 +644,14 @@ class Calendar_JsonTests extends Calendar_TestCase
         $this->_assertJsonEvent($eventData, $resultEventData, 'failed to filter for me as attender');
     }
     
+    /**
+     * testFreeBusyCleanup
+     */
     public function testFreeBusyCleanup()
     {
         // give fb grants from sclever
-        Tinebase_Container::getInstance()->setGrants($this->_personasDefaultCals['sclever'], new Tinebase_Record_RecordSet('Tinebase_Model_Grants', array(array(
+        $scleverCal = Tinebase_Container::getInstance()->getContainerById($this->_personasDefaultCals['sclever']);
+        Tinebase_Container::getInstance()->setGrants($scleverCal->getId(), new Tinebase_Record_RecordSet('Tinebase_Model_Grants', array(array(
             'account_id'    => $this->_personas['sclever']->getId(),
             'account_type'  => 'user',
             Tinebase_Model_Grants::GRANT_READ     => true,
@@ -621,38 +664,36 @@ class Calendar_JsonTests extends Calendar_TestCase
         ), array(
             'account_id'    => $this->_testUser->getId(),
             'account_type'  => 'user',
-            Tinebase_Model_Grants::GRANT_ADD      => true,
             Tinebase_Model_Grants::GRANT_FREEBUSY => true,
         ))), TRUE);
         
-        $eventData = $this->testCreateEvent();
-        $eventData['container_id'] = $this->_personasDefaultCals['sclever']->getId();
+        Tinebase_Core::set(Tinebase_Core::USER, $this->_personas['sclever']);
+        $eventData = $this->_getEvent()->toArray();
+        unset($eventData['organizer']);
+        $eventData['container_id'] = $scleverCal->getId();
         $eventData['attendee'] = array(array(
             'user_id' => $this->_personasContacts['sclever']->getId()
         ));
         $eventData['organizer'] = $this->_personasContacts['sclever']->getId();
+        $eventData = $this->_uit->saveEvent($eventData);
+        $filter = $this->_getEventFilterArray($this->_personasDefaultCals['sclever']->getId());
+        $searchResultData = $this->_uit->searchEvents($filter, array());
+        $this->assertTrue(! empty($searchResultData['results']), 'expected event in search result (search by sclever): ' 
+            . print_r($eventData, TRUE) . 'search filter: ' . print_r($filter, TRUE));
         
-        try {
-            $eventData = $this->_uit->saveEvent($eventData);
-        } catch (Exception $e) {
-            // add but not read
-        }
-        
-        $filter = array(
-            array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_personasDefaultCals['sclever']->getId()),
-        );
-        
+        Tinebase_Core::set(Tinebase_Core::USER, $this->_testUser);
         $searchResultData = $this->_uit->searchEvents($filter, array());
+        $this->assertTrue(! empty($searchResultData['results']), 'expected (freebusy cleanup) event in search result: ' 
+            . print_r($eventData, TRUE) . 'search filter: ' . print_r($filter, TRUE));
         $eventData = $searchResultData['results'][0];
         
-        $this->assertFalse(array_key_exists('summary', $eventData), 'summary not empty');
+        $this->assertFalse(array_key_exists('summary', $eventData), 'summary not empty: ' . print_r($eventData, TRUE));
         $this->assertFalse(array_key_exists('description', $eventData), 'description not empty');
         $this->assertFalse(array_key_exists('tags', $eventData), 'tags not empty');
         $this->assertFalse(array_key_exists('notes', $eventData), 'notes not empty');
         $this->assertFalse(array_key_exists('attendee', $eventData), 'attendee not empty');
         $this->assertFalse(array_key_exists('organizer', $eventData), 'organizer not empty');
         $this->assertFalse(array_key_exists('alarms', $eventData), 'alarms not empty');
-        
     }
     
     /**
@@ -705,7 +746,8 @@ class Calendar_JsonTests extends Calendar_TestCase
      * @param array $eventData
      * @param string $msg
      */
-    protected function _assertJsonEvent($expectedEventData, $eventData, $msg) {
+    protected function _assertJsonEvent($expectedEventData, $eventData, $msg)
+    {
         $this->assertEquals($expectedEventData['summary'], $eventData['summary'], $msg . ': failed to create/load event');
         
         // assert effective grants are set
@@ -780,4 +822,482 @@ class Calendar_JsonTests extends Calendar_TestCase
         $result = $this->_uit->searchEvents($filter, array());
         $this->assertEquals(0, $result['totalcount']);
     }
+    
+    /**
+     * testExdateDeleteAll
+     * 
+     * @see 0007382: allow to edit / delete the whole series / thisandfuture when editing/deleting recur exceptions
+     */
+    public function testExdateDeleteAll()
+    {
+        $events = $this->testCreateRecurException();
+        $exception = $this->_getException($events);
+        $this->_uit->deleteEvents(array($exception['id']), Calendar_Model_Event::RANGE_ALL);
+        
+        $search = $this->_uit->searchEvents($events['filter'], NULL);
+        $this->assertEquals(0, $search['totalcount'], 'all events should be deleted: ' . print_r($search,TRUE));
+    }
+    
+    /**
+     * get exception from event resultset
+     * 
+     * @param array $events
+     * @param integer $index (1 = picks first, 2 = picks second, ...)
+     * @return array|NULL
+     */
+    protected function _getException($events, $index = 1)
+    {
+        $event = NULL;
+        $found = 0;
+        foreach ($events['results'] as $event) {
+            if (! empty($event['recurid'])) {
+                $found++;
+                if ($index === $found) {
+                    return $event;
+                }
+            }
+        }
+        
+        return $event;
+    }
+    
+    /**
+     * testExdateDeleteThis
+     * 
+     * @see 0007382: allow to edit / delete the whole series / thisandfuture when editing/deleting recur exceptions
+     */
+    public function testExdateDeleteThis()
+    {
+        $events = $this->testCreateRecurException();
+        $exception = $this->_getException($events);
+        $this->_uit->deleteEvents(array($exception['id']));
+        
+        $search = $this->_uit->searchEvents($events['filter'], NULL);
+        $this->assertEquals(2, $search['totalcount'], '2 events should remain: ' . print_r($search,TRUE));
+    }
+    
+    /**
+     * testExdateDeleteThisAndFuture
+     * 
+     * @see 0007382: allow to edit / delete the whole series / thisandfuture when editing/deleting recur exceptions
+     */
+    public function testExdateDeleteThisAndFuture()
+    {
+        $events = $this->testCreateRecurException();
+        $exception = $this->_getException($events, 1);
+        $this->_uit->deleteEvents(array($exception['id']), Calendar_Model_Event::RANGE_THISANDFUTURE);
+        
+        $search = $this->_uit->searchEvents($events['filter'], NULL);
+        $this->assertEquals(1, $search['totalcount'], '1 event should remain: ' . print_r($search,TRUE));
+    }
+    
+    /**
+     * assert grant handling
+     */
+    public function testSaveResource($grants = array('readGrant' => true,'editGrant' => true))
+    {
+        $resoureData = array(
+            'name'  => Tinebase_Record_Abstract::generateUID(),
+            'email' => Tinebase_Record_Abstract::generateUID() . '@unittest.com',
+            'grants' => array(array_merge($grants, array(
+                'account_id' => Tinebase_Core::getUser()->getId(),
+                'account_type' => 'user'
+            )))
+        );
+        
+        $resoureData = $this->_uit->saveResource($resoureData);
+        $this->assertTrue(is_array($resoureData['grants']), 'grants are not resolved');
+        
+        return $resoureData;
+    }
+    
+    /**
+     * assert only resources with read grant are returned if the user has no manage right
+     */
+    public function testSearchResources()
+    {
+        $readableResoureData = $this->testSaveResource();
+        $nonReadableResoureData = $this->testSaveResource(array());
+        
+        $filer = array(
+            array('field' => 'name', 'operator' => 'in', 'value' => array(
+                $readableResoureData['name'],
+                $nonReadableResoureData['name'],
+            ))
+        );
+        
+        $searchResultManager = $this->_uit->searchResources($filer, array());
+        $this->assertEquals(2, count($searchResultManager['results']), 'with manage grants all records should be found');
+        
+        // steal manage right and reactivate container checks
+        Tinebase_Acl_Roles::getInstance()->deleteAllRoles();
+        Calendar_Controller_Resource::getInstance()->doContainerACLChecks(TRUE);
+        
+        $searchResult = $this->_uit->searchResources($filer, array());
+        $this->assertEquals(1, count($searchResult['results']), 'without manage grants only one record should be found');
+    }
+    
+    /**
+     * assert status authkey with editGrant
+     * assert stauts can be set with editGrant
+     * assert stauts can't be set without editGrant
+     */
+    public function testResourceAttendeeGrants()
+    {
+        $editableResoureData = $this->testSaveResource();
+        $nonEditableResoureData = $this->testSaveResource(array('readGrant'));
+        
+        $event = $this->_getEvent(TRUE);
+        $event->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(
+            array(
+                'user_type'  => Calendar_Model_Attender::USERTYPE_RESOURCE,
+                'user_id'    => $editableResoureData['id'],
+                'status'     => Calendar_Model_Attender::STATUS_ACCEPTED
+            ),
+            array(
+                'user_type'  => Calendar_Model_Attender::USERTYPE_RESOURCE,
+                'user_id'    => $nonEditableResoureData['id'],
+                'status'     => Calendar_Model_Attender::STATUS_ACCEPTED
+            )
+        ));
+        
+        $persistentEventData = $this->_uit->saveEvent($event->toArray());
+        
+        $attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', $persistentEventData['attendee']);
+        $this->assertEquals(1, count($attendee->filter('status', Calendar_Model_Attender::STATUS_ACCEPTED)), 'one accepted');
+        $this->assertEquals(1, count($attendee->filter('status', Calendar_Model_Attender::STATUS_NEEDSACTION)), 'one needs action');
+        
+        $this->assertEquals(1, count($attendee->filter('status_authkey', '/[a-z0-9]+/', TRUE)), 'one has authkey');
+        
+        $attendee->status = Calendar_Model_Attender::STATUS_TENTATIVE;
+        $persistentEventData['attendee'] = $attendee->toArray();
+        
+        $updatedEventData = $this->_uit->saveEvent($persistentEventData);
+        $attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', $updatedEventData['attendee']);
+        $this->assertEquals(1, count($attendee->filter('status', Calendar_Model_Attender::STATUS_TENTATIVE)), 'one tentative');
+    }
+
+    /**
+     * testExdateUpdateAllSummary
+     * 
+     * @see 0007690: allow to update the whole series / thisandfuture when updating recur exceptions
+     */
+    public function testExdateUpdateAllSummary()
+    {
+        $events = $this->testCreateRecurException();
+        $exception = $this->_getException($events, 1);
+        $exception['summary'] = 'new summary';
+        
+        $event = $this->_uit->saveEvent($exception, FALSE, Calendar_Model_Event::RANGE_ALL);
+        
+        $search = $this->_uit->searchEvents($events['filter'], NULL);
+        foreach ($search['results'] as $event) {
+            $this->assertEquals('new summary', $event['summary']);
+        }
+    }
+
+    /**
+     * testExdateUpdateAllDtStart
+     * 
+     * @see 0007690: allow to update the whole series / thisandfuture when updating recur exceptions
+     * 
+     * @todo finish
+     */
+    public function testExdateUpdateAllDtStart()
+    {
+        $events = $this->testCreateRecurException();
+        $exception = $this->_getException($events, 1);
+        $exception['dtstart'] = '2009-04-01 08:00:00';
+        $exception['dtend'] = '2009-04-01 08:15:00';
+        
+        $event = $this->_uit->saveEvent($exception, FALSE, Calendar_Model_Event::RANGE_ALL);
+        
+        $search = $this->_uit->searchEvents($events['filter'], NULL);
+        foreach ($search['results'] as $event) {
+            $this->assertContains('08:00:00', $event['dtstart'], 'wrong dtstart: ' . print_r($event, TRUE));
+            $this->assertContains('08:15:00', $event['dtend']);
+        }
+    }
+    
+    /**
+     * testExdateUpdateThis
+     * 
+     * @see 0007690: allow to update the whole series / thisandfuture when updating recur exceptions
+     */
+    public function testExdateUpdateThis()
+    {
+        $events = $this->testCreateRecurException();
+        $exception = $this->_getException($events, 1);
+        $exception['summary'] = 'exception';
+        
+        $event = $this->_uit->saveEvent($exception);
+        $this->assertEquals('exception', $event['summary']);
+        
+        // check for summary (only changed in one event)
+        $search = $this->_uit->searchEvents($events['filter'], NULL);
+        foreach ($search['results'] as $event) {
+            if (! empty($event['recurid']) && ! preg_match('/^fakeid/', $event['id'])) {
+                $this->assertEquals('exception', $event['summary'], 'summary not changed in exception: ' . print_r($event, TRUE));
+            } else {
+                $this->assertEquals('Wakeup', $event['summary']);
+            }
+        }
+    }
+
+    /**
+     * testExdateUpdateThisAndFuture
+     * 
+     * @see 0007690: allow to update the whole series / thisandfuture when updating recur exceptions
+     */
+    public function testExdateUpdateThisAndFuture()
+    {
+        $events = $this->testCreateRecurException();
+        $exception = $this->_getException($events, 1);
+        $exception['summary'] = 'new summary';
+        
+        $updatedEvent = $this->_uit->saveEvent($exception, FALSE, Calendar_Model_Event::RANGE_THISANDFUTURE);
+        $this->assertEquals('new summary', $updatedEvent['summary'], 'summary not changed in exception: ' . print_r($updatedEvent, TRUE));
+        
+        $search = $this->_uit->searchEvents($events['filter'], NULL);
+        foreach ($search['results'] as $event) {
+            if ($event['dtstart'] >= $updatedEvent['dtstart']) {
+                $this->assertEquals('new summary', $event['summary'], 'summary not changed in event: ' . print_r($event, TRUE));
+            } else {
+                $this->assertEquals('Wakeup', $event['summary']);
+            }
+        }
+    }
+
+    /**
+     * testExdateUpdateThisAndFutureWithRruleUntil
+     * 
+     * @see 0008244: "rrule until must not be before dtstart" when updating recur exception (THISANDFUTURE)
+     */
+    public function testExdateUpdateThisAndFutureWithRruleUntil()
+    {
+        $events = $this->testCreateRecurException();
+        
+        $exception = $this->_getException($events, 1);
+        $exception['dtstart'] = Tinebase_DateTime::now()->toString();
+        $exception['dtend'] = Tinebase_DateTime::now()->addHour(1)->toString();
+        
+        // move exception
+        $updatedEvent = $this->_uit->saveEvent($exception);
+        // try to update the whole series
+        $updatedEvent['summary'] = 'new summary';
+        $updatedEvent = $this->_uit->saveEvent($updatedEvent, FALSE, Calendar_Model_Event::RANGE_THISANDFUTURE);
+        
+        $this->assertEquals('new summary', $updatedEvent['summary'], 'summary not changed in event: ' . print_r($updatedEvent, TRUE));
+    }
+    
+    /**
+     * testExdateUpdateThisAndFutureRemoveAttendee
+     * 
+     * @see 0007690: allow to update the whole series / thisandfuture when updating recur exceptions
+     */
+    public function testExdateUpdateThisAndFutureRemoveAttendee()
+    {
+        $events = $this->testCreateRecurException();
+        $exception = $this->_getException($events, 1);
+        // remove susan from attendee
+        unset($exception['attendee'][0]);
+        
+        $updatedEvent = $this->_uit->saveEvent($exception, FALSE, Calendar_Model_Event::RANGE_THISANDFUTURE);
+        $this->assertEquals(1, count($updatedEvent['attendee']), 'attender not removed from exception: ' . print_r($updatedEvent, TRUE));
+        
+        $search = $this->_uit->searchEvents($events['filter'], NULL);
+        foreach ($search['results'] as $event) {
+            if ($event['dtstart'] >= $updatedEvent['dtstart']) {
+                $this->assertEquals(1, count($event['attendee']), 'attendee count mismatch: ' . print_r($event, TRUE));
+            } else {
+                $this->assertEquals(2, count($event['attendee']), 'attendee count mismatch: ' . print_r($event, TRUE));
+            }
+        }
+    }
+
+    /**
+     * testExdateUpdateAllAddAttendee
+     * 
+     * @see 0007690: allow to update the whole series / thisandfuture when updating recur exceptions
+     */
+    public function testExdateUpdateAllAddAttendee()
+    {
+        $events = $this->testCreateRecurException();
+        $exception = $this->_getException($events, 1);
+        // add new attender
+        $exception['attendee'][] = $this->_getUserTypeAttender();
+        
+        $updatedEvent = $this->_uit->saveEvent($exception, FALSE, Calendar_Model_Event::RANGE_ALL);
+        $this->assertEquals(3, count($updatedEvent['attendee']), 'attender not added to exception: ' . print_r($updatedEvent, TRUE));
+        
+        $search = $this->_uit->searchEvents($events['filter'], NULL);
+        foreach ($search['results'] as $event) {
+            $this->assertEquals(3, count($event['attendee']), 'attendee count mismatch: ' . print_r($event, TRUE));
+        }
+    }
+    
+    /**
+     * testExdateUpdateThisAndFutureChangeDtstart
+     * 
+     * @see 0007690: allow to update the whole series / thisandfuture when updating recur exceptions
+     */
+    public function testExdateUpdateThisAndFutureChangeDtstart()
+    {
+        $events = $this->testCreateRecurException();
+        $exception = $this->_getException($events, 1);
+        $exception['dtstart'] = '2009-04-01 08:00:00';
+        $exception['dtend'] = '2009-04-01 08:15:00';
+        
+        $updatedEvent = $this->_uit->saveEvent($exception, FALSE, Calendar_Model_Event::RANGE_THISANDFUTURE);
+        
+        $search = $this->_uit->searchEvents($events['filter'], NULL);
+        foreach ($search['results'] as $event) {
+            if ($event['dtstart'] >= $updatedEvent['dtstart']) {
+                $this->assertContains('08:00:00', $event['dtstart'], 'wrong dtstart: ' . print_r($event, TRUE));
+                $this->assertContains('08:15:00', $event['dtend']);
+            } else {
+                $this->assertContains('06:00:00', $event['dtstart'], 'wrong dtstart: ' . print_r($event, TRUE));
+                $this->assertContains('06:15:00', $event['dtend']);
+            }
+        }
+    }
+    
+    /**
+     * testExdateUpdateAllWithModlog
+     * - change base event, then update all
+     * 
+     * @see 0007690: allow to update the whole series / thisandfuture when updating recur exceptions
+     */
+    public function testExdateUpdateAllWithModlog()
+    {
+        $events = $this->testCreateRecurException();
+        $baseEvent = $events['results'][0];
+        $exception = $this->_getException($events, 1);
+        
+        $baseEvent['summary'] = 'Get up, lazyboy!';
+        $baseEvent = $this->_uit->saveEvent($baseEvent);
+        sleep(1);
+        
+        $exception['summary'] = 'new summary';
+        $updatedEvent = $this->_uit->saveEvent($exception, FALSE, Calendar_Model_Event::RANGE_ALL);
+        
+        $search = $this->_uit->searchEvents($events['filter'], NULL);
+        foreach ($search['results'] as $event) {
+            if ($event['dtstart'] == $updatedEvent['dtstart']) {
+                $this->assertEquals('new summary', $event['summary'], 'Recur&nb