Merge branch '2015.11' into 2015.11-develop
authorPhilipp Schüle <p.schuele@metaways.de>
Wed, 2 Aug 2017 11:33:21 +0000 (13:33 +0200)
committerPhilipp Schüle <p.schuele@metaways.de>
Wed, 2 Aug 2017 11:33:21 +0000 (13:33 +0200)
683 files changed:
.gitignore
tests/tine20/Addressbook/Export/DocTest.php
tests/tine20/Addressbook/Frontend/WebDAV/ContactTest.php
tests/tine20/Addressbook/Import/CsvTest.php
tests/tine20/Addressbook/Import/files/adb_import_csv_duplicate.xml
tests/tine20/Addressbook/Import/files/import_duplicate_1.csv
tests/tine20/Addressbook/Import/files/import_duplicate_1_cf.csv [new file with mode: 0644]
tests/tine20/Addressbook/Import/files/import_duplicate_2.csv
tests/tine20/Addressbook/Import/files/import_duplicate_2_cf.csv [new file with mode: 0644]
tests/tine20/Addressbook/JsonTest.php
tests/tine20/Addressbook/ListControllerTest.php
tests/tine20/AllServerTests.php
tests/tine20/AllTests.php
tests/tine20/Calendar/AllTests.php
tests/tine20/Calendar/Controller/EventNotificationsTests.php
tests/tine20/Calendar/Controller/EventTests.php
tests/tine20/Calendar/Controller/RecurTest.php
tests/tine20/Calendar/Export/DocTest.php [new file with mode: 0644]
tests/tine20/Calendar/JsonTests.php
tests/tine20/CoreData/AllTests.php [new file with mode: 0644]
tests/tine20/CoreData/JsonTest.php [new file with mode: 0644]
tests/tine20/Crm/ControllerTest.php
tests/tine20/Crm/Export/PdfTest.php
tests/tine20/Crm/JsonTest.php
tests/tine20/Crm/NotificationsTests.php
tests/tine20/Felamimail/Frontend/JsonTest.php
tests/tine20/Felamimail/files/multipart_alternative_pgp_inline.eml [new file with mode: 0644]
tests/tine20/Felamimail/files/openpgpencrypted.eml [new file with mode: 0644]
tests/tine20/Filemanager/Controller/DownloadLinkTests.php
tests/tine20/Filemanager/Frontend/JsonTests.php
tests/tine20/HumanResources/CliTests.php
tests/tine20/Inventory/AllTests.php
tests/tine20/Inventory/ControllerTest.php [new file with mode: 0644]
tests/tine20/Inventory/DoctrineModelTest.php [new file with mode: 0644]
tests/tine20/Inventory/JsonTest.php
tests/tine20/Phone/AllTests.php
tests/tine20/Phone/Call/ControllerTest.php [new file with mode: 0644]
tests/tine20/Phone/ControllerTest.php
tests/tine20/Phone/JsonTest.php
tests/tine20/Projects/JsonTest.php
tests/tine20/Sales/CustomersTest.php
tests/tine20/Sales/InvoiceControllerTests.php
tests/tine20/Sales/InvoiceJsonTests.php
tests/tine20/Sales/InvoiceTestCase.php
tests/tine20/Sales/JsonTest.php
tests/tine20/Sales/PurchaseInvoiceTest.php
tests/tine20/TestCase.php
tests/tine20/TestServer.php
tests/tine20/Timetracker/AbstractTest.php
tests/tine20/Timetracker/ControllerTest.php
tests/tine20/Timetracker/FilterTest.php
tests/tine20/Timetracker/JsonTest.php
tests/tine20/Tinebase/AllTests.php
tests/tine20/Tinebase/ApplicationTest.php
tests/tine20/Tinebase/Frontend/CliTest.php
tests/tine20/Tinebase/Frontend/HttpTest.php
tests/tine20/Tinebase/Frontend/Json/PersistentFilterTest.php
tests/tine20/Tinebase/Frontend/JsonTest.php
tests/tine20/Tinebase/Record/AllTests.php [new file with mode: 0644]
tests/tine20/Tinebase/Record/AutoRecord.php [deleted file]
tests/tine20/Tinebase/Record/ContainerTest.php [deleted file]
tests/tine20/Tinebase/Record/DummyRecord.php
tests/tine20/Tinebase/Record/PathTest.php [new file with mode: 0644]
tests/tine20/Tinebase/Record/PersistentObserverTest.php
tests/tine20/Tinebase/Record/RecordTest.php
tests/tine20/Tinebase/Relation/Backend/SqlTest.php
tests/tine20/Tinebase/Relation/RelationTest.php
tests/tine20/Tinebase/ScheduledImportTest.php
tests/tine20/Tinebase/Server/AllServerTests.php [deleted file]
tests/tine20/Tinebase/Server/JsonTests.php [new file with mode: 0644]
tine20/ActiveSync/Controller.php
tine20/Addressbook/Acl/Rights.php
tine20/Addressbook/Addressbook.jsb2
tine20/Addressbook/Backend/Ldap.php
tine20/Addressbook/Backend/List.php
tine20/Addressbook/Config.php
tine20/Addressbook/Controller.php
tine20/Addressbook/Controller/Contact.php
tine20/Addressbook/Controller/List.php
tine20/Addressbook/Controller/ListRole.php [new file with mode: 0644]
tine20/Addressbook/Convert/Contact/Json.php
tine20/Addressbook/Convert/Contact/VCard/Abstract.php
tine20/Addressbook/Convert/List/Json.php [new file with mode: 0644]
tine20/Addressbook/Event/ChangeList.php [new file with mode: 0644]
tine20/Addressbook/Event/DeleteList.php [new file with mode: 0644]
tine20/Addressbook/Export/Doc.php
tine20/Addressbook/Export/definitions/adb_default_doc.xml
tine20/Addressbook/Export/templates/addressbook_contact_letter.docx
tine20/Addressbook/Frontend/Json.php
tine20/Addressbook/Model/Contact.php
tine20/Addressbook/Model/ContactFilter.php
tine20/Addressbook/Model/List.php
tine20/Addressbook/Model/ListFilter.php
tine20/Addressbook/Model/ListMemberRole.php [new file with mode: 0644]
tine20/Addressbook/Model/ListRole.php [new file with mode: 0644]
tine20/Addressbook/Model/ListRoleFilter.php [new file with mode: 0644]
tine20/Addressbook/Model/ListRoleMemberFilter.php [new file with mode: 0644]
tine20/Addressbook/Setup/Initialize.php
tine20/Addressbook/Setup/Update/Release9.php [new file with mode: 0644]
tine20/Addressbook/Setup/setup.xml
tine20/Addressbook/css/Addressbook.css
tine20/Addressbook/js/Addressbook.js
tine20/Addressbook/js/AdminPanel.js [new file with mode: 0644]
tine20/Addressbook/js/ContactEditDialog.js
tine20/Addressbook/js/ContactGrid.js
tine20/Addressbook/js/ContactSearchCombo.js [moved from tine20/Addressbook/js/SearchCombo.js with 82% similarity]
tine20/Addressbook/js/ListEditDialog.js
tine20/Addressbook/js/ListGrid.js
tine20/Addressbook/js/ListMemberGridPanel.js [deleted file]
tine20/Addressbook/js/ListMemberRoleGridPanel.js [new file with mode: 0644]
tine20/Addressbook/js/ListMemberRoleLayerCombo.js [new file with mode: 0644]
tine20/Addressbook/js/ListRoleEditDialog.js [new file with mode: 0644]
tine20/Addressbook/js/ListRoleGridPanel.js [new file with mode: 0644]
tine20/Addressbook/js/ListRoleMemberFilterModel.js [new file with mode: 0644]
tine20/Addressbook/js/ListSearchCombo.js [new file with mode: 0644]
tine20/Addressbook/js/Model.js
tine20/Addressbook/translations/de.po
tine20/Admin/Controller/Customfield.php
tine20/Admin/Controller/Group.php
tine20/Admin/Frontend/Cli.php
tine20/Admin/Frontend/Json.php
tine20/Admin/Setup/Initialize.php
tine20/Admin/js/Admin.js
tine20/Admin/js/Applications.js
tine20/Admin/js/GroupEditDialog.js
tine20/Admin/js/Groups.js
tine20/Admin/js/RoleEditDialog.js
tine20/Admin/js/Roles.js
tine20/Admin/js/TagEditDialog.js
tine20/Admin/js/Tags.js
tine20/Admin/js/config/FieldManager.js
tine20/Admin/js/config/GridPanel.js
tine20/Admin/js/container/EditDialog.js
tine20/Admin/js/container/GridPanel.js
tine20/Admin/js/customfield/EditDialog.js
tine20/Admin/js/customfield/GridPanel.js
tine20/Admin/js/user/EditDialog.js
tine20/Admin/translations/de.po
tine20/Calendar/Backend/Sql.php
tine20/Calendar/Calendar.jsb2
tine20/Calendar/Config.php
tine20/Calendar/Controller.php
tine20/Calendar/Controller/Event.php
tine20/Calendar/Convert/Event/Json.php
tine20/Calendar/Export/DocSheet.php [new file with mode: 0644]
tine20/Calendar/Export/GenericTrait.php [moved from tine20/Calendar/Export/Abstract.php with 77% similarity]
tine20/Calendar/Export/Ods.php
tine20/Calendar/Export/definitions/cal_default_doc_sheet.xml [new file with mode: 0644]
tine20/Calendar/Export/definitions/cal_default_ods.xml
tine20/Calendar/Export/templates/SimpleDocSheet.docx [new file with mode: 0644]
tine20/Calendar/Frontend/Http.php
tine20/Calendar/Frontend/Json.php
tine20/Calendar/Model/Event.php
tine20/Calendar/Model/EventFilter.php
tine20/Calendar/Model/PeriodFilter.php
tine20/Calendar/Model/Resource.php
tine20/Calendar/Model/Rrule.php
tine20/Calendar/Preference.php
tine20/Calendar/Scheduler/Task.php [new file with mode: 0644]
tine20/Calendar/Setup/Initialize.php
tine20/Calendar/Setup/Update/Release9.php
tine20/Calendar/Setup/setup.xml
tine20/Calendar/css/Calendar.css
tine20/Calendar/css/daysviewpanel.css
tine20/Calendar/css/print.css
tine20/Calendar/js/AttendeeFilterGrid.js
tine20/Calendar/js/AttendeeGridPanel.js
tine20/Calendar/js/Calendar.js
tine20/Calendar/js/CalendarPanelSplitPlugin.js
tine20/Calendar/js/DaysView.js
tine20/Calendar/js/DaysViewEventUI.js [new file with mode: 0644]
tine20/Calendar/js/EventContextAttendeesItem.js
tine20/Calendar/js/EventDetailsPanel.js
tine20/Calendar/js/EventEditDialog.js
tine20/Calendar/js/EventUI.js
tine20/Calendar/js/ImportDialog.js
tine20/Calendar/js/MainScreenCenterPanel.js
tine20/Calendar/js/Model.js
tine20/Calendar/js/MonthView.js
tine20/Calendar/js/MonthViewEventUI.js [new file with mode: 0644]
tine20/Calendar/js/PerspectiveCombo.js
tine20/Calendar/js/Printer/DaysView.js
tine20/Calendar/js/Printer/EventRecord.js [new file with mode: 0644]
tine20/Calendar/js/ResourceEditDialog.js
tine20/Calendar/js/ResourcesGridPanel.js
tine20/Calendar/js/RrulePanel.js
tine20/Calendar/js/SearchCombo.js
tine20/Calendar/js/YearView.js
tine20/Calendar/translations/de.po
tine20/CoreData/Config.php [new file with mode: 0644]
tine20/CoreData/Controller.php [new file with mode: 0644]
tine20/CoreData/CoreData.jsb2 [new file with mode: 0644]
tine20/CoreData/Exception.php [new file with mode: 0644]
tine20/CoreData/Frontend/Cli.php [new file with mode: 0644]
tine20/CoreData/Frontend/Http.php [new file with mode: 0644]
tine20/CoreData/Frontend/Json.php [new file with mode: 0644]
tine20/CoreData/Model/CoreData.php [new file with mode: 0644]
tine20/CoreData/Preference.php [new file with mode: 0644]
tine20/CoreData/Setup/Initialize.php [new file with mode: 0644]
tine20/CoreData/Setup/setup.xml [new file with mode: 0644]
tine20/CoreData/css/CoreData.css [new file with mode: 0644]
tine20/CoreData/js/CoreData.js [new file with mode: 0644]
tine20/CoreData/js/Manager.js [new file with mode: 0644]
tine20/CoreData/js/TreePanel.js [new file with mode: 0644]
tine20/CoreData/js/WestPanel.js [new file with mode: 0644]
tine20/CoreData/translations/bg.po [new file with mode: 0644]
tine20/CoreData/translations/ca.po [new file with mode: 0644]
tine20/CoreData/translations/cs.po [new file with mode: 0644]
tine20/CoreData/translations/da.po [new file with mode: 0644]
tine20/CoreData/translations/de.po [new file with mode: 0644]
tine20/CoreData/translations/el_GR.po [new file with mode: 0644]
tine20/CoreData/translations/en.po [new file with mode: 0644]
tine20/CoreData/translations/en_AU.po [new file with mode: 0644]
tine20/CoreData/translations/en_NZ.po [new file with mode: 0644]
tine20/CoreData/translations/es.po [new file with mode: 0644]
tine20/CoreData/translations/es_MX.po [new file with mode: 0644]
tine20/CoreData/translations/et.po [new file with mode: 0644]
tine20/CoreData/translations/fa_IR.po [new file with mode: 0644]
tine20/CoreData/translations/fi.po [new file with mode: 0644]
tine20/CoreData/translations/fr.po [new file with mode: 0644]
tine20/CoreData/translations/hr_HR.po [new file with mode: 0644]
tine20/CoreData/translations/hu.po [new file with mode: 0644]
tine20/CoreData/translations/it.po [new file with mode: 0644]
tine20/CoreData/translations/ja.po [new file with mode: 0644]
tine20/CoreData/translations/ko.po [new file with mode: 0644]
tine20/CoreData/translations/ko_KR.po [new file with mode: 0644]
tine20/CoreData/translations/lt.po [new file with mode: 0644]
tine20/CoreData/translations/nb.po [new file with mode: 0644]
tine20/CoreData/translations/nl_NL.po [new file with mode: 0644]
tine20/CoreData/translations/pl.po [new file with mode: 0644]
tine20/CoreData/translations/pt_BR.po [new file with mode: 0644]
tine20/CoreData/translations/ro_RO.po [new file with mode: 0644]
tine20/CoreData/translations/ru.po [new file with mode: 0644]
tine20/CoreData/translations/sk.po [new file with mode: 0644]
tine20/CoreData/translations/sl.po [new file with mode: 0644]
tine20/CoreData/translations/template.pot [new file with mode: 0644]
tine20/Courses/Controller.php
tine20/Courses/js/AddMemberDialog.js
tine20/Courses/js/CourseEditDialog.js
tine20/Courses/js/Models.js
tine20/Crm/Backend/Lead.php
tine20/Crm/Config.php
tine20/Crm/Controller.php
tine20/Crm/Controller/Lead.php
tine20/Crm/Crm.jsb2
tine20/Crm/Export/Csv.php
tine20/Crm/Export/Helper.php
tine20/Crm/Export/Pdf.php
tine20/Crm/Frontend/Json.php
tine20/Crm/Import/Csv.php
tine20/Crm/Model/Config.php [deleted file]
tine20/Crm/Model/Lead.php
tine20/Crm/Model/LeadSource.php [new file with mode: 0644]
tine20/Crm/Model/LeadState.php [new file with mode: 0644]
tine20/Crm/Model/LeadType.php [new file with mode: 0644]
tine20/Crm/Setup/Initialize.php
tine20/Crm/Setup/Update/Release8.php
tine20/Crm/Setup/Update/Release9.php [new file with mode: 0644]
tine20/Crm/Setup/setup.xml
tine20/Crm/js/AdminPanel.js
tine20/Crm/js/Crm.js
tine20/Crm/js/LeadEditDialog.js
tine20/Crm/js/LeadGridDetailsPanel.js
tine20/Crm/js/LeadGridPanel.js
tine20/Crm/js/LeadSource.js [deleted file]
tine20/Crm/js/LeadSourceFilterModel.js [deleted file]
tine20/Crm/js/LeadState.js [deleted file]
tine20/Crm/js/LeadStateFilterModel.js [deleted file]
tine20/Crm/js/LeadType.js [deleted file]
tine20/Crm/js/Model.js
tine20/ExampleApplication/Frontend/Cli.php
tine20/ExampleApplication/js/Example.js
tine20/Expressodriver/js/AdminPanel.js
tine20/Expressodriver/js/ExceptionHandler.js
tine20/Expressodriver/js/Expressodriver.js
tine20/Expressodriver/js/ExternalAdapterEditDialog.js
tine20/Expressodriver/js/GridContextMenu.js
tine20/Expressodriver/js/Model.js
tine20/Expressodriver/js/NodeGridPanel.js
tine20/Expressodriver/js/NodeTreePanel.js
tine20/Expressomail/Expressomail.jsb2
tine20/Expressomail/Setup/Initialize.php
tine20/Expressomail/js/AccountEditDialog.js
tine20/Expressomail/js/AclsEditDialog.js
tine20/Expressomail/js/AclsGrid.js
tine20/Expressomail/js/AddressbookGridPanelHook.js
tine20/Expressomail/js/ContactGrid.js
tine20/Expressomail/js/Expressomail.js
tine20/Expressomail/js/FolderSelectPanel.js
tine20/Expressomail/js/GridPanel.js
tine20/Expressomail/js/ImportEmlDialog.js
tine20/Expressomail/js/MessageEditDialog.js
tine20/Expressomail/js/Model.js
tine20/Expressomail/js/RecipientGrid.js
tine20/Expressomail/js/TreeContextMenu.js
tine20/Expressomail/js/editorplugins/Ext.ux.form.HtmlEditor.SpellChecker.js
tine20/Expressomail/js/editorplugins/Ext.ux.form.HtmlEditor.Table.js
tine20/Expressomail/js/editorplugins/Ext.ux.form.HtmlEditor.UploadImage.js
tine20/Expressomail/js/sieve/RuleEditDialog.js
tine20/Expressomail/js/sieve/RulesGridPanel.js
tine20/Felamimail/Controller.php
tine20/Felamimail/Controller/Account.php
tine20/Felamimail/Controller/Message.php
tine20/Felamimail/Controller/Message/Send.php
tine20/Felamimail/Felamimail.jsb2
tine20/Felamimail/Frontend/Json.php
tine20/Felamimail/Model/Account.php
tine20/Felamimail/Model/Message.php
tine20/Felamimail/Setup/Initialize.php
tine20/Felamimail/Setup/Update/Release9.php
tine20/Felamimail/Setup/setup.xml
tine20/Felamimail/css/Felamimail.css
tine20/Felamimail/js/AccountEditDialog.js
tine20/Felamimail/js/ComposeEditor.js
tine20/Felamimail/js/ContactGrid.js
tine20/Felamimail/js/Felamimail.js
tine20/Felamimail/js/FolderSelectPanel.js
tine20/Felamimail/js/GridDetailsPanel.js
tine20/Felamimail/js/GridPanel.js
tine20/Felamimail/js/GridPanelHook.js
tine20/Felamimail/js/MailvelopeHelper.js [new file with mode: 0644]
tine20/Felamimail/js/MessageEditDialog.js
tine20/Felamimail/js/Model.js
tine20/Felamimail/js/PGPDetailsPanel.js [new file with mode: 0644]
tine20/Felamimail/js/RecipientGrid.js
tine20/Felamimail/js/TreeContextMenu.js
tine20/Felamimail/js/sieve/RulesGridPanel.js
tine20/Felamimail/translations/de.po
tine20/Filemanager/Config.php [new file with mode: 0644]
tine20/Filemanager/Controller.php
tine20/Filemanager/Controller/DownloadLink.php
tine20/Filemanager/Frontend/Download.php
tine20/Filemanager/Model/DownloadLink.php
tine20/Filemanager/Setup/Initialize.php
tine20/Filemanager/js/DownloadLinkGridPanel.js
tine20/Filemanager/js/ExceptionHandler.js
tine20/Filemanager/js/Filemanager.js
tine20/Filemanager/js/GridContextMenu.js
tine20/Filemanager/js/Model.js
tine20/Filemanager/js/NodeGridPanel.js
tine20/Filemanager/js/NodeTreePanel.js
tine20/HumanResources/js/ContractDetailsPanel.js
tine20/HumanResources/js/ContractEditDialog.js
tine20/HumanResources/js/ExtraFreeTimeDetailsPanel.js
tine20/HumanResources/js/FreeTimeEditDialog.js
tine20/HumanResources/js/Models.js
tine20/Inventory/Controller.php
tine20/Inventory/Controller/InventoryItem.php
tine20/Inventory/Export/definitions/i_default_ods.xml
tine20/Inventory/Export/definitions/i_default_xls.xml
tine20/Inventory/Frontend/Json.php
tine20/Inventory/Import/definitions/inv_tine_import_csv.xml
tine20/Inventory/Model/InventoryItem.php
tine20/Inventory/Setup/Update/Release10.php [new file with mode: 0644]
tine20/Inventory/Setup/Update/Release9.php [new file with mode: 0644]
tine20/Inventory/Setup/setup.xml
tine20/Inventory/js/InventoryItemEditDialog.js
tine20/PRIVACY
tine20/Phone/Config.php [new file with mode: 0644]
tine20/Phone/Controller.php
tine20/Phone/Controller/Call.php
tine20/Phone/Frontend/Json.php
tine20/Phone/Model/Call.php
tine20/Phone/Model/CallFilter.php
tine20/Phone/Setup/Update/Release9.php [new file with mode: 0644]
tine20/Phone/Setup/setup.xml
tine20/Phone/js/Phone.js
tine20/Projects/Model/Project.php
tine20/Projects/js/Model.js
tine20/Projects/js/ProjectEditDialog.js
tine20/Sales/Controller/Invoice.php
tine20/Sales/Controller/PurchaseInvoice.php
tine20/Sales/Export/definitions/invoice_default_ods.xml
tine20/Sales/Frontend/Cli.php
tine20/Sales/Frontend/Json.php
tine20/Sales/Model/Contract.php
tine20/Sales/Model/Invoice.php
tine20/Sales/Model/PurchaseInvoice.php
tine20/Sales/Scheduler/Task.php
tine20/Sales/Setup/DemoData.php
tine20/Sales/Setup/Uninitialize.php [new file with mode: 0644]
tine20/Sales/Setup/Update/Release2.php
tine20/Sales/Setup/Update/Release9.php
tine20/Sales/Setup/setup.xml
tine20/Sales/css/Sales.css
tine20/Sales/js/AddressEditDialog.js
tine20/Sales/js/AdminPanel.js
tine20/Sales/js/BillingDateDialog.js
tine20/Sales/js/CopyAddressDialog.js
tine20/Sales/js/CustomerDetailsPanel.js
tine20/Sales/js/CustomerGridPanel.js
tine20/Sales/js/InvoiceEditDialog.js
tine20/Sales/js/InvoiceGridPanel.js
tine20/Sales/js/InvoicePositionGridPanel.js
tine20/Sales/js/ProductAggregateGridPanel.js
tine20/Sales/js/PurchaseInvoiceGridPanel.js
tine20/Sales/js/SupplierDetailsPanel.js
tine20/Sales/js/SupplierGridPanel.js
tine20/Sales/translations/de.po
tine20/Setup/Backend/Mysql.php
tine20/Setup/Backend/Schema/Index/Mysql.php
tine20/Setup/Backend/Schema/Table/Factory.php
tine20/Setup/Controller.php
tine20/Setup/Core.php
tine20/Setup/Exception/Import/SkipDataset.php [new file with mode: 0644]
tine20/Setup/Frontend/Cli.php
tine20/Setup/Import/Abstract.php [new file with mode: 0644]
tine20/Setup/Initialize.php
tine20/Setup/SchemaTool.php [new file with mode: 0644]
tine20/Setup/Uninitialize.php [new file with mode: 0644]
tine20/Setup/Update/Abstract.php
tine20/Setup/js/ConfigManagerPanel.js
tine20/Setup/js/EnvCheckGridPanel.js
tine20/Setup/js/MainScreen.js
tine20/Setup/js/Setup.js
tine20/Setup/js/TermsPanel.js
tine20/Setup/js/init.js
tine20/Setup/views/jsclient.php
tine20/SimpleFAQ/js/Model.js
tine20/Sipgate/js/AccountEditDialog.js
tine20/Sipgate/js/CallStateWindow.js
tine20/Sipgate/js/DialNumberDialog.js
tine20/Sipgate/js/LineGridPanel.js
tine20/Sipgate/js/Models.js
tine20/Sipgate/js/SearchAddressDialog.js
tine20/Sipgate/js/SmsEditDialog.js
tine20/Tasks/js/Models.js
tine20/Tasks/js/TaskEditDialog.js
tine20/Tasks/js/Tasks.js
tine20/Timetracker/Controller.php
tine20/Timetracker/Controller/Timeaccount.php
tine20/Timetracker/Controller/Timesheet.php
tine20/Timetracker/Convert/Timeaccount/Json.php [new file with mode: 0644]
tine20/Timetracker/Exception/ClosedTimeaccount.php [new file with mode: 0644]
tine20/Timetracker/Export/definitions/ts_default_ods.xml
tine20/Timetracker/Frontend/Json.php
tine20/Timetracker/Model/Timeaccount.php
tine20/Timetracker/Model/TimeaccountFilter.php
tine20/Timetracker/Model/Timesheet.php
tine20/Timetracker/Model/TimesheetFilter.php
tine20/Timetracker/Setup/DemoData.php
tine20/Timetracker/Setup/Import/Egw14.php
tine20/Timetracker/Timetracker.jsb2
tine20/Timetracker/js/DurationSlider.js
tine20/Timetracker/js/DurationSpinner.js
tine20/Timetracker/js/Models.js
tine20/Timetracker/js/TimeAccountBilledFilterModel.js
tine20/Timetracker/js/TimeAccountFilterModel.js
tine20/Timetracker/js/TimeaccountEditDialog.js
tine20/Timetracker/js/TimeaccountGridPanel.js
tine20/Timetracker/js/TimeaccountResponsibleFilterModel.js [new file with mode: 0644]
tine20/Timetracker/js/TimesheetEditDialog.js
tine20/Timetracker/js/TimesheetGridPanel.js
tine20/Timetracker/js/Timetracker.js
tine20/Timetracker/translations/de.po
tine20/Tinebase/ActionQueue.php
tine20/Tinebase/ActiveDirectory/DomainConfigurationTrait.php [new file with mode: 0644]
tine20/Tinebase/Application.php
tine20/Tinebase/Application/Controller.php [new file with mode: 0755]
tine20/Tinebase/Backend/Sql/Abstract.php
tine20/Tinebase/Config.php
tine20/Tinebase/Config/Abstract.php
tine20/Tinebase/Config/KeyField.php
tine20/Tinebase/Container.php
tine20/Tinebase/Controller.php
tine20/Tinebase/Controller/Abstract.php
tine20/Tinebase/Controller/Record/Abstract.php
tine20/Tinebase/Controller/Record/Grants.php
tine20/Tinebase/Controller/ScheduledImport.php
tine20/Tinebase/Convert/Json.php
tine20/Tinebase/Core.php
tine20/Tinebase/CustomField.php
tine20/Tinebase/Exception/Record/StillInUse.php [new file with mode: 0644]
tine20/Tinebase/Export/Abstract.php
tine20/Tinebase/Export/Richtext/Doc.php
tine20/Tinebase/Export/Spreadsheet/Abstract.php
tine20/Tinebase/FileSystem.php
tine20/Tinebase/Frontend/Cli.php
tine20/Tinebase/Frontend/Http.php
tine20/Tinebase/Frontend/Json.php
tine20/Tinebase/Frontend/Json/Abstract.php
tine20/Tinebase/Frontend/Json/Generic.php [new file with mode: 0644]
tine20/Tinebase/Group/ActiveDirectory.php
tine20/Tinebase/Group/Ldap.php
tine20/Tinebase/ImageHelper.php
tine20/Tinebase/Import/Abstract.php
tine20/Tinebase/Ldap.php
tine20/Tinebase/Mail.php
tine20/Tinebase/Model/Application.php
tine20/Tinebase/Model/ApplicationFilter.php
tine20/Tinebase/Model/Container.php
tine20/Tinebase/Model/CustomField/Config.php
tine20/Tinebase/Model/CustomField/ConfigFilter.php
tine20/Tinebase/Model/CustomField/Value.php
tine20/Tinebase/Model/Filter/Abstract.php
tine20/Tinebase/Model/Filter/CustomField.php
tine20/Tinebase/Model/Filter/FilterGroup.php
tine20/Tinebase/Model/Filter/Path.php [new file with mode: 0644]
tine20/Tinebase/Model/Image.php
tine20/Tinebase/Model/Import.php
tine20/Tinebase/Model/Note.php
tine20/Tinebase/Model/Path.php [new file with mode: 0644]
tine20/Tinebase/Model/PathFilter.php [new file with mode: 0644]
tine20/Tinebase/Model/Relation.php
tine20/Tinebase/Model/RelationFilter.php
tine20/Tinebase/Model/Tree/FileObjectFilter.php [new file with mode: 0644]
tine20/Tinebase/ModelConfiguration.php
tine20/Tinebase/Notes.php
tine20/Tinebase/Notification/Backend/Smtp.php
tine20/Tinebase/Path/Backend/Sql.php [new file with mode: 0644]
tine20/Tinebase/Record/Abstract.php
tine20/Tinebase/Record/DoctrineMappingDriver.php [new file with mode: 0644]
tine20/Tinebase/Record/Iterator.php
tine20/Tinebase/Record/Path.php [new file with mode: 0644]
tine20/Tinebase/Record/RecordSet.php
tine20/Tinebase/Record/Simple.php [new file with mode: 0644]
tine20/Tinebase/Relation/Backend/Sql.php
tine20/Tinebase/Relations.php
tine20/Tinebase/Scheduler/Task.php
tine20/Tinebase/Server/Json.php
tine20/Tinebase/Setup/DemoData/Abstract.php
tine20/Tinebase/Setup/Initialize.php
tine20/Tinebase/Setup/Update/Release0.php
tine20/Tinebase/Setup/Update/Release5.php
tine20/Tinebase/Setup/Update/Release8.php
tine20/Tinebase/Setup/Update/Release9.php
tine20/Tinebase/Setup/setup.xml
tine20/Tinebase/Tinebase.jsb2
tine20/Tinebase/User/Abstract.php
tine20/Tinebase/User/ActiveDirectory.php
tine20/Tinebase/View.php
tine20/Tinebase/css/SmallForms.css
tine20/Tinebase/css/Tinebase.css
tine20/Tinebase/css/ux/form/HtmlEditor.css
tine20/Tinebase/js/AboutDialog.js
tine20/Tinebase/js/AdminPanel.js
tine20/Tinebase/js/AppManager.js
tine20/Tinebase/js/AppTabsPanel.js
tine20/Tinebase/js/Application.js
tine20/Tinebase/js/ApplicationStarter.js
tine20/Tinebase/js/Container.js
tine20/Tinebase/js/CreditsScreen.js
tine20/Tinebase/js/ExceptionDialog.js
tine20/Tinebase/js/ExceptionHandler.js
tine20/Tinebase/js/LicenseScreen.js
tine20/Tinebase/js/LoginPanel.js
tine20/Tinebase/js/MainMenu.js
tine20/Tinebase/js/MainScreen.js
tine20/Tinebase/js/Models.js
tine20/Tinebase/js/PasswordChangeDialog.js
tine20/Tinebase/js/Tinebase.js [new file with mode: 0644]
tine20/Tinebase/js/common.js
tine20/Tinebase/js/data/Record.js
tine20/Tinebase/js/data/RecordProxy.js
tine20/Tinebase/js/extFixes.js
tine20/Tinebase/js/extInit.js
tine20/Tinebase/js/npm-shrinkwrap.json [new file with mode: 0644]
tine20/Tinebase/js/package.json [new file with mode: 0644]
tine20/Tinebase/js/prototypeTranslations.js
tine20/Tinebase/js/tineInit.js
tine20/Tinebase/js/ux/ConnectionStatus.js
tine20/Tinebase/js/ux/Date.js [new file with mode: 0644]
tine20/Tinebase/js/ux/Percentage.js
tine20/Tinebase/js/ux/PopupWindow.js
tine20/Tinebase/js/ux/PopupWindowManager.js
tine20/Tinebase/js/ux/Printer/Printer.js
tine20/Tinebase/js/ux/Printer/renderers/Base.js
tine20/Tinebase/js/ux/SearchField.js
tine20/Tinebase/js/ux/form/BooleanCombo.js [new file with mode: 0644]
tine20/Tinebase/js/ux/form/ComboBoxRecentsPlugin.js
tine20/Tinebase/js/ux/form/HtmlEditor.js
tine20/Tinebase/js/ux/form/ImageField.js
tine20/Tinebase/js/ux/form/LayerCombo.js
tine20/Tinebase/js/ux/grid/GroupingGridPlugin.js
tine20/Tinebase/js/ux/grid/PagingToolbar.js
tine20/Tinebase/js/ux/layout/cardLayoutHelper.js [new file with mode: 0644]
tine20/Tinebase/js/webpack.config.js [new file with mode: 0644]
tine20/Tinebase/js/widgets/ActivitiesGridPanel.js
tine20/Tinebase/js/widgets/ActivitiesPanel.js
tine20/Tinebase/js/widgets/ContentTypeTreePanel.js
tine20/Tinebase/js/widgets/CountryCombo.js
tine20/Tinebase/js/widgets/EditRecord.js
tine20/Tinebase/js/widgets/LangChooser.js
tine20/Tinebase/js/widgets/MainScreen.js
tine20/Tinebase/js/widgets/TimezoneChooser.js
tine20/Tinebase/js/widgets/VersionCheck.js
tine20/Tinebase/js/widgets/account/ChangeAccountAction.js
tine20/Tinebase/js/widgets/account/PickerGridPanel.js
tine20/Tinebase/js/widgets/container/CalDAVContainerPropertiesHookField.js
tine20/Tinebase/js/widgets/container/ContainerSelect.js
tine20/Tinebase/js/widgets/container/FilterModel.js
tine20/Tinebase/js/widgets/container/GrantsDialog.js
tine20/Tinebase/js/widgets/container/GrantsGrid.js
tine20/Tinebase/js/widgets/container/PropertiesDialog.js
tine20/Tinebase/js/widgets/container/TreePanel.js
tine20/Tinebase/js/widgets/customfields/EditDialogPlugin.js
tine20/Tinebase/js/widgets/customfields/Renderer.js
tine20/Tinebase/js/widgets/dialog/AddRelationsEditDialogPlugin.js
tine20/Tinebase/js/widgets/dialog/AddToRecordPanel.js
tine20/Tinebase/js/widgets/dialog/AdminPanel.js
tine20/Tinebase/js/widgets/dialog/AlarmPanel.js
tine20/Tinebase/js/widgets/dialog/AttachmentsGridPanel.js
tine20/Tinebase/js/widgets/dialog/CredentialsDialog.js
tine20/Tinebase/js/widgets/dialog/DuplicateMergeDialog.js
tine20/Tinebase/js/widgets/dialog/DuplicateResolveGridPanel.js
tine20/Tinebase/js/widgets/dialog/EditDialog.js
tine20/Tinebase/js/widgets/dialog/ExceptionHandlerDialog.js
tine20/Tinebase/js/widgets/dialog/ExportDialog.js
tine20/Tinebase/js/widgets/dialog/FileListDialog.js
tine20/Tinebase/js/widgets/dialog/ImportDialog.js
tine20/Tinebase/js/widgets/dialog/LinkPanel.js
tine20/Tinebase/js/widgets/dialog/MultiOptionsDialog.js
tine20/Tinebase/js/widgets/dialog/MultipleEditDialogPlugin.js
tine20/Tinebase/js/widgets/dialog/MultipleEditResultSummary.js
tine20/Tinebase/js/widgets/dialog/PreferencesDialog.js
tine20/Tinebase/js/widgets/dialog/PreferencesPanel.js
tine20/Tinebase/js/widgets/dialog/PreferencesTreePanel.js
tine20/Tinebase/js/widgets/dialog/SimpleImportDialog.js
tine20/Tinebase/js/widgets/dialog/SimpleRecordEditDialog.js [new file with mode: 0644]
tine20/Tinebase/js/widgets/dialog/WizardPanel.js
tine20/Tinebase/js/widgets/form/ConfigPanel.js
tine20/Tinebase/js/widgets/form/FieldManager.js [new file with mode: 0644]
tine20/Tinebase/js/widgets/form/FileUploadButton.js
tine20/Tinebase/js/widgets/form/RecordForm.js [new file with mode: 0644]
tine20/Tinebase/js/widgets/form/RecordPickerComboBox.js
tine20/Tinebase/js/widgets/form/RecordPickerManager.js
tine20/Tinebase/js/widgets/grid/BbarGridPanel.js
tine20/Tinebase/js/widgets/grid/DetailsPanel.js
tine20/Tinebase/js/widgets/grid/FileUploadGrid.js
tine20/Tinebase/js/widgets/grid/FilterModel.js
tine20/Tinebase/js/widgets/grid/FilterModelMultiSelect.js
tine20/Tinebase/js/widgets/grid/FilterPanel.js
tine20/Tinebase/js/widgets/grid/FilterStructureTreePanel.js
tine20/Tinebase/js/widgets/grid/FilterToolbar.js
tine20/Tinebase/js/widgets/grid/FilterToolbarQuickFilterPlugin.js
tine20/Tinebase/js/widgets/grid/ForeignRecordFilter.js
tine20/Tinebase/js/widgets/grid/GridPanel.js
tine20/Tinebase/js/widgets/grid/LinkGridPanel.js
tine20/Tinebase/js/widgets/grid/MonthFilter.js
tine20/Tinebase/js/widgets/grid/PickerFilter.js
tine20/Tinebase/js/widgets/grid/PickerGridLayerCombo.js [new file with mode: 0644]
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/ConfigField.js
tine20/Tinebase/js/widgets/keyfield/ConfigGrid.js
tine20/Tinebase/js/widgets/keyfield/Filter.js
tine20/Tinebase/js/widgets/keyfield/Store.js
tine20/Tinebase/js/widgets/mainscreen/WestPanel.js
tine20/Tinebase/js/widgets/path/renderer.js [new file with mode: 0644]
tine20/Tinebase/js/widgets/persistentfilter/EditPersistentFilterPanel.js
tine20/Tinebase/js/widgets/persistentfilter/PickerPanel.js
tine20/Tinebase/js/widgets/relation/FilterModel.js
tine20/Tinebase/js/widgets/relation/GenericPickerGridPanel.js
tine20/Tinebase/js/widgets/relation/PickerCombo.js
tine20/Tinebase/js/widgets/tags/TagCombo.js
tine20/Tinebase/js/widgets/tags/TagFilter.js
tine20/Tinebase/js/widgets/tags/TagToggleBox.js
tine20/Tinebase/js/widgets/tags/TagsMassAttachAction.js
tine20/Tinebase/js/widgets/tags/TagsMassDetachAction.js
tine20/Tinebase/js/widgets/tags/TagsPanel.js
tine20/Tinebase/js/widgets/tree/ContextMenu.js
tine20/Tinebase/js/widgets/tree/FilterPlugin.js
tine20/Tinebase/translations/de.po
tine20/Tinebase/views/includeJsAndCss.php
tine20/Tinebase/views/jsclient.php
tine20/Tinebase/views/postal.xwindow.php [new file with mode: 0644]
tine20/Voipmanager/Setup/DemoData.php
tine20/Voipmanager/js/MainScreen.js
tine20/Voipmanager/js/Models.js
tine20/Voipmanager/js/Snom/LocationGridPanel.js
tine20/Voipmanager/js/Voipmanager.js
tine20/build.xml
tine20/composer.json
tine20/composer.lock
tine20/images/list.png [new file with mode: 0644]
tine20/library/Store/store.bind.js
tine20/library/Store/store.compat.js
tine20/library/Store/store2.js
tine20/library/Zend/Http/Client/Adapter/Socket.php
tine20/library/addressparser.js/addressparser.js [new file with mode: 0644]
tine20/library/es6-promise/es6-promise.js [new file with mode: 0644]
tine20/library/zf1ext/Zend/Service/Tine20.php

index 94bc4bd..eb16ad4 100644 (file)
@@ -27,3 +27,4 @@ scripts/syncuuids/conf.php
 tine20/*/translations/*.mo
 tine20/.htaccess
 tine20/vendor
+tine20/Tinebase/js/node_modules*
index cfca71e..fca918c 100644 (file)
@@ -29,11 +29,16 @@ class Addressbook_Export_DocTest extends TestCase
         //  class name in /usr/local/share/tine20.git/tine20/vendor/phpoffice/phpword/src/PhpWord/TemplateProcessor.php
         //  on line 23
         if (PHP_VERSION_ID >= 70000) {
-            $this->markTestSkipped('FIXME in php7');
+            $this->markTestSkipped('FIXME 0011730: fix doc export for php7');
         }
 
+        // make sure definition is imported
+        $definitionFile = __DIR__ . '/../../../../tine20/Addressbook/Export/definitions/adb_default_doc.xml';
+        $app = Tinebase_Application::getInstance()->getApplicationByName('Addressbook');
+        Tinebase_ImportExportDefinition::getInstance()->updateOrCreateFromFilename($definitionFile, $app);
+
         $filter = new Addressbook_Model_ContactFilter(array(
-            array('field' => 'n_given', 'operator' => 'equals', 'value' => 'Robert')
+            array('field' => 'n_given', 'operator' => 'equals', 'value' => 'James')
         ));
         $doc = new Addressbook_Export_Doc($filter);
         $doc->generate();
@@ -43,4 +48,18 @@ class Addressbook_Export_DocTest extends TestCase
 
         $this->assertGreaterThan(0, filesize($tempfile));
     }
-}
\ No newline at end of file
+
+    // read and write sucks
+    public function _testReadWriteCycleSucks()
+    {
+        PhpWord\Settings::setTempDir(Tinebase_Core::getTempDir());
+
+        $source = str_replace('tests/tine20', 'tine20', __DIR__) . '/templates/addressbook_contact_letter.docx';
+        $phpWord = PhpWord\IOFactory::load($source);
+
+        $tempfile = tempnam(Tinebase_Core::getTempDir(), __METHOD__ . '_') . '.docx';
+        $writer = $phpWord->save($tempfile);
+
+        `open $tempfile`;
+    }
+}
index 17d5a8b..c203823 100644 (file)
@@ -4,7 +4,7 @@
  * 
  * @package     Addressbook
  * @license     http://www.gnu.org/licenses/agpl.html
- * @copyright   Copyright (c) 2011-2013 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2011-2016 Metaways Infosystems GmbH (http://www.metaways.de)
  * @author      Lars Kneschke <l.kneschke@metaways.de>
  */
 
@@ -105,8 +105,15 @@ class Addressbook_Frontend_WebDAV_ContactTest extends PHPUnit_Framework_TestCase
         $record = $contact->getRecord();
 
         $imgBlob = $record->getSmallContactImage();
-        $this->assertTrue(strlen($imgBlob) > 0);
-        $this->assertTrue(strlen($imgBlob) < Addressbook_Model_Contact::SMALL_PHOTO_SIZE);
+        $standardSize = strlen($imgBlob);
+        $this->assertTrue($standardSize > 0);
+        $this->assertTrue($standardSize < Addressbook_Model_Contact::SMALL_PHOTO_SIZE);
+
+        // test custom size
+        $imgBlob = $record->getSmallContactImage(Addressbook_Model_Contact::SMALL_PHOTO_SIZE / 8);
+        $this->assertTrue(strlen($imgBlob) < $standardSize, 'custom size error');
+
+        return $contact;
     }
 
     /**
index 2751301..7482e7d 100644 (file)
@@ -275,24 +275,50 @@ class Addressbook_Import_CsvTest extends ImportTestCase
      * testImportDuplicateResolve
      * 
      * @see 0009316: add duplicate resolving to cli import
+     *
+     * @param bool $withCustomfields
+     * @return array
      */
-    public function testImportDuplicateResolve()
+    public function testImportDuplicateResolve($withCustomfields = false)
     {
         $definition = $this->_getDefinitionFromFile('adb_import_csv_duplicate.xml');
         
-        $this->_filename = dirname(__FILE__) . '/files/import_duplicate_1.csv';
+        $this->_filename = dirname(__FILE__) . ($withCustomfields ? '/files/import_duplicate_1_cf.csv' : '/files/import_duplicate_1.csv');
         $this->_deleteImportFile = FALSE;
         
         $this->_doImport(array(), $definition);
         $this->_deletePersonalContacts = TRUE;
 
-        $this->_filename = dirname(__FILE__) . '/files/import_duplicate_2.csv';
+        $this->_filename = dirname(__FILE__) .($withCustomfields ? '/files/import_duplicate_2_cf.csv' : '/files/import_duplicate_2.csv');
         
         $result = $this->_doImport(array(), $definition);
         
         $this->assertEquals(1, $result['updatecount'], 'should have updated 1 contact');
+        $this->assertEquals(0, $result['totalcount'], 'should have imported 0 records: ' . print_r($result['results']->toArray(), true));
+        $this->assertEquals(0, $result['failcount']);
         $this->assertEquals('joerg@home.com', $result['results'][0]->email_home, 'duplicates resolving did not work: ' . print_r($result['results']->toArray(), true));
         $this->assertEquals('Jörg', $result['results'][0]->n_given, 'wrong encoding: ' . print_r($result['results']->toArray(), true));
+
+        return $result;
+    }
+
+    /**
+     * testImportDuplicateResolveCustomfields
+     */
+    public function testImportDuplicateResolveCustomfields()
+    {
+        $this->_createCustomField('customfield1');
+        $this->_createCustomField('customfield2');
+        // empty values: should not trigger record updates
+        $this->_createCustomField('customfield3');
+
+        $result = $this->testImportDuplicateResolve(/* $withCustomfields */ true);
+
+        // check customfields in result
+        $joerg = $result['results'][0]->toArray();
+        $this->assertTrue(isset($joerg['customfields']), 'cfs missing: ' .  print_r($joerg, true));
+        $this->assertFalse(isset($joerg['customfields']['customfield1']), print_r($joerg, true));
+        $this->assertEquals('cf2-2', $joerg['customfields']['customfield2']);
     }
 
     /**
@@ -331,17 +357,12 @@ class Addressbook_Import_CsvTest extends ImportTestCase
         
         $result = $this->_doImport($options, $definition);
         
-        $this->assertEquals(6, count($result['results']));
-        $this->assertEquals(3, $result['updatecount'], 'should have updated 3 contacts');
+        $this->assertEquals(5, count($result['results']));
+        $this->assertEquals(2, $result['updatecount'], 'should have updated 3 contacts');
         $this->assertEquals(3, $result['totalcount'], 'should have added 3 contacts');
         $this->assertEquals('Straßbough', $result['results'][1]['adr_one_locality'],
                 'should have changed the locality of contact #2: ' . print_r($result['results'][1]->toArray(), true));
-        $this->assertEquals('Dr. Schutheiss', $result['results'][3]['n_family']);
-        // TODO this should be researched, imho the relation should not trigger an update of the record
-        $this->assertEquals(1, $result['results'][3]['seq'], 'Wolfer has been updated - relations changed');
-        $this->assertEquals('Weixdorf DD', $result['results'][0]['adr_one_locality'], 'locality should persist');
-        $this->assertEquals('Gartencenter Röhr & Vater', $result['results'][4]['n_fileas']);
-        $this->assertEquals('Straßback', $result['results'][5]['adr_one_locality']);
+        $this->assertEquals('Gartencenter Röhr & Vater', $result['results'][3]['n_family']);
     }
 
     public function testSplitField()
index db5ef94..80994f6 100644 (file)
@@ -11,7 +11,7 @@
     <label>Simple CSV import</label>
     <description>simple import</description>
     <extension>csv</extension>
-    <duplicateResolveStrategy>mergeTheirs</duplicateResolveStrategy>
+    <duplicateResolveStrategy>mergeMine</duplicateResolveStrategy>
     <mapping>
         <field>
             <source>adr_one_countryname</source>
             <source>tel_work</source>
             <destination>tel_work</destination>
         </field>
+        <field>
+            <source>customfield1</source>
+            <destination>customfield1</destination>
+        </field>
+        <field>
+            <source>customfield2</source>
+            <destination>customfield2</destination>
+        </field>
+        <field>
+            <source>customfield3</source>
+            <destination>customfield3</destination>
+        </field>
     </mapping>
 </config>
\ No newline at end of file
index a48f0a1..f6ab019 100644 (file)
@@ -1,2 +1,3 @@
 "org_name","salutation","title","n_given","n_family","role","adr_one_street","adr_one_postalcode","adr_one_locality","adr_one_countryname","tel_work","tel_fax","tel_cell","email","tel_fax_home","tel_home","email_home"\r
 "effect gmbh","Herr","Dr.","Jörg","Heinz","Geschäftsführer","Str. 25","21222","Köln","DE","022324321","","","joerg.heinz@honk.com","","",""\r
+"effect gmbh","Herr","","Hans","Fritz","Technical Lead","Str. 25","21222","Köln","DE","022324321","","","hans.fritz@honk.com","","",""\r
diff --git a/tests/tine20/Addressbook/Import/files/import_duplicate_1_cf.csv b/tests/tine20/Addressbook/Import/files/import_duplicate_1_cf.csv
new file mode 100644 (file)
index 0000000..3066ef8
--- /dev/null
@@ -0,0 +1,3 @@
+"org_name","salutation","title","n_given","n_family","role","adr_one_street","adr_one_postalcode","adr_one_locality","adr_one_countryname","tel_work","tel_fax","tel_cell","email","tel_fax_home","tel_home","email_home","customfield1","customfield2","customfield3"
+"effect gmbh","Herr","Dr.","Jörg","Heinz","Geschäftsführer","Str. 25","21222","Köln","DE","022324321","","","joerg.heinz@honk.com","","","","cf1","cf2",""
+"effect gmbh","Herr","","Hans","Fritz","Technical Lead","Str. 25","21222","Köln","DE","022324321","","","hans.fritz@honk.com","","","","cf1","cf2",""
index 02d9a67..cbfc347 100644 (file)
@@ -1,2 +1,3 @@
 "org_name","salutation","title","n_given","n_family","role","adr_one_street","adr_one_postalcode","adr_one_locality","adr_one_countryname","tel_work","tel_fax","tel_cell","email","tel_fax_home","tel_home","email_home"\r
 "effect gmbh","Herr","Dr.","Jörg","Heinz","Geschäftsführer","Str. 25","21222","Köln","DE","022324321","","","joerg.heinz@honk.com","022324322","022324323","joerg@home.com"\r
+"effect gmbh","Herr","","Hans","Fritz","Technical Lead","Str. 25","21222","Köln","DE","022324321","","","hans.fritz@honk.com","","",""\r
diff --git a/tests/tine20/Addressbook/Import/files/import_duplicate_2_cf.csv b/tests/tine20/Addressbook/Import/files/import_duplicate_2_cf.csv
new file mode 100644 (file)
index 0000000..8651f2e
--- /dev/null
@@ -0,0 +1,3 @@
+"org_name","salutation","title","n_given","n_family","role","adr_one_street","adr_one_postalcode","adr_one_locality","adr_one_countryname","tel_work","tel_fax","tel_cell","email","tel_fax_home","tel_home","email_home","customfield1","customfield2","customfield3"
+"effect gmbh","Herr","Dr.","Jörg","Heinz","Geschäftsführer","Str. 25","21222","Köln","DE","022324321","","","joerg.heinz@honk.com","022324322","022324323","joerg@home.com","","cf2-2",""
+"effect gmbh","Herr","","Hans","Fritz","Technical Lead","Str. 25","21222","Köln","DE","022324321","","","hans.fritz@honk.com","","","","cf1","cf2",""
index 51f08d5..5a23a22 100644 (file)
@@ -27,7 +27,7 @@ class Addressbook_JsonTest extends TestCase
      *
      * @var Addressbook_Frontend_Json
      */
-    protected $_instance;
+    protected $_uit;
 
     /**
      * contacts that should be deleted later
@@ -70,18 +70,6 @@ class Addressbook_JsonTest extends TestCase
     protected $_groupIdsToDelete = NULL;
     
     protected $_originalRoleRights = null;
-    
-    /**
-     * Runs the test methods of this class.
-     *
-     * @access public
-     * @static
-     */
-    public static function main()
-    {
-        $suite  = new PHPUnit_Framework_TestSuite('Tine 2.0 Addressbook Json Tests');
-        PHPUnit_TextUI_TestRunner::run($suite);
-    }
 
     /**
      * Sets up the fixture.
@@ -96,7 +84,7 @@ class Addressbook_JsonTest extends TestCase
         // always resolve customfields
         Addressbook_Controller_Contact::getInstance()->resolveCustomfields(TRUE);
         
-        $this->_instance = new Addressbook_Frontend_Json();
+        $this->_uit = new Addressbook_Frontend_Json();
         
         $personalContainer = Tinebase_Container::getInstance()->getPersonalContainer(
             Zend_Registry::get('currentAccount'),
@@ -118,6 +106,8 @@ class Addressbook_JsonTest extends TestCase
             'sort' => 'n_fileas',
             'dir' => 'ASC',
         );
+
+        parent::setUp();
     }
 
     /**
@@ -130,7 +120,7 @@ class Addressbook_JsonTest extends TestCase
     {
         Addressbook_Controller_Contact::getInstance()->setGeoDataForContacts($this->_geodata);
         
-        $this->_instance->deleteContacts($this->_contactIdsToDelete);
+        $this->_uit->deleteContacts($this->_contactIdsToDelete);
 
         foreach ($this->_customfieldIdsToDelete as $cfd) {
             Tinebase_CustomField::getInstance()->deleteCustomField($cfd);
@@ -156,6 +146,8 @@ class Addressbook_JsonTest extends TestCase
         }
         
         $this->_resetOriginalRoleRights();
+
+        parent::tearDown();
     }
     
     protected function _resetOriginalRoleRights()
@@ -179,7 +171,7 @@ class Addressbook_JsonTest extends TestCase
         $filter = array(
             array('field' => 'containerType', 'operator' => 'equals',   'value' => 'all'),
         );
-        $contacts = $this->_instance->searchContacts($filter, $paging);
+        $contacts = $this->_uit->searchContacts($filter, $paging);
 
         $this->assertGreaterThan(0, $contacts['totalcount']);
     }
@@ -195,7 +187,7 @@ class Addressbook_JsonTest extends TestCase
         $filter = array(
             array('field' => 'list', 'operator' => 'equals',   'value' => $adminListId),
         );
-        $contacts = $this->_instance->searchContacts($filter, $paging);
+        $contacts = $this->_uit->searchContacts($filter, $paging);
 
         $this->assertGreaterThan(0, $contacts['totalcount']);
         // check if user in admin list
@@ -232,7 +224,7 @@ class Addressbook_JsonTest extends TestCase
                         "label": "Kontakte"
                     }
                 ]';
-        $contacts = $this->_instance->searchContacts(Zend_Json::decode($filter), NULL);
+        $contacts = $this->_uit->searchContacts(Zend_Json::decode($filter), NULL);
         $this->assertGreaterThan(0, $contacts['totalcount']);
     }
 
@@ -249,7 +241,7 @@ class Addressbook_JsonTest extends TestCase
             array('field' => 'containerType', 'operator' => 'equals',   'value' => 'all'),
         );
     
-        $contacts = $this->_instance->searchContacts($filter, $paging);
+        $contacts = $this->_uit->searchContacts($filter, $paging);
         $this->assertGreaterThan(0, $contacts['totalcount']);
     }
     
@@ -264,7 +256,7 @@ class Addressbook_JsonTest extends TestCase
         $filter = array(
             array('field' => 'container_id', 'operator' => 'equals',   'value' => ''),
         );
-        $contacts = $this->_instance->searchContacts($filter, $paging);
+        $contacts = $this->_uit->searchContacts($filter, $paging);
 
         $this->assertGreaterThan(0, $contacts['totalcount']);
     }
@@ -280,7 +272,7 @@ class Addressbook_JsonTest extends TestCase
         $filter = array(
             array('field' => 'containerType', 'operator' => 'equals',   'value' => 'otherUsers'),
         );
-        $contacts = $this->_instance->searchContacts($filter, $paging);
+        $contacts = $this->_uit->searchContacts($filter, $paging);
 
         $this->assertGreaterThanOrEqual(0, $contacts['totalcount'], 'getting other peoples contacts failed');
     }
@@ -298,7 +290,7 @@ class Addressbook_JsonTest extends TestCase
         $filter = array(
             array('field' => 'telephone', 'operator' => 'contains', 'value' => '+49TELCELLPRIVATE')
         );
-        $contacts = $this->_instance->searchContacts($filter, $paging);
+        $contacts = $this->_uit->searchContacts($filter, $paging);
         $this->assertEquals(1, $contacts['totalcount']);
     }
 
@@ -316,7 +308,7 @@ class Addressbook_JsonTest extends TestCase
         if ($_tags !== NULL) {
             $newContactData['tags'] = $_tags;
         }
-        $newContact = $this->_instance->saveContact($newContactData, $_forceCreation);
+        $newContact = $this->_uit->saveContact($newContactData, $_forceCreation);
         $this->assertEquals($newContactData['n_family'], $newContact['n_family'], 'Adding contact failed');
 
         $this->_contactIdsToDelete[] = $newContact['id'];
@@ -359,9 +351,17 @@ class Addressbook_JsonTest extends TestCase
         $changes = array(
             array('name' => 'url',                    'value' => "http://www.phpunit.de"),
             array('name' => 'adr_one_region',         'value' => 'PHPUNIT_multipleUpdate'),
-            array('name' => 'customfield_' . $createdCustomField->name, 'value' => 'PHPUNIT_multipleUpdate' )
+            array('name' => 'customfield_' . $createdCustomField->name, 'value' => 'PHPUNIT_multipleUpdate' ),
+            array('name' => '%add', 'value' => json_encode(array(
+                'own_model'         => 'Addressbook_Model_Contact',
+                'own_backend'       => 'Sql',
+                'related_degree'    => 'parent',
+                'related_model'     => 'Addressbook_Model_Contact',
+                'related_backend'   => 'Sql',
+                'related_id'        => Tinebase_Core::getUser()->contact_id,
+                'remark'            => 'some remark'
+            ))),
         );
-
         foreach($companies as $company) {
             $contact = $this->_addContact($company);
             $contactIds[] = $contact['id'];
@@ -377,7 +377,7 @@ class Addressbook_JsonTest extends TestCase
 
         // check if default field adr_one_region value was found
         $sFilter = array(array('field' => 'adr_one_region','operator' => 'equals', 'value' => 'PHPUNIT_multipleUpdate'));
-        $searchResult = $this->_instance->searchContacts($sFilter,$this->objects['paging']);
+        $searchResult = $this->_uit->searchContacts($sFilter,$this->objects['paging']);
 
         // look if all 3 contacts are found again by default field, and check if default field got properly updated
         $this->assertEquals(3, $searchResult['totalcount'],'Could not find the correct number of records by adr_one_region');
@@ -392,8 +392,14 @@ class Addressbook_JsonTest extends 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) relations (1 hinzugefügt) customfields ( -> {');
+
+        // check relation
+        $fullRecord = $this->_uit->getContact($record['id']);
+        $this->assertEquals(1, count($fullRecord['relations']), 'relation got not added');
+        $this->assertEquals('some remark', $fullRecord['relations'][0]['remark']);
+        $this->assertEquals('parent', $fullRecord['relations'][0]['related_degree']);
+
         // check invalid data
         $changes = array(
             array('name' => 'type', 'value' => 'Z'),
@@ -432,7 +438,7 @@ class Addressbook_JsonTest extends TestCase
         $cf = $this->_createCustomfield();
         $contact = $this->_addContact();
         $contact['customfields'][$cf->name] = 'changed value';
-        $result = $this->_instance->saveContact($contact);
+        $result = $this->_uit->saveContact($contact);
         
         $this->assertEquals('changed value', $result['customfields'][$cf->name]);
         $this->_checkChangedNote($result['id'], ' -> {"' . $cf->name . '":"changed value"})');
@@ -485,7 +491,7 @@ class Addressbook_JsonTest extends TestCase
         );
         $contact['tags'] = array($tag);
         
-        $result = $this->_instance->saveContact($contact);
+        $result = $this->_uit->saveContact($contact);
         
         $this->assertEquals($tagName, $result['tags'][0]['name']);
         $this->_checkChangedNote($result['id'], array(
@@ -521,7 +527,7 @@ class Addressbook_JsonTest extends TestCase
         $contact = $this->testTagsModlog();
         $contact['tags'] = array();
         sleep(1); // make sure that the second change always gets last when fetching notes
-        $result = $this->_instance->saveContact($contact);
+        $result = $this->_uit->saveContact($contact);
         $this->_checkChangedNote($result['id'], array(
             'tags',
             '1 ' . Tinebase_Translation::getTranslation('Tinebase')->_('removed'),
@@ -555,7 +561,7 @@ class Addressbook_JsonTest extends TestCase
         $contact = $this->testAttachMultipleTagsModlog(Tinebase_Model_Tag::TYPE_PERSONAL);
         $this->_originalRoleRights = $this->_removeRoleRight('Addressbook', Tinebase_Acl_Rights::USE_PERSONAL_TAGS);
         
-        $contact = $this->_instance->getContact($contact['id']);
+        $contact = $this->_uit->getContact($contact['id']);
         
         $this->assertTrue(! isset($contact['tags']) || count($contact['tags'] === 0), 'record should not have any tags');
     }
@@ -574,7 +580,7 @@ class Addressbook_JsonTest extends TestCase
             array('field' => 'containerType', 'operator' => 'equals',   'value' => 'singleContainer'),
             array('field' => 'container', 'operator' => 'equals',   'value' => $this->container->id),
         );
-        $contacts = $this->_instance->searchContacts($filter, $paging);
+        $contacts = $this->_uit->searchContacts($filter, $paging);
 
         $this->assertGreaterThan(0, $contacts['totalcount']);
     }
@@ -593,7 +599,7 @@ class Addressbook_JsonTest extends TestCase
             array('field' => 'containerType', 'operator' => 'equals',   'value' => 'personal'),
             array('field' => 'owner',  'operator' => 'equals',   'value' => Zend_Registry::get('currentAccount')->getId()),
         );
-        $contacts = $this->_instance->searchContacts($filter, $paging);
+        $contacts = $this->_uit->searchContacts($filter, $paging);
 
         $this->assertGreaterThan(0, $contacts['totalcount']);
     }
@@ -606,7 +612,7 @@ class Addressbook_JsonTest extends TestCase
     {
         $contact = $this->_addContact();
 
-        $contact = $this->_instance->getContact($contact['id']);
+        $contact = $this->_uit->getContact($contact['id']);
 
         $this->assertEquals('PHPUNIT', $contact['n_family'], 'getting contact failed');
     }
@@ -623,7 +629,7 @@ class Addressbook_JsonTest extends TestCase
         $contact['n_family'] = 'PHPUNIT UPDATE';
         $contact['adr_one_locality'] = 'Hamburg';
         $contact['adr_one_street'] = 'Pickhuben 2';
-        $updatedContact = $this->_instance->saveContact($contact);
+        $updatedContact = $this->_uit->saveContact($contact);
 
         $this->assertEquals($contact['id'], $updatedContact['id'], 'updated produced a new contact');
         $this->assertEquals('PHPUNIT UPDATE', $updatedContact['n_family'], 'updating data failed');
@@ -638,7 +644,7 @@ class Addressbook_JsonTest extends TestCase
             $updatedContact['adr_one_street']      = 'Blindengasse 52';
             $updatedContact['adr_one_postalcode']  = '1095';
             $updatedContact['adr_one_countryname'] = '';
-            $updatedContact = $this->_instance->saveContact($updatedContact);
+            $updatedContact = $this->_uit->saveContact($updatedContact);
 
             // check geo data
             $this->assertEquals(16,   round($updatedContact['adr_one_lon']), 'wrong geodata (lon): ' . $updatedContact['adr_one_lon']);
@@ -655,10 +661,10 @@ class Addressbook_JsonTest extends TestCase
     {
         $contact = $this->_addContact();
 
-        $this->_instance->deleteContacts($contact['id']);
+        $this->_uit->deleteContacts($contact['id']);
 
         $this->setExpectedException('Tinebase_Exception_NotFound');
-        $contact = $this->_instance->getContact($contact['id']);
+        $contact = $this->_uit->getContact($contact['id']);
     }
 
     /**
@@ -864,9 +870,13 @@ class Addressbook_JsonTest extends TestCase
      * test import
      * 
      * @see 0006226: Data truncated for column 'adr_two_lon'
+     *
+     * TODO move import test to separate test class
      */
     public function testImport()
     {
+        $this->_testNeedsTransaction();
+
         $result = $this->_importHelper();
         $this->assertEquals(2, $result['totalcount'], 'dryrun should detect 2 for import.' . print_r($result, TRUE));
         $this->assertEquals(0, $result['failcount'], 'Import failed for one or more records.');
@@ -904,6 +914,8 @@ class Addressbook_JsonTest extends TestCase
     */
     public function testImportWithResolveStrategyDiscard()
     {
+        $this->_testNeedsTransaction();
+
         $result = $this->_importHelper(array('dryrun' => 0));
         $fritz = $result['results'][1];
 
@@ -925,6 +937,8 @@ class Addressbook_JsonTest extends TestCase
     */
     public function testImportWithResolveStrategyMergeTheirs()
     {
+        $this->_testNeedsTransaction();
+
         $result = $this->_importHelper(array('dryrun' => 0));
         $this->assertEquals(2, count($result['results']), 'no import results');
         $fritz = $result['results'][1];
@@ -977,7 +991,7 @@ class Addressbook_JsonTest extends TestCase
         $options = array_merge($additionalOptions, array(
             'container_id'  => $this->container->getId(),
         ));
-        $result = $this->_instance->importContacts($tempFile->getId(), $definition->getId(), $options, $clientRecords);
+        $result = $this->_uit->importContacts($tempFile->getId(), $definition->getId(), $options, $clientRecords);
         if (isset($additionalOptions['dryrun']) && $additionalOptions['dryrun'] === 0) {
             foreach ($result['results'] as $contact) {
                 $this->_contactIdsToDelete[] = $contact['id'];
@@ -992,6 +1006,8 @@ class Addressbook_JsonTest extends TestCase
      */
     public function testImportWithTags()
     {
+        $this->_testNeedsTransaction();
+
         $options = array(
             'dryrun'     => 0,
             'autotags'   => array(array(
@@ -1013,7 +1029,7 @@ class Addressbook_JsonTest extends TestCase
             'name'    => 'supi',
             'type'    => Tinebase_Model_Tag::TYPE_PERSONAL,
         ));
-        $fritz = $this->_instance->saveContact($fritz);
+        $fritz = $this->_uit->saveContact($fritz);
         //print_r($fritz);
         
         // once again for duplicates (check if client record has tag)
@@ -1044,6 +1060,8 @@ class Addressbook_JsonTest extends TestCase
     */
     public function testImportWithExistingTag()
     {
+        $this->_testNeedsTransaction();
+
         $tag = $this->_getTag(Tinebase_Model_Tag::TYPE_PERSONAL);
         $tag = Tinebase_Tags::getInstance()->create($tag);
         
@@ -1062,6 +1080,8 @@ class Addressbook_JsonTest extends TestCase
     */
     public function testImportWithNewTag()
     {
+        $this->_testNeedsTransaction();
+
         $tag = $this->_getTag(Tinebase_Model_Tag::TYPE_PERSONAL);
         
         $options = array(
@@ -1081,6 +1101,8 @@ class Addressbook_JsonTest extends TestCase
      */
     public function testImportKeepExistingWithTag()
     {
+        $this->_testNeedsTransaction();
+
         $klaus = $this->_tagImportHelper('discard');
         $this->assertEquals(2, count($klaus['tags']), 'klaus should have both tags: ' . print_r($klaus['tags'], TRUE));
     }
@@ -1091,6 +1113,8 @@ class Addressbook_JsonTest extends TestCase
      */
     public function testImportMergeTheirsWithTag()
     {
+        $this->_testNeedsTransaction();
+
         $result = $this->_importHelper(array('dryrun' => 0));
         $this->assertTrue(count($result['results']) > 0, 'no record were imported');
         $klaus = $result['results'][0];
@@ -1112,7 +1136,7 @@ class Addressbook_JsonTest extends TestCase
         $result = $this->_importHelper($options, $clientRecords);
         $this->assertEquals(2, count($result['results'][0]['tags']), 'klaus should have both tags: ' . print_r($result['results'][0], TRUE));
         
-        $klaus = $this->_instance->getContact($klaus['id']);
+        $klaus = $this->_uit->getContact($klaus['id']);
         $this->assertEquals(2, count($klaus['tags']), 'klaus should have both tags: ' . print_r($klaus, TRUE));
         $this->assertEquals('12345', $klaus['adr_one_postalcode']);
     }
@@ -1152,7 +1176,7 @@ class Addressbook_JsonTest extends TestCase
         $this->assertEquals($expectedTotalcount, $result['totalcount'], 'Should discard fritz');
         $this->assertEquals(1, $result['duplicatecount'], 'fritz should still be a duplicate');
         
-        $klaus = $this->_instance->getContact($klausId);
+        $klaus = $this->_uit->getContact($klausId);
         
         return $klaus;
     }
@@ -1164,6 +1188,8 @@ class Addressbook_JsonTest extends TestCase
      */
     public function testImportKeepBothWithTag()
     {
+        $this->_testNeedsTransaction();
+
         $klaus = $this->_tagImportHelper('keep');
         $this->assertEquals(1, count($klaus['tags']), 'klaus should have only one tag: ' . print_r($klaus['tags'], TRUE));
     }
@@ -1176,6 +1202,8 @@ class Addressbook_JsonTest extends TestCase
      */
     public function testImportTagWithLongName()
     {
+        $this->_testNeedsTransaction();
+
         // import records with long tag name
         $result = $this->_importHelper(array('dryrun' => 0), array(), dirname(__FILE__) . '/Import/files/adb_tine_import_with_tag.csv');
         
@@ -1203,7 +1231,7 @@ class Addressbook_JsonTest extends TestCase
             $this->markTestSkipped('Projects not installed.');
         }
         
-        $contact = $this->_instance->saveContact($this->_getContactData());
+        $contact = $this->_uit->saveContact($this->_getContactData());
         $project = $this->_getProjectData($contact);
 
         $projectJson = new Projects_Frontend_Json();
@@ -1232,7 +1260,7 @@ class Addressbook_JsonTest extends TestCase
                 'own_model'              => 'Projects_Model_Project',
                 'own_backend'            => 'Sql',
                 'own_id'                 => 0,
-                'own_degree'             => Tinebase_Model_Relation::DEGREE_SIBLING,
+                'related_degree'         => Tinebase_Model_Relation::DEGREE_SIBLING,
                 'type'                   => 'COWORKER',
                 'related_backend'        => 'Sql',
                 'related_id'             => $_contact['id'],
@@ -1243,7 +1271,7 @@ class Addressbook_JsonTest extends TestCase
                 'own_model'              => 'Projects_Model_Project',
                 'own_backend'            => 'Sql',
                 'own_id'                 => 0,
-                'own_degree'             => Tinebase_Model_Relation::DEGREE_SIBLING,
+                'related_degree'         => Tinebase_Model_Relation::DEGREE_SIBLING,
                 'type'                   => 'RESPONSIBLE',
                 'related_backend'        => 'Sql',
                 'related_id'             => Tinebase_Core::getUser()->contact_id,
@@ -1297,7 +1325,7 @@ class Addressbook_JsonTest extends TestCase
             ),
             array('field' => 'id', 'operator' => 'in', 'value' => array($_contact['id'], Tinebase_Core::getUser()->contact_id)),
         );
-        $result = $this->_instance->searchContacts($filter, array());
+        $result = $this->_uit->searchContacts($filter, array());
 
         $this->assertEquals('relation', $result['filter'][0]['value']['linkType']);
         $this->assertTrue(isset($result['filter'][0]['id']), 'id expected');
@@ -1342,7 +1370,7 @@ class Addressbook_JsonTest extends TestCase
             ),
             array('field' => 'id', 'operator' => 'in', 'value' => array(Tinebase_Core::getUser()->contact_id, $contact['id']))
         );
-        $result = $this->_instance->searchContacts($filter, array());
+        $result = $this->_uit->searchContacts($filter, array());
         $this->assertEquals('foreignRecord', $result['filter'][0]['field']);
         $this->assertEquals('foreignId', $result['filter'][0]['value']['linkType']);
         $this->assertEquals('ContactAttendeeFilter', $result['filter'][0]['value']['filterName']);
@@ -1365,7 +1393,7 @@ class Addressbook_JsonTest extends TestCase
             $this->_getOrganizerForeignIdFilter(),
             array('field' => 'id', 'operator' => 'in', 'value' => array(Tinebase_Core::getUser()->contact_id, $contact['id']))
         );
-        $result = $this->_instance->searchContacts($filter, array());
+        $result = $this->_uit->searchContacts($filter, array());
 
         $this->assertEquals(1, $result['totalcount']);
         $this->assertEquals(Tinebase_Core::getUser()->contact_id, $result['results'][0]['id']);
@@ -1380,7 +1408,7 @@ class Addressbook_JsonTest extends TestCase
         $filter = array(
             array('field' => 'n_family', 'operator' => 'contains', 'value' => strtolower('PHPUNIT'))
         );
-        $result = $this->_instance->searchContacts($filter, array());
+        $result = $this->_uit->searchContacts($filter, array());
 
         $this->assertGreaterThan(0, $result['totalcount'], 'contact not found: ' . print_r($result, true));
     }
@@ -1426,7 +1454,7 @@ class Addressbook_JsonTest extends TestCase
                 array('field' => 'id', 'operator' => 'in', 'value' => array($contact['id']))
             )
         ));
-        $result = $this->_instance->searchContacts($filter, array());
+        $result = $this->_uit->searchContacts($filter, array());
 
         $this->assertEquals(2, $result['totalcount'], 'expected 2 contacts');
     }
@@ -1499,6 +1527,8 @@ class Addressbook_JsonTest extends TestCase
     */
     public function testDuplicateCheckWithTag()
     {
+        $this->_testNeedsTransaction();
+
         $tagName = Tinebase_Record_Abstract::generateUID();
         $tag = array(
             'type'          => Tinebase_Model_Tag::TYPE_PERSONAL,
@@ -1512,7 +1542,7 @@ class Addressbook_JsonTest extends TestCase
         // replace tag array with single tag id (like the client does)
         $contact['tags'] = array($contact['tags'][0]['id']);
         try {
-            $newContact = $this->_instance->saveContact($contact, TRUE);
+            $newContact = $this->_uit->saveContact($contact, TRUE);
             $this->assertTrue(FALSE, 'duplicate detection failed');
         } catch (Tinebase_Exception_Duplicate $ted) {
             $exceptionData = $ted->toArray();
@@ -1530,12 +1560,12 @@ class Addressbook_JsonTest extends TestCase
     {
         $contact = $this->_getContactData();
         $contact['email'] = 'test@example.org';
-        $contact = $this->_instance->saveContact($contact);
+        $contact = $this->_uit->saveContact($contact);
         $this->_contactIdsToDelete[] = $contact['id'];
         try {
             $contact2 = $this->_getContactData();
             $contact2['email'] = 'test@example.org';
-            $contact2 = $this->_instance->saveContact($contact2);
+            $contact2 = $this->_uit->saveContact($contact2);
             $this->_contactIdsToDelete[] = $contact2['id'];
             $this->assertTrue(FALSE, 'no duplicate exception');
         } catch (Tinebase_Exception_Duplicate $ted) {
@@ -1558,7 +1588,7 @@ class Addressbook_JsonTest extends TestCase
      */
     public function testImportDefinitionsInRegistry()
     {
-        $registryData = $this->_instance->getRegistryData();
+        $registryData = $this->_uit->getRegistryData();
 
         $this->assertEquals('adb_tine_import_csv', $registryData['defaultImportDefinition']['name']);
         $this->assertTrue(is_array($registryData['importDefinitions']['results']));
@@ -1575,7 +1605,7 @@ class Addressbook_JsonTest extends TestCase
      */
     public function testSearchContactsWithTagIsNotFilter()
     {
-        $allContacts = $this->_instance->searchContacts(array(), array());
+        $allContacts = $this->_uit->searchContacts(array(), array());
 
         $filter = new Addressbook_Model_ContactFilter(array(array(
             'field'    => 'n_fileas',
@@ -1596,7 +1626,7 @@ class Addressbook_JsonTest extends TestCase
             'operator' => 'not',
             'value'    => $tag->getId()
         ));
-        $allContactsWithoutTheTag = $this->_instance->searchContacts($filter, array());
+        $allContactsWithoutTheTag = $this->_uit->searchContacts($filter, array());
 
         $this->assertTrue(count($allContactsWithoutTheTag['totalcount']) > 0);
         $this->assertEquals($allContacts['totalcount']-1, $allContactsWithoutTheTag['totalcount']);
@@ -1627,7 +1657,7 @@ class Addressbook_JsonTest extends TestCase
             'operator' => 'in',
             'value'    => array($tag->getId())
         ));
-        $allContactsWithTheTag = $this->_instance->searchContacts($filter, array());
+        $allContactsWithTheTag = $this->_uit->searchContacts($filter, array());
         $this->assertEquals(1, $allContactsWithTheTag['totalcount']);
 
         $filter = array(array(
@@ -1635,7 +1665,7 @@ class Addressbook_JsonTest extends TestCase
             'operator' => 'in',
             'value'    => array()
         ));
-        $emptyResult = $this->_instance->searchContacts($filter, array());
+        $emptyResult = $this->_uit->searchContacts($filter, array());
         $this->assertEquals(0, $emptyResult['totalcount']);
     }
     
@@ -1654,7 +1684,7 @@ Web: http://www.metaways.de
 Tel: +49 (0)40 343244-232
 Fax: +49 (0)40 343244-222";
         
-        $result = $this->_instance->parseAddressData($addressString);
+        $result = $this->_uit->parseAddressData($addressString);
         
         $this->assertTrue((isset($result['contact']) || array_key_exists('contact', $result)));
         $this->assertTrue(is_array($result['contact']));
@@ -1684,7 +1714,7 @@ Fax: +49 (0)40 343244-222";
         $addressString = "Straßenname 25 · 23569 Lübeck
 Steuernummer 33/111/32212";
         
-        $result = $this->_instance->parseAddressData($addressString);
+        $result = $this->_uit->parseAddressData($addressString);
         $this->assertEquals('Straßenname 25', $result['contact']['adr_one_street'], 'wrong street: ' . print_r($result, TRUE));
         $this->assertEquals('Lübeck', $result['contact']['adr_one_locality'], 'wrong street: ' . print_r($result, TRUE));
     }
@@ -1703,11 +1733,11 @@ Steuernummer 33/111/32212";
         
         // search for her with ContactDisabledFilter
         $filter = array(array('field' => 'n_given',      'operator' => 'equals',   'value' => 'Susan'));
-        $result = $this->_instance->searchContacts($filter, array());
+        $result = $this->_uit->searchContacts($filter, array());
         $this->assertEquals(0, $result['totalcount'], 'found contacts: ' . print_r($result, true));
         
         $filter[] = array('field' => 'showDisabled', 'operator' => 'equals',   'value' => TRUE);
-        $result = $this->_instance->searchContacts($filter, array());
+        $result = $this->_uit->searchContacts($filter, array());
         $this->assertEquals(1, $result['totalcount']);
     }
     
@@ -1739,7 +1769,7 @@ Steuernummer 33/111/32212";
             'value'    => 'hiddengroup'
         ));
         
-        $result = $this->_instance->searchLists($filter, array());
+        $result = $this->_uit->searchLists($filter, array());
         $this->assertEquals(0, $result['totalcount'], 'should not find hidden list: ' . print_r($result, TRUE));
     }
 
@@ -1751,14 +1781,14 @@ Steuernummer 33/111/32212";
         $tag2 = Tinebase_Tags::getInstance()->create($this->_getTag(Tinebase_Model_Tag::TYPE_PERSONAL, 'tag2'));
 
         $filter = array(array('field' => 'id','operator' => 'in', 'value' => array($contact1['id'], $contact2['id'])));
-        $json = new Tinebase_Frontend_Json();
+        $tinebaseJson = new Tinebase_Frontend_Json();
 
-        $json->attachMultipleTagsToMultipleRecords($filter,'Addressbook_Model_ContactFilter',array(
+        $tinebaseJson->attachMultipleTagsToMultipleRecords($filter,'Addressbook_Model_ContactFilter',array(
             $tag1->toArray(),
             $tag2->toArray(),
         ));
 
-        $result = $this->_instance->searchContacts($filter, array());
+        $result = $this->_uit->searchContacts($filter, array());
         $this->assertCount(2, $result['results'], 'search count failed');
 
         foreach($result['results'] as $contactData) {
@@ -1767,6 +1797,73 @@ Steuernummer 33/111/32212";
     }
 
     /**
+     * @see 0011584: allow to set group member roles
+     */
+    public function testCeateListWithMemberAndRole($listRoleName = 'my test role')
+    {
+        $contact = $this->_addContact();
+        $listRole = $this->_uit->saveListRole(array(
+            'name'          => $listRoleName,
+            'description'   => 'my test description'
+        ));
+        $memberroles = array(array(
+            'contact_id'   => $contact['id'],
+            'list_role_id' => $listRole['id'],
+        ));
+        $list = $this->_uit->saveList(array(
+            'name'                  => 'my test list',
+            'description'           => '',
+            'members'               => array($contact['id']),
+            'memberroles'           => $memberroles,
+            'type'                  => Addressbook_Model_List::LISTTYPE_LIST,
+        ));
+
+        $this->assertEquals(array($contact['id']), $list['members'], 'members are not saved/returned in list: ' . print_r($list, true));
+        $this->assertTrue(isset($list['memberroles']), 'memberroles missing from list');
+        $this->assertEquals(1, count($list['memberroles']), 'member roles are not saved/returned in list: ' . print_r($list, true));
+        $this->assertTrue(isset($list['memberroles'][0]['list_role_id']['id']), 'list roles should be resolved');
+        $this->assertEquals($listRole['id'], $list['memberroles'][0]['list_role_id']['id'], 'member roles are not saved/returned in list: ' . print_r($list, true));
+
+        return $list;
+    }
+
+    /**
+     * @see 0011584: allow to set group member roles
+     */
+    public function testRemoveListMemberRoles()
+    {
+        $list = $this->testCeateListWithMemberAndRole();
+
+        $list['memberroles'] = array();
+        $updatedList = $this->_uit->saveList($list);
+        $this->assertTrue(empty($updatedList['memberroles']), 'memberroles should be removed: ' . print_r($updatedList, true));
+    }
+
+    /**
+     * @see 0011578: add list roles to CoreData + Addressbook
+     */
+    public function testListRolesApi()
+    {
+        $this->_testSimpleRecordApi('ListRole');
+    }
+
+    /**
+     * @see 0011584: allow to set group member roles
+     */
+    public function testSearchContactByListRole()
+    {
+        $list = $this->testCeateListWithMemberAndRole();
+
+        $filter = array(
+            array('field' => 'list_role_id','operator' => 'in', 'value' => array($list['memberroles'][0]['list_role_id']['id']))
+        );
+
+        $result = $this->_uit->searchContacts($filter, array());
+
+        $this->assertEquals(1, $result['totalcount']);
+    }
+
+    /**
      * @see 0011704: PHP 7 can't decode empty JSON-strings
      */
     public function testEmptyPagingParamJsonDecode()
@@ -1776,7 +1873,7 @@ Steuernummer 33/111/32212";
             'operator' => 'equals',
             'value'    => 'somename'
         ));
-        $result = $this->_instance->searchContacts($filter, '');
+        $result = $this->_uit->searchContacts($filter, '');
         $this->assertEquals(0, $result['totalcount']);
     }
 }
index 34b9185..78e8615 100644 (file)
@@ -4,19 +4,14 @@
  * 
  * @package     Addressbook
  * @license     http://www.gnu.org/licenses/agpl.html
- * @copyright   Copyright (c) 2010-2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2010-2016 Metaways Infosystems GmbH (http://www.metaways.de)
  * @author      Lars Kneschke <l.kneschke@metaways.de>
  */
 
 /**
- * Test helper
+ * Test class for Addressbook_Controller_List
  */
-require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'TestHelper.php';
-
-/**
- * Test class for Tinebase_Group
- */
-class Addressbook_ListControllerTest extends PHPUnit_Framework_TestCase
+class Addressbook_ListControllerTest extends TestCase
 {
     /**
      * @var array test objects
@@ -24,25 +19,6 @@ class Addressbook_ListControllerTest extends PHPUnit_Framework_TestCase
     protected $objects = array();
 
     /**
-     * set geodata for contacts
-     * 
-     * @var boolean
-     */
-    protected $_geodata = FALSE;
-    
-    /**
-     * Runs the test methods of this class.
-     *
-     * @access public
-     * @static
-     */
-    public static function main()
-    {
-        $suite  = new PHPUnit_Framework_TestSuite('Tine 2.0 Addressbook List Controller Tests');
-        PHPUnit_TextUI_TestRunner::run($suite);
-    }
-
-    /**
      * Sets up the fixture.
      * This method is called before a test is executed.
      *
@@ -50,9 +26,8 @@ class Addressbook_ListControllerTest extends PHPUnit_Framework_TestCase
      */
     protected function setUp()
     {
-        Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
-        $this->_geodata = Addressbook_Controller_Contact::getInstance()->setGeoDataForContacts($this->_geodata);
-        
+        parent::setUp();
+
         $personalContainer = Tinebase_Container::getInstance()->getPersonalContainer(
             Zend_Registry::get('currentAccount'), 
             'Addressbook', 
@@ -155,18 +130,6 @@ class Addressbook_ListControllerTest extends PHPUnit_Framework_TestCase
     }
 
     /**
-     * Tears down the fixture
-     * This method is called after a test is executed.
-     *
-     * @access protected
-     */
-    protected function tearDown()
-    {
-        Addressbook_Controller_Contact::getInstance()->setGeoDataForContacts($this->_geodata);
-        Tinebase_TransactionManager::getInstance()->rollBack();
-    }
-    
-    /**
      * try to add a list
      */
     public function testAddList()
@@ -267,4 +230,30 @@ class Addressbook_ListControllerTest extends PHPUnit_Framework_TestCase
         $userContact = Addressbook_Controller_Contact::getInstance()->getContactByUserId(Tinebase_Core::getUser()->getId());
         Addressbook_Controller_Contact::getInstance()->delete($userContact->getId());
     }
+
+    /**
+     * @see 0011522: improve handling of group-lists
+     */
+    public function testChangeListWithoutManageGrant()
+    {
+        // try to set memberships without MANAGE_ACCOUNTS
+        $this->_removeRoleRight('Admin', Admin_Acl_Rights::MANAGE_ACCOUNTS, true);
+
+        $listId = Tinebase_Group::getInstance()->getDefaultGroup()->list_id;
+        try {
+            Addressbook_Controller_List::getInstance()->addListMember($listId, array($this->objects['contact1']->getId()));
+            $this->fail('should not be possible to add list member to system group');
+        } catch (Tinebase_Exception_AccessDenied $tead) {
+            $this->assertEquals('No permission to add list member.', $tead->getMessage());
+        }
+
+        $list = Addressbook_Controller_List::getInstance()->get($listId);
+        $list->name = 'my new name';
+        try {
+            Addressbook_Controller_List::getInstance()->update($list);
+            $this->fail('should not be possible to set name of system group');
+        } catch (Tinebase_Exception_AccessDenied $tead) {
+            $this->assertEquals('You are not allowed to MANAGE_ACCOUNTS in application Admin !', $tead->getMessage());
+        }
+    }
 }
index 09da549..55dfa52 100644 (file)
@@ -22,7 +22,8 @@ class AllServerTests
         $suite->addTestSuite('ActiveSync_Server_HttpTests');
         $suite->addTestSuite('Tinebase_ControllerServerTest');
         $suite->addTestSuite('Tinebase_Server_WebDAVTests');
-        
+        $suite->addTestSuite('Tinebase_Server_JsonTests');
+
         return $suite;
     }
 }
index a63995c..647a774 100644 (file)
@@ -45,6 +45,7 @@ class AllTests
         $suite->addTest(ExampleApplication_AllTests::suite());
         $suite->addTest(Sipgate_AllTests::suite());
         $suite->addTest(SimpleFAQ_AllTests::suite());
+        $suite->addTest(CoreData_AllTests::suite());
         $suite->addTest(Zend_AllTests::suite());
         
         return $suite;
index 2354e4f..e0c1bac 100644 (file)
@@ -43,6 +43,7 @@ class Calendar_AllTests
         $suite->addTestSuite('Calendar_Import_CalDAVTest');
         $suite->addTestSuite('Calendar_Export_ICalTest');
         $suite->addTestSuite('Calendar_Export_OdsTests');
+        $suite->addTestSuite('Calendar_Export_DocTest');
         $suite->addTestSuite('Calendar_Convert_Event_VCalendar_AllTests');
         $suite->addTestSuite('Calendar_Setup_DemoDataTests');
         
index 514559d..326315a 100644 (file)
@@ -1359,6 +1359,11 @@ class Calendar_Controller_EventNotificationsTests extends Calendar_TestCase
             $this->assertEquals(2, count($messages), 'two mails should be send (resource=pwulf + attender invite=sclever) '
                 . print_r($messages, true));
         }
+
+        // assert user agent
+        // @see 0011498: set user agent header for notification messages
+        $headers = $messages[0]->getHeaders();
+        $this->assertEquals(Tinebase_Core::getTineUserAgent('Notification Service'), $headers['User-Agent'][0]);
     }
 
     /**
index 2bd97e2..da1343b 100644 (file)
@@ -337,8 +337,16 @@ class Calendar_Controller_EventTests extends Calendar_TestCase
             array('user_id' => $this->_getPersonasContacts('pwulf')->getId())
         ));
         $persistentEvent = $this->_controller->create($event);
-        
-        $fbinfo = $this->_controller->getFreeBusyInfo(array(array('from' => $persistentEvent->dtstart, 'until' => $persistentEvent->dtend)), $persistentEvent->attendee);
+
+        $period = new Calendar_Model_EventFilter(array(array(
+            'field'     => 'period',
+            'operator'  => 'within',
+            'value'     => array(
+                'from'      => $persistentEvent->dtstart,
+                'until'     => $persistentEvent->dtend
+            ),
+        )));
+        $fbinfo = $this->_controller->getFreeBusyInfo($period, $persistentEvent->attendee);
        
         $this->assertGreaterThanOrEqual(2, count($fbinfo));
         
@@ -347,9 +355,19 @@ class Calendar_Controller_EventTests extends Calendar_TestCase
 
     public function testSearchFreeTime()
     {
+        $this->markTestSkipped();
         $persistentEvent = $this->testGetFreeBusyInfo();
-        
-        $this->_controller->searchFreeTime($persistentEvent->dtstart->setHour(6), $persistentEvent->dtend->setHour(22), $persistentEvent->attendee);
+
+        $period = new Calendar_Model_EventFilter(array(array(
+            'field'     => 'period',
+            'operator'  => 'within',
+            'value'     => array(
+                'from'      => $persistentEvent->dtstart->setHour(6),
+                'until'     => $persistentEvent->dtend->setHour(22)
+            ),
+        )));
+
+        $this->_controller->searchFreeTime($period, $persistentEvent->attendee);
     }
     
     /**
@@ -488,7 +506,35 @@ class Calendar_Controller_EventTests extends Calendar_TestCase
         
         $this->_controller->create($nonConflictEvent, TRUE);
     }
-    
+
+    public function testCreateConflictResourceUnavailable()
+    {
+        $event = $this->_getEvent();
+
+        // create & add resource
+        $rt = new Calendar_Controller_ResourceTest();
+        $rt->setUp();
+        $resource = $rt->testCreateResource();
+        $resource->busy_type = Calendar_Model_FreeBusy::FREEBUSY_BUSY_UNAVAILABLE;
+        Calendar_Controller_Resource::getInstance()->update($resource);
+
+        $event->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(new Calendar_Model_Attender(array(
+            'user_type' => Calendar_Model_Attender::USERTYPE_RESOURCE,
+            'user_id'   => $resource->getId()
+        ))));
+
+        $conflictEvent = clone $event;
+        $this->_controller->create($event);
+        try {
+            $this->_controller->create($conflictEvent, TRUE);
+            $this->fail('Calendar_Exception_AttendeeBusy was not thrown');
+        } catch (Calendar_Exception_AttendeeBusy $abe) {
+            $fb = $abe->getFreeBusyInfo();
+            $this->assertEquals(Calendar_Model_FreeBusy::FREEBUSY_BUSY_UNAVAILABLE, $fb[0]->type);
+        }
+
+    }
+
     public function testUpdateWithConflictNoTimechange()
     {
         $persitentConflictEvent = $this->testCreateEventWithConflict();
index e6bea9a..a00f6ec 100644 (file)
@@ -1000,6 +1000,27 @@ class Calendar_Controller_RecurTest extends Calendar_TestCase
         $savedEvent = Calendar_Controller_Event::getInstance()->create($newEvent, /* $checkBusyConflicts = */ true);
     }
 
+    public function testRecurEventWithConstrainsBackgroundComputation()
+    {
+        $constrainEvent = $this->_getRecurEvent();
+        $constrainEvent->rrule_constraints = new Calendar_Model_EventFilter(array(
+            array('field' => 'container_id', 'operator' => 'in', 'value' => array($constrainEvent['container_id'])),
+        ));
+        $constrainEvent = Calendar_Controller_Event::getInstance()->create($constrainEvent);
+
+        // create conflicting event
+        $conflictEvent = $this->_getRecurEvent();
+        $conflictEvent->rrule->until = $conflictEvent->dtstart->getClone()->addDay(5);
+        $conflictEvent = Calendar_Controller_Event::getInstance()->create($conflictEvent);
+
+        // run background job
+        Calendar_Controller_Event::getInstance()->updateConstraintsExdates();
+
+        // check exdates
+        $constrainEvent = Calendar_Controller_Event::getInstance()->get($constrainEvent->getId());
+        $this->assertCount(6, $constrainEvent->exdate);
+    }
+
     /**
      * returns a simple recure event
      *
diff --git a/tests/tine20/Calendar/Export/DocTest.php b/tests/tine20/Calendar/Export/DocTest.php
new file mode 100644 (file)
index 0000000..33633cf
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+/**
+ * Tine 2.0 - http://www.tine20.org
+ *
+ * @package     Calendar
+ * @license     http://www.gnu.org/licenses/agpl.html
+ * @copyright   Copyright (c) 2016 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Cornelius Weiß <c.weiss@metaways.de>
+ */
+
+use \PhpOffice\PhpWord;
+
+/**
+ * Calendar Doc generation class tests
+ *
+ * @package     Calendar
+ * @subpackage  Export
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Cornelius Weiß <c.weiss@metaways.de>
+ * @copyright   Copyright (c) 2016 Metaways Infosystems GmbH (http://www.metaways.de)
+ *
+ */
+class Calendar_Export_DocTest extends Calendar_TestCase
+{
+    public function testExportSimpleDocSheet()
+    {
+        // skip tests for php7
+        // ERROR: PHP Fatal error:  Cannot use PhpOffice\PhpWord\Shared\String as String because 'String' is a special
+        //  class name in /usr/local/share/tine20.git/tine20/vendor/phpoffice/phpword/src/PhpWord/TemplateProcessor.php
+        //  on line 23
+        if (PHP_VERSION_ID >= 70000) {
+            $this->markTestSkipped('FIXME 0011730: fix doc export for php7');
+        }
+
+        // make sure definition is imported
+        $definitionFile = __DIR__ . '/../../../../tine20/Calendar/Export/definitions/cal_default_doc_sheet.xml';
+        $calendarApp = Tinebase_Application::getInstance()->getApplicationByName('Calendar');
+        Tinebase_ImportExportDefinition::getInstance()->updateOrCreateFromFilename($definitionFile, $calendarApp, 'cal_default_doc_sheet');
+
+//        Tinebase_TransactionManager::getInstance()->commitTransaction($this->_transactionId);
+
+        // @TODO have some demodata to export here
+        $filter = new Calendar_Model_EventFilter(array(
+//            array('field' => 'period', 'operator' => 'within', 'value' => array(
+//                'from' => '',
+//                'until' => ''
+//            ))
+        ));
+        $doc = new Calendar_Export_DocSheet($filter);
+        $doc->generate();
+
+        $tempfile = tempnam(Tinebase_Core::getTempDir(), __METHOD__ . '_') . '.docx';
+        $doc->save($tempfile);
+
+        $this->assertGreaterThan(0, filesize($tempfile));
+//        `open $tempfile`;
+    }
+}
\ No newline at end of file
index 2d6ad10..07ad814 100644 (file)
@@ -506,7 +506,34 @@ class Calendar_JsonTests extends Calendar_TestCase
         $midnightInUTC = new Tinebase_DateTime($queryResult['rrule_until']);
         $this->assertEquals(Tinebase_DateTime::now()->setTime(23,59,59)->toString(), $midnightInUTC->setTimezone(Tinebase_Core::getUserTimezone(), TRUE)->toString());
     }
-    
+
+    /**
+     * testCreateRecurEventWithConstrains
+     */
+    public function testCreateRecurEventWithConstrains()
+    {
+        $conflictEventData = $this->testCreateEvent();
+
+        $eventData = $this->testCreateEvent();
+        $eventData['rrule'] = array(
+            'freq'       => 'WEEKLY',
+            'interval'   => 1,
+            'byday'      => 'WE',
+        );
+        $eventData['rrule_constraints'] = array(
+            array('field' => 'container_id', 'operator' => 'in', 'value' => array($eventData['container_id'])),
+        );
+
+        $updatedEventData = $this->_uit->saveEvent($eventData);
+
+        $this->assertTrue(is_array($updatedEventData['rrule_constraints']));
+        $this->assertEquals('personal',$updatedEventData['rrule_constraints'][0]['value'][0]['type'], 'filter is not resolved');
+        $this->assertEquals(1, count($updatedEventData['exdate']));
+        $this->assertEquals('2009-03-25 06:00:00', $updatedEventData['exdate'][0]);
+
+        return $updatedEventData;
+    }
+
     /**
     * testSearchRecuringIncludes
     */
@@ -1944,7 +1971,7 @@ class Calendar_JsonTests extends Calendar_TestCase
                 'own_model' => 'Calendar_Model_Event',
                 'own_backend' => 'Sql',
                 'own_id' => 0,
-                'own_degree' => Tinebase_Model_Relation::DEGREE_SIBLING,
+                'related_degree' => Tinebase_Model_Relation::DEGREE_SIBLING,
                 'type' => '',
                 'related_backend' => 'Sql',
                 'related_id' => $contact->getId(),
diff --git a/tests/tine20/CoreData/AllTests.php b/tests/tine20/CoreData/AllTests.php
new file mode 100644 (file)
index 0000000..85d29ed
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Tine 2.0 - http://www.tine20.org
+ * 
+ * @package     CoreData
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @copyright   Copyright (c) 2012-2014 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Philipp Schüle <p.schuele@metaways.de>
+ * 
+ */
+
+/**
+ * Test helper
+ */
+require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'TestHelper.php';
+
+class CoreData_AllTests
+{
+    public static function main()
+    {
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+    
+    public static function suite()
+    {
+        $suite = new PHPUnit_Framework_TestSuite('Tine 2.0 CoreData All Tests');
+        
+        $suite->addTestSuite('CoreData_JsonTest');
+        return $suite;
+    }
+}
diff --git a/tests/tine20/CoreData/JsonTest.php b/tests/tine20/CoreData/JsonTest.php
new file mode 100644 (file)
index 0000000..cd9674a
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+/**
+ * Tine 2.0 - http://www.tine20.org
+ * 
+ * @package     CoreData
+ * @subpackage  Record
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @copyright   Copyright (c) 2016 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Philipp Schüle <p.schuele@metaways.de>
+ */
+
+/**
+ * Test helper
+ */
+require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'TestHelper.php';
+
+/**
+ * Test class for CoreData_JsonTest
+ */
+class CoreData_JsonTest extends TestCase
+{
+    /**
+     * unit in test
+     *
+     * @var CoreData_Frontend_Json
+     */
+    protected $_uit = null;
+
+    /**
+     * set up tests
+     */
+    protected function setUp()
+    {
+        parent::setUp();
+        $this->_uit = new CoreData_Frontend_Json();
+    }
+
+    /**
+     * testGetCoreData
+     */
+    public function testGetCoreData()
+    {
+        $result = $this->_uit->getCoreData();
+
+        $this->assertGreaterThan(0, $result['totalcount'], print_r($result, true));
+
+        // look for 'lists'
+        $lists = null;
+        foreach ($result['results'] as $coreData) {
+            if ($coreData['id'] === 'adb_lists') {
+                $lists = $coreData;
+            }
+        }
+        $this->assertTrue($lists !== null);
+        $this->assertEquals('Addressbook_Model_List', $lists['model'], print_r($lists, true));
+    }
+}
index a2ddc64..f334f9d 100644 (file)
@@ -293,7 +293,7 @@ class Crm_ControllerTest extends PHPUnit_Framework_TestCase
             'own_model'              => 'Crm_Model_Lead',
             'own_backend'            => 'Sql',
             'own_id'                 => $GLOBALS['Addressbook_ControllerTest']['leadId'],
-            'own_degree'             => Tinebase_Model_Relation::DEGREE_SIBLING,
+            'related_degree'         => Tinebase_Model_Relation::DEGREE_SIBLING,
             'related_model'          => 'Tasks_Model_Task',
             'related_backend'        => Tasks_Backend_Factory::SQL,
             'related_id'             => $task->getId(),
index 57625e6..aa09855 100644 (file)
@@ -144,7 +144,7 @@ class Crm_Export_PdfTest extends TestCase
             'own_model'              => 'Crm_Model_Lead',
             'own_backend'            => 'Sql',
             'own_id'                 => $lead->getId(),
-            'own_degree'             => Tinebase_Model_Relation::DEGREE_SIBLING,
+            'related_degree'         => Tinebase_Model_Relation::DEGREE_SIBLING,
             'related_model'          => 'Addressbook_Model_Contact',
             'related_backend'        => Addressbook_Backend_Factory::SQL,
             'related_id'             => $this->objects['linkedContact']->id,
@@ -177,7 +177,7 @@ class Crm_Export_PdfTest extends TestCase
             'own_model'              => 'Crm_Model_Lead',
             'own_backend'            => 'Sql',
             'own_id'                 => $lead->getId(),
-            'own_degree'             => Tinebase_Model_Relation::DEGREE_SIBLING,
+            'related_degree'         => Tinebase_Model_Relation::DEGREE_SIBLING,
             'related_model'          => 'Tasks_Model_Task',
             'related_backend'        => Tasks_Backend_Factory::SQL,
             'related_id'             => $task->getId(),
index c8a75ed..e59d8e6 100644 (file)
@@ -87,86 +87,7 @@ class Crm_JsonTest extends Crm_AbstractTest
         parent::tearDown();
         Crm_Controller_Lead::getInstance()->duplicateCheckFields(array('lead_name'));
     }
-     
-    /**
-     * test get crm registry
-     * 
-     * @return void
-     */
-    public function testGetRegistryData()
-    {
-        $registry = $this->_getUit()->getRegistryData();
-        
-        $types = array('leadtypes', 'leadstates', 'leadsources');
-        
-        // check data
-        foreach ($types as $type) {
-            $this->assertGreaterThan(0, $registry[$type]['totalcount']);
-            $this->assertGreaterThan(0, count($registry[$type]['results']));
-        }
-        
-        // check defaults
-        $this->assertEquals(array(
-            'leadstate_id'  => 1,
-            'leadtype_id'   => 1,
-            'leadsource_id' => 1,
-        ), array(
-            'leadstate_id' => $registry['defaults']['leadstate_id'],
-            'leadtype_id' => $registry['defaults']['leadtype_id'],
-            'leadsource_id' => $registry['defaults']['leadsource_id'],
-        ));
-        $this->assertEquals(
-            Tinebase_Container::getInstance()->getDefaultContainer('Crm')->getId(),
-            $registry['defaults']['container_id']['id']
-        );
-    }
-    
-    /**
-     * test get settings/config
-     * 
-     * @return void
-     */
-    public function testGetSettings()
-    {
-        $result = $this->_getUit()->getSettings();
-        
-        $this->assertArrayHasKey('leadstates',  $result);
-        $this->assertArrayHasKey('leadtypes',   $result);
-        $this->assertArrayHasKey('leadsources', $result);
-        $this->assertArrayHasKey('defaults',    $result);
-        $this->assertEquals(6, count($result[Crm_Model_Config::LEADSTATES]));
-        $this->assertEquals(3, count($result[Crm_Model_Config::LEADTYPES]));
-        $this->assertEquals(4, count($result[Crm_Model_Config::LEADSOURCES]));
-    }
-    
-    /**
-     * test get settings/config
-     * 
-     * @return void
-     */
-    public function testSaveSettings()
-    {
-        $oldSettings = $this->_getUit()->getSettings();
-        
-        // change some settings
-        $newSettings = $oldSettings;
-        $newSettings['defaults']['leadstate_id'] = 2;
-        $newSettings['leadsources'][] = array(
-            'id' => 5,
-            'leadsource' => 'Another Leadsource'
-        );
-        $anotherResult = $this->_getUit()->saveSettings($newSettings);
-        $this->assertEquals($newSettings, $anotherResult, 'new settings have not been saved');
-        
-        // reset original settings
-        $result = $this->_getUit()->saveSettings($oldSettings);
-        $this->assertEquals($result, $oldSettings, 'old settings have not been reset');
-        
-        // test Crm_Model_Config::getOptionById
-        $settings = Crm_Controller::getInstance()->getConfigSettings();
-        $this->assertEquals(array(), $settings->getOptionById(5, 'leadsources'), 'Crm_Model_Config::getOptionById failed');
-    }
-    
+
     /**
      * try to add/search/delete a lead with linked contact, task and product
      * 
@@ -414,7 +335,7 @@ class Crm_JsonTest extends Crm_AbstractTest
                 'type'  => 'TASK',
                 'own_model' => 'Tasks_Model_Task',
                 'own_backend' => 'Sql',
-                'own_degree' => 'sibling',
+                'related_degree' => 'sibling',
                 'related_model' => 'Crm_Model_Lead',
                 'related_backend' => 'Sql',
                 'related_id' => $leadData['id'],
@@ -458,7 +379,7 @@ class Crm_JsonTest extends Crm_AbstractTest
                 'type'  => 'TASK',
                 'own_model' => 'Tasks_Model_Task',
                 'own_backend' => 'Sql',
-                'own_degree' => 'sibling',
+                'related_degree' => 'sibling',
                 'related_model' => 'Crm_Model_Lead',
                 'related_backend' => 'Sql',
                 'related_id' => $leadData1['id'],
@@ -473,7 +394,7 @@ class Crm_JsonTest extends Crm_AbstractTest
             'type'  => 'TASK',
             'own_model' => 'Tasks_Model_Task',
             'own_backend' => 'Sql',
-            'own_degree' => 'sibling',
+            'related_degree' => 'sibling',
             'related_model' => 'Crm_Model_Lead',
             'related_backend' => 'Sql',
             'related_id' => $leadData2['id'],
@@ -501,7 +422,7 @@ class Crm_JsonTest extends Crm_AbstractTest
                 'type'  => 'TASK',
                 'own_model' => 'Tasks_Model_Task',
                 'own_backend' => 'Sql',
-                'own_degree' => 'sibling',
+                'related_degree' => 'sibling',
                 'related_model' => 'Crm_Model_Lead',
                 'related_backend' => 'Sql',
                 'related_id' => $leadData1['id'],
@@ -518,7 +439,7 @@ class Crm_JsonTest extends Crm_AbstractTest
                 'type'  => 'TASK',
                 'own_model' => 'Crm_Model_Lead',
                 'own_backend' => 'Sql',
-                'own_degree' => 'sibling',
+                'related_degree' => 'sibling',
                 'related_model' => 'Tasks_Model_Task',
                 'related_backend' => 'Sql',
                 'related_id' => $taskData['id'],
index 683e36c..518f014 100644 (file)
@@ -51,7 +51,7 @@ class Crm_NotificationsTests extends Crm_AbstractTest
             'related_record'         => $this->_getContact(),
             'own_model'              => 'Crm_Model_Lead',
             'own_backend'            => 'Sql',
-            'own_degree'             => Tinebase_Model_Relation::DEGREE_SIBLING,
+            'related_degree'         => Tinebase_Model_Relation::DEGREE_SIBLING,
             'related_model'          => 'Addressbook_Model_Contact',
             'related_backend'        => Tasks_Backend_Factory::SQL,
         ), TRUE));
@@ -83,7 +83,7 @@ class Crm_NotificationsTests extends Crm_AbstractTest
             'related_record'         => Addressbook_Controller_Contact::getInstance()->getContactByUserId(Tinebase_Core::getUser()->getId()),
             'own_model'              => 'Crm_Model_Lead',
             'own_backend'            => 'Sql',
-            'own_degree'             => Tinebase_Model_Relation::DEGREE_SIBLING,
+            'related_degree'         => Tinebase_Model_Relation::DEGREE_SIBLING,
             'related_model'          => 'Addressbook_Model_Contact',
             'related_backend'        => Tasks_Backend_Factory::SQL,
         ), TRUE));
@@ -110,7 +110,7 @@ class Crm_NotificationsTests extends Crm_AbstractTest
                 'related_record'         => Addressbook_Controller_Contact::getInstance()->getContactByUserId(Tinebase_Core::getUser()->getId()),
                 'own_model'              => 'Crm_Model_Lead',
                 'own_backend'            => 'Sql',
-                'own_degree'             => Tinebase_Model_Relation::DEGREE_SIBLING,
+                'related_degree'         => Tinebase_Model_Relation::DEGREE_SIBLING,
                 'related_model'          => 'Addressbook_Model_Contact',
                 'related_backend'        => Tasks_Backend_Factory::SQL,
         ), TRUE));
index 68014da..51e2477 100644 (file)
@@ -1167,7 +1167,92 @@ class Felamimail_Frontend_JsonTest extends TestCase
         $fullMessage = $this->_json->getMessage($message['id']);
         $this->assertTrue(empty($fullMessage->preparedParts));
     }
-    
+
+    /**
+     * testSendMailveopeAPIMessage
+     *
+     * - envolpe amored message into PGP MIME structure
+     */
+    public function testSendMailveopeAPIMessage()
+    {
+        $subject = 'testSendMailveopeAPIMessage';
+        $messageData = $this->_getMessageData('', $subject);
+        $messageData['body'] = '-----BEGIN PGP MESSAGE-----
+Version: Mailvelope v1.3.3
+Comment: https://www.mailvelope.com
+
+wcFMA/0LJF28pDbGAQ//YgtsmEZN+pgIJiBDb7iYwPEOchDRIEjGOx543KF6
+5YigW9p39pfcJgvGfT8x9cUIrYGxyw5idPSOEftYXyjjGaOYGaKpRSR4hI83
+OcJSlEHKq72xhg04mNpCjjJ8dLBstPcQ7tDtsA8Nfb4PwkUYB9IhIBnARg+n
+NvrN8mSA2UnY9ElFCvf30sar8EuM5swAjbk64C8TIypMy/Bg4T93zRdxwik6
+7BCcbOpm/2PTsiVYBOTcU4+XdG5eyTENXH58M6UTxTD4/g7Qi5PjN+PxyXqf
+v2Y1k9F49Y1egf2QJ2r4PX0EWS8SaynSHiIoBsp1xb07nLwZwCdMPG1QNPpF
+l2FqlS4dEuQTdkv0deMvd7gtiNynRTAVcJc1ZC6RuWJ+EH2jA49XWkn14eRC
+e5jMtPPudkhubnN9Je5lwatGKbJGyuXh+IaM0E0WQMZ3dm8+ST1l4WpVuGbw
+KozLUiTRJP9UoxWOcwpQOnzcSlc4rHmWdtF0y3usM9u9GPREqpNUWkEyEEuv
+XdZE7rKKj22dJHLCXxAQEh3m29Y2WVaq50YbtEZ+SwwbrHhxP4+FJEru+byh
+fiZ47sVW2KvYGJPvbFoSZHiSvMecxDg8BVwe+naZXww/Rwa/TlaX4bYyzpUG
+KeJUAzWEfFpJ0+yAvMGQEC7psIJ9NCx149C4ujiQmajSwhUB3XANcmCGB0wm
+JjcqC4AHvc7/t4MrQZm0F/W+nrMmNqbZk+gylVrPs9rFEqu7wbjwTmsFA3sS
+LkenvQIxBali6uzCR+nd09REqcYirG9cLti39DW048lhhG/ml+gAxxNEaSpG
+NbIoV/3w8n7sAIM1fjuHne8bX0gWG43TTjU8MwSMryG7tCOG5u+Cebh6TAoY
+NzbX2dpDhOYq5zXdCgKU4P3eh0csSs4UrqFT3TdAxIGrQJ7KrXvB6+N8gRZo
+FcUaR+zrRPJjPUZfi46ecP5SG/tM5ea1hqvkwEnEpqjLmCUxqB+rfxx46USX
+hMZd2ukUv6kEKv3EUDsRYu1SlDLhDLhWNx8RJae5XkMR+eUUMyNNVwbeMQbB
+VAcMcaPITTk84sH7XElr9eF6sCUN4V79OSBRPGY/aNGrcwcoDSD4Hwu+Lw9w
+Q+1n8EQ66gAkbJzCNd5GaYMZR9echkBaD/rdWDS3ktcrMehra+h44MTQONV9
+8W+RI+IT5jaIXtB4jePmGjsJjbC9aEhTRBRkUnPA7phgknc52dD74AY/6lzK
+yd4uZ6S3vhurJW0Vt4iBWJzhFNiSODh5PzteeNzCVAkGMsQvy1IHk0d3uzcE
+0tEuSh8fZOFGB4fvMx9Mk8oAU92wfj4J7AVpSo5oRdxMqAXfaYKqfr2Gn++q
+E5LClhVIBbFXclCoe0RYNz4wtxjeeYbP40Bq5g0JvPutD/dBMp8hz8Qt+yyG
+d8X4/KmQIXyFZ8aP17GMckE5GVVvY9y89eWnWuTUJdwM540hB/EJNeHHTE5y
+N2FSLGcmNkvE+3H7BczQ2ZI1SZDhof+umbUst0qoQW+hHmY3CSma48yGAVox
+52u2t7hosHCfpf631Ve/6fcICo8vJ2Qfufu2BGIMlSfx4WzUuaMQBynuxFSa
+IbVx8ZTO7dJRKrg72aFmWTf0uNla7vicAhpiLWobyNYcZbIjrAGDfg==
+=BaAn
+-----END PGP MESSAGE-----';
+
+        $this->_foldersToClear[] = 'INBOX';
+        $this->_json->saveMessage($messageData);
+
+        $message = $this->_searchForMessageBySubject(Tinebase_Core::filterInputForDatabase($subject));
+        $fullMessage = $this->_json->getMessage($message['id']);
+
+        $this->assertContains('multipart/encrypted', $fullMessage['headers']['content-type']);
+        $this->assertContains('protocol="application/pgp-encrypted"', $fullMessage['headers']['content-type']);
+        $this->assertCount(2, $fullMessage['structure']['parts']);
+        $this->assertEquals('application/pgp-encrypted', $fullMessage['structure']['parts'][1]['contentType']);
+        $this->assertEquals('application/octet-stream', $fullMessage['structure']['parts'][2]['contentType']);
+
+        return $fullMessage;
+    }
+
+    /**
+     * testMessagePGPMime
+     *
+     * - prepare amored part of PGP MIME structure
+     */
+    public function testMessagePGPMime()
+    {
+        $fullMessage = $this->testSendMailveopeAPIMessage();
+
+        $this->assertEquals('application/pgp-encrypted', $fullMessage['preparedParts'][0]['contentType']);
+        $this->assertContains('-----BEGIN PGP MESSAGE-----', $fullMessage['preparedParts'][0]['preparedData']);
+    }
+
+    public function testMessagePGPInline()
+    {
+        $inbox = $this->_getFolder('INBOX');
+        $mailAsString = file_get_contents(dirname(__FILE__) . '/../files/multipart_alternative_pgp_inline.eml');
+        Felamimail_Controller_Message::getInstance()->appendMessage($inbox, $mailAsString);
+
+        $this->_foldersToClear = array('INBOX');
+        $message = $this->_searchForMessageBySubject('Re: mailvelope und tine20');
+
+        $fullMessage = $this->_json->getMessage($message['id']);
+        $this->assertFalse(empty($fullMessage['preparedParts']));
+    }
+
     /*********************** sieve tests ****************************/
     
     /**
diff --git a/tests/tine20/Felamimail/files/multipart_alternative_pgp_inline.eml b/tests/tine20/Felamimail/files/multipart_alternative_pgp_inline.eml
new file mode 100644 (file)
index 0000000..98906aa
--- /dev/null
@@ -0,0 +1,208 @@
+Return-Path: <thomas@mailvelope.com>\r
+Delivered-To: <cweiss@metaways.de>\r
+Received: from mail03.metaways.net ([10.129.3.213])\r
+       by mail03.metaways.net (Dovecot) with LMTP id sRwED3RkBldLYQAA5ANymA\r
+       for <cweiss@metaways.de>; Thu, 07 Apr 2016 15:45:24 +0200\r
+Received: from mx03.metaways.net ([127.0.0.1])\r
+       by mail03.metaways.net (Dovecot) with LMTP id heejDnRkBldKYQAA5ANymA\r
+       ; Thu, 07 Apr 2016 15:45:24 +0200\r
+Received: from mail-yw0-f170.google.com (mail-yw0-f170.google.com [209.85.161.170])\r
+       by mx03.metaways.net (Postfix) with ESMTPS id E8754212C\r
+       for <c.weiss@metaways.de>; Thu,  7 Apr 2016 15:45:22 +0200 (CEST)\r
+Received: by mail-yw0-f170.google.com with SMTP id t10so96916384ywa.0\r
+        for <c.weiss@metaways.de>; Thu, 07 Apr 2016 06:45:22 -0700 (PDT)\r
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;\r
+        d=mailvelope.com; s=google;\r
+        h=mime-version:in-reply-to:references:date:message-id:subject:from:to;\r
+        bh=DA8m9kynvQyPxx4zYMdnGtkBSm9oYV6Qp1J15pVpvfE=;\r
+        b=gJHEGl2utZ84XN0itLD51eWe9Hj1cUuemk87XmdRMTvKsjjFNmTyh4ARHSq/YQOrY+\r
+         fQ9Gvy3UjG+131CFD2jcRqoNofdRbFXniIGCoX+UIGupDGmXAOxWj84qPBGes+r0N+Nq\r
+         UQbIfQ989//pE/P0C5WBFaqyAEq6zpz+nJt+g=\r
+X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;\r
+        d=1e100.net; s=20130820;\r
+        h=x-gm-message-state:mime-version:in-reply-to:references:date\r
+         :message-id:subject:from:to;\r
+        bh=DA8m9kynvQyPxx4zYMdnGtkBSm9oYV6Qp1J15pVpvfE=;\r
+        b=IrcdaWcf5r5qyROo0FCu9eGSR9g/a84CLFTOjMLYD8PgLT6Oouu23KGto+yyrr9quG\r
+         zPxSQ8B3wBZI60Z44HHyWffF63gOKCXzvu+GzsupmCpSzHe9NH/7FvWBR6W16BthX8pI\r
+         uaa231sNy2W1dv5xHM5usKX6lAoM4HDfS/nSjBwLWeKyOeDgZGbRYSLo/pAnLoIu3g9R\r
+         shXhXHp/3SJdU9eVl39+ExbXeuL7dwvdB3s7EYr76EHQ3n7qj4MF6dGlv+bqyaVLWtZI\r
+         eOXVZcEe+ESKZ2u/oBjUIXyTXw9duFwPjIOI5FE8+Bu/Bwr82tXXSsfVSfGCKjxanXME\r
+         EJqQ==\r
+X-Gm-Message-State: AD7BkJJDIpIn+OIxFNLv0Z3+62Q5qTPoFNE+Zb84OrAwT8V6FP9wWBqWfYSdQI96IHtb0aiCRE06+GZcibJGFA==\r
+MIME-Version: 1.0\r
+X-Received: by 10.129.87.206 with SMTP id l197mr1581903ywb.312.1460036720599;\r
+ Thu, 07 Apr 2016 06:45:20 -0700 (PDT)\r
+Received: by 10.37.65.83 with HTTP; Thu, 7 Apr 2016 06:45:20 -0700 (PDT)\r
+In-Reply-To: <b2ea857d45f63a0ff1aa3d3b34f98dbc24ec39f0@metaways.de>\r
+References: <31e080fd293da45f754069194cde530ee2051682@metaways.de>\r
+       <CAMQ7_A6GYu1yiWxpfUJ7MQ3LzCx1rSsN2SraPJZ_X+T54gaagw@mail.gmail.com>\r
+       <139452372f23c19631a5cbbc2817dccf8bb30ee5@metaways.de>\r
+       <CAOrwtgkWi3-PbDPnbrdZSB681VtFxzX_7qeC73jeGpj5P5H03w@mail.gmail.com>\r
+       <40b040a86b1525fa8673f407f36a24b1b0f14592@metaways.de>\r
+       <CAOrwtg=NAhneN2r8YCHEvMC53UgRKTPiJ0aWWTVOAh67h4Voqg@mail.gmail.com>\r
+       <CAOrwtgk-iLvBcuCa91hS6kneXZqP72oS7ME6Kp58Tf9wPccpkw@mail.gmail.com>\r
+       <32589991a20208719a52b2e42058c43d6838b5bf@metaways.de>\r
+       <CAOrwtgm9G=z=xsPRZzSH5hhkH8-SyJnoQdsJxtazm8UAmjqhRA@mail.gmail.com>\r
+       <b36d390330347c77e2600a210fd99a765944bcda@metaways.de>\r
+       <CAOrwtgkXQ3BrWFY=2EdW9TpRemqrJPQbLcOexRdwcyXwdAM_pQ@mail.gmail.com>\r
+       <c0837421e695fd15c7865f4b744995cedc97f705@metaways.de>\r
+       <CAOrwtg=e6u1t03gkQycq-xfWpCFcd0nc9My1-7gOA-iYPpE=MA@mail.gmail.com>\r
+       <712ad8ebf6481e35b0623944db6e3625abbaa9a7@metaways.de>\r
+       <CAOrwtgmrfNL4W9LJHKnAh164Y6OgM4KvAq+T5tiATQZxRMrzWQ@mail.gmail.com>\r
+       <b2ea857d45f63a0ff1aa3d3b34f98dbc24ec39f0@metaways.de>\r
+Date: Thu, 7 Apr 2016 15:45:20 +0200\r
+Message-ID: <CAOrwtgnVa7CLsu=o6VmY7oMHguS0OxZYR3NjO-rf9HW-0CorMQ@mail.gmail.com>\r
+Subject: Re: mailvelope und tine20\r
+From: =?UTF-8?Q?Thomas_Obernd=C3=B6rfer?= <thomas@mailvelope.com>\r
+To: Cornelius Weiss <c.weiss@metaways.de>\r
+Content-Type: multipart/alternative; boundary=001a11462a14175d9e052fe54a5d\r
+X-Spam-Status: No, score=-0.5 required=5.0 tests=AWL,DKIM_SIGNED,DKIM_VALID,\r
+       DKIM_VALID_AU,HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,\r
+       RCVD_IN_MSPIKE_WL autolearn=disabled version=3.4.0\r
+X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail03.metaways.net\r
+\r
+--001a11462a14175d9e052fe54a5d\r
+Content-Type: text/plain; charset=UTF-8\r
+\r
+-----BEGIN PGP MESSAGE-----\r
+Version: Mailvelope v1.3.6\r
+Comment: https://www.mailvelope.com\r
+\r
+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\r
+=Ypx9\r
+-----END PGP MESSAGE-----\r
+\r
+--001a11462a14175d9e052fe54a5d\r
+Content-Type: text/html; charset=UTF-8\r
+\r
+<div dir="ltr"><pre>-----BEGIN PGP MESSAGE-----\r
+Version: Mailvelope v1.3.6\r
+Comment: <a href="https://www.mailvelope.com">https://www.mailvelope.com</a>\r
+\r
+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\r
+=Ypx9\r
+-----END PGP MESSAGE-----\r
+<pre></pre></pre></div>\r
+\r
+--001a11462a14175d9e052fe54a5d--\r
diff --git a/tests/tine20/Felamimail/files/openpgpencrypted.eml b/tests/tine20/Felamimail/files/openpgpencrypted.eml
new file mode 100644 (file)
index 0000000..eceebf7
--- /dev/null
@@ -0,0 +1,43 @@
+Return-Path: <unittest@tine20.org>\r
+Delivered-To: unittest@tine20.org\r
+Received: from localhost (unknown [192.168.33.1])\r
+       (using TLSv1 with cipher ECDHE-RSA-AES256-SHA (256/256 bits))\r
+       (No client certificate requested)\r
+       (Authenticated sender: unittest@tine20.org)\r
+       by packer-virtualbox-iso-1410946258.hh.metaways.de (Postfix) with ESMTPSA id 7839780069\r
+       for <unittest@tine20.org>; Wed, 14 Oct 2015 21:09:43 +0200 (CEST)\r
+Subject: ENC02\r
+From: "Tine 2.0 Admin Account" <unittest@tine20.org>\r
+To: unittest@tine20.org\r
+User-Agent: Tine 2.0 Email Client (version mailvelope: 901d207b8b6cd30bfca0a8f781a11c97208a129c (2015-10-09 16:18:55) - none)\r
+Message-Id: <aba6dba5a4f6ef4b136cbf955975bb41d6fe69b5@tine20.org>\r
+X-MailGenerator: Tine 2.0\r
+Date: Wed, 14 Oct 2015 19:19:10 +0000\r
+Content-Type: text/plain; charset=UTF-8\r
+Content-Transfer-Encoding: quoted-printable\r
+Content-Disposition: inline\r
+MIME-Version: 1.0\r
+\r
+-----BEGIN PGP MESSAGE-----=0D=0AVersion: Mailvelope v1.2.0=0D=0AComment=\r
+: https://www.mailvelope.com=0D=0A=0D=0AwcFMA3VA7DhVUrUPAQ//WFbMOBAy2dWJ=\r
+3+oFFNHktJWVMCZF+2h1awlRNMtv=0AgjJb90QRSmZvn2dDhuYwLS4skCjsguqK313kJvRjj=\r
+MV1Bl5tjAwOvGMczgI3=0AvfQ+R3Kbj8OleQewBlAHvYrJkjI0ll0z/ES5Q7Jf21gql7rRQK=\r
+euvUXuLtgX=0Ag0/8HjzYrnzsOM2Mf3NyaKz5zammvLl9c/DXmy+N39qnLCd+9YLNAdpOadk=\r
+5=0A1qBcWKzO9IIPnZWuTJhAMKn8gzFi8C9SnSboHG9u25+h/aiQOa50P7LaRLGt=0AX02pU=\r
+it9rqMWBb8FBaCJx9JilpHJsp12g4kYdmcxaqcdNWZD+jaQR5OtP4Ex=0At9/JVckzrMkJua=\r
+Hzfk5lLy25eZtYXGAGR2Fs8eG06T5NGUXDCr6Yf46I7D/r=0Al4Kz6aS/AQXi2EZDXsJsYzi=\r
+Se1tEulFgdyQcbcIX6ptBbiJqcd0lTae6a0bm=0AQ1PgSJ4/dXc6izHNiXQGC2JsfaUPPlzH=\r
+9DYg6TKZu+s2Z1uxp1dKgBWatoq7=0AGYBXRqMTGFCw4MFZhqQrAh1uu8Tg/o768xPilSHJL=\r
+1cbaTPEehInTXS6inZ1=0ARmcftWvshPgnfz573NGCRZzIRyO6dvL5osnhy2Yda6H1RO8taa=\r
+X2NUzciqxl=0App4FC3Ylr1MVoewKtUQ/aSK2PwQxFGYeMVUXNLWlb9PSwSoBCaI6DEPNCmx=\r
+s=0AxaRISqaVibLy74+bt6ah+SueKpM7PiVNsW+LtDJi3Szz7GozoIt4TvEyipVX=0Aj7O5K=\r
+gRLU00z003VWre1FYZU2TP/zEd9fkL0cnUCoLb99VL/gM2uhPwrtNtV=0AUASjSm0eCnEH9n=\r
+MKAEY8ZZzbQW9fzL3jJxpIcxT2QsAvdP4m7JO6CpyP3M+K=0AdZSIcVkXNIaOgzV7Hqg90bF=\r
+uU7CW8/GMC0B3c15muSrJTk41Ku72SWzYzO24=0AF7VEAD8tioHkwkv73z0P/GaKX7tm7+JX=\r
+zqBPMhW0lsZDrqcJo0zAtvUEo/ND=0AAQ+YWEDSuT/rO6AgkOWtFQ3JzlnvzY0njmiVc+XaI=\r
+cEaOeMvsgeTCdA7Neuc=0AhHuQx4hWKYGCXVJVyMX/VZnrtDmFHSWunK/Bvo13aTJ5h13DnU=\r
++7TIRlatRV=0AIP/RQfpWIYI5uOi8CtpAmJT69rrPxnvpJbv2ZG6Cb/6LszUiqX/VjCV4cVg=\r
+d=0AXdedRqulQi4GM9xSel335pj9ER8hONUmep9VLhQef4wlcz7yOyrrI54nqunN=0AII52m=\r
+2LdvYRS0yjzXWk34UqRCEVAphEl3J6unSFd7yVXUiW/F/4ZxCEc2YVY=0AddJeIYuxxkrRac=\r
+aODpH762QJqAHL6vUnNZdWYSwN=0D=0A=3D5QzJ=0D=0A-----END PGP MESSAGE-----=\r
+=0D=0A\r
index 7d1cc58..43f03a4 100644 (file)
@@ -102,9 +102,11 @@ class Filemanager_Controller_DownloadLinkTests extends TestCase
         Filemanager_Controller_Node::getInstance()->createNodes($directories, Tinebase_Model_Tree_Node::TYPE_FOLDER);
         
         $fileList = $this->_getUit()->getFileList($downloadLink, array());
-        
+
         $this->assertGreaterThan(1, count($fileList));
         $this->assertNotNull($fileList->filter('name', 'one')->getFirstRecord());
+
+        return $fileList;
     }
     
     /**
@@ -157,4 +159,20 @@ class Filemanager_Controller_DownloadLinkTests extends TestCase
 
         $this->assertEquals(2, $downloadLink->access_count);
     }
+
+    public function testDownloadLinkAlternativeURL()
+    {
+        Filemanager_Config::getInstance()->set(Filemanager_Config::PUBLIC_DOWNLOAD_URL, 'https://download.example.com/');
+        $downloadLink = $this->testCreateDownloadLink();
+
+        $this->assertContains('example', $downloadLink->url);
+    }
+
+    public function testDownloadListAlternativeURL()
+    {
+        Filemanager_Config::getInstance()->set(Filemanager_Config::PUBLIC_DOWNLOAD_URL, 'https://download.example.com/');
+        $fileList = $this->testGetFileList();
+
+        $this->assertContains('example', $fileList[0]->path);
+    }
 }
index 994ad37..43d8538 100644 (file)
@@ -1047,7 +1047,7 @@ class Filemanager_Frontend_JsonTests extends TestCase
             'own_model'              => 'Filemanager_Model_Node',
             'own_backend'            => 'Sql',
             'own_id'                 => $node['id'],
-            'own_degree'             => Tinebase_Model_Relation::DEGREE_SIBLING,
+            'related_degree'         => Tinebase_Model_Relation::DEGREE_SIBLING,
             'type'                   => 'FILE',
             'related_backend'        => 'Sql',
             'related_model'          => 'Addressbook_Model_Contact',
index 2207b4b..156420b 100644 (file)
@@ -99,7 +99,7 @@ class HumanResources_CliTests extends HumanResources_TestCase
         $this->assertEquals(0, $result, 'import failed: ' . $out);
         
         if ($checkOutput) {
-            $this->assertContains("Imported 2 records. Import failed for 0 records. \n", $out);
+            $this->assertContains("Imported 2 records.", $out);
         }
     }
     
index caf33c3..95c3114 100644 (file)
@@ -26,7 +26,9 @@ class Inventory_AllTests
         $suite = new PHPUnit_Framework_TestSuite('Tine 2.0 Inventory All Tests');
         
         $suite->addTestSuite('Inventory_JsonTest');
+        $suite->addTestSuite('Inventory_ControllerTest');
         $suite->addTestSuite('Inventory_Import_AllTests');
+        $suite->addTestSuite('Inventory_DoctrineModelTest');
         return $suite;
     }
 }
diff --git a/tests/tine20/Inventory/ControllerTest.php b/tests/tine20/Inventory/ControllerTest.php
new file mode 100644 (file)
index 0000000..be1bbbb
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+/**
+ * Tine 2.0 - http://www.tine20.org
+ * 
+ * @package     Inventory
+ * @subpackage  Record
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @copyright   Copyright (c) 2012-2016 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Philipp Schüle <p.schuele@metaways.de>
+ */
+
+/**
+ * Test class for Inventory_ControllerTest
+ */
+class Inventory_ControllerTest extends Inventory_TestCase
+{
+    public function testGetModels()
+    {
+        $models = Inventory_Controller::getInstance()->getModels();
+        $this->assertEquals(array(
+            'Inventory_Model_InventoryItem',
+            'Inventory_Model_Status'
+        ), $models);
+    }
+}
diff --git a/tests/tine20/Inventory/DoctrineModelTest.php b/tests/tine20/Inventory/DoctrineModelTest.php
new file mode 100644 (file)
index 0000000..d781e91
--- /dev/null
@@ -0,0 +1,88 @@
+<?php
+/**
+ * Tine 2.0 - http://www.tine20.org
+ * 
+ * @package     Inventory
+ * @subpackage  Record
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @copyright   Copyright (c) 2016 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Cornelius Weiß <c.weiss@metaways.de>
+ */
+
+use Doctrine\DBAL\Schema\Comparator;
+
+/**
+ * Test class for Inventory_JsonTest
+ */
+class Inventory_DoctrineModelTest extends Inventory_TestCase
+{
+
+    protected function setUp()
+    {
+    }
+
+    public function testGetMetadataOfInventoryModel()
+    {
+        $em = Setup_SchemaTool::getEntityManager('Inventory', array('Inventory_Model_InventoryItem'));
+
+        $invItemMetadata = $em->getClassMetadata('Inventory_Model_InventoryItem');
+
+        $this->assertEquals('Doctrine\ORM\Mapping\ClassMetadata', get_class($invItemMetadata));
+        $this->assertTrue($invItemMetadata->hasField('name'));
+
+        $mapping = $invItemMetadata->getFieldMapping('name');
+        $this->assertEquals('string', $mapping['type']);
+    }
+
+    public function testExplicitRenameProblemExists()
+    {
+        $em = Setup_SchemaTool::getEntityManager('Inventory');
+        $sm = $em->getConnection()->getSchemaManager();
+
+        // NOTE: the DBAL schema is stateless and 'just' describes a schema in a plattform independend way
+        //       thus, all schema upgrade is based on schema comparisim
+        $fromSchema = $sm->createSchema();
+        $toSchema = clone $fromSchema;
+
+        $table = $toSchema->getTable('tine20_inventory_item');
+
+        $this->setExpectedException('Doctrine\DBAL\DBALException');
+        $table->renameColumn('id', 'ident');
+    }
+
+    public function testExplicitRename()
+    {
+        $this->markTestSkipped('evauate concept for explicit field rename with doctrine2 schema tool');
+        $em = Setup_SchemaTool::getEntityManager('Inventory');
+        $sm = $em->getConnection()->getSchemaManager();
+
+        // NOTE: the DBAL schema is stateless and 'just' describes a schema in a plattform independend way
+        //       thus, all schema upgrade is based on schema comparisim
+
+        $fromSchema = $sm->createSchema();
+        $toSchema = clone $fromSchema;
+
+        $table = $toSchema->getTable('tine20_inventory_item');
+
+
+        // workaround -> might have problems?!
+        $col = $table->getColumn('id');
+        $table->dropColumn('id');
+        $table->addColumn('ident', $col->getType()->getName(), $col->toArray());
+
+        // better create, copy, delete?
+        // @TODO ask some insider
+        //  ? Schema tool can't rename cols, but schema diff with compare (at least with mysql plattform) alters table name correctly when col is renamed in annotations
+
+        // non rename updates are a lot more easy
+        $table->changeColumn('name', array(
+            'length' => 200,
+        ));
+
+        $comparator = new Comparator();
+        $schemaDiff = $comparator->compare($fromSchema, $toSchema);
+
+        $updateSql = $schemaDiff->toSql($em->getConnection()->getDatabasePlatform());
+//        print_r($updateSql);
+    }
+}
index b4a955b..22004dd 100644 (file)
@@ -5,16 +5,11 @@
  * @package     Inventory
  * @subpackage  Record
  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
- * @copyright   Copyright (c) 2012-2013 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2012-2016 Metaways Infosystems GmbH (http://www.metaways.de)
  * @author      Michael Spahn <m.spahn@metaways.de>
  */
 
 /**
- * Test helper
- */
-require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'TestHelper.php';
-
-/**
  * Test class for Inventory_JsonTest
  */
 class Inventory_JsonTest extends Inventory_TestCase
@@ -235,4 +230,27 @@ class Inventory_JsonTest extends Inventory_TestCase
         
         return $result;
     }
+
+    /**
+     * saveRecordWithImage
+     */
+    public function testSaveRecordWithImage()
+    {
+        // create TEMPFILE and save in inv item
+        $imageFile = dirname(dirname(dirname(dirname(__FILE__)))) . '/tine20/images/cancel.gif';
+        $tempImage = Tinebase_TempFile::getInstance()->createTempFile($imageFile);
+        $imageUrl = Tinebase_Model_Image::getImageUrl('Tinebase', $tempImage->getId(), 'tempFile');
+
+        $invItem = $this->_getInventoryItem()->toArray();
+        $invItem['image'] = $imageUrl;
+        $savedInvItem = $this->_json->saveInventoryItem($invItem);
+
+        //$savedInvItem = $this->_json->getInventoryItem($savedInvItem['id']);
+        $this->assertTrue(! empty($savedInvItem['image']), 'image url is empty');
+        $this->assertTrue(preg_match('/location=vfs&id=([a-z0-9]*)/', $savedInvItem['image']) == 1, print_r($savedInvItem, true));
+
+        // check if favicon is delivered
+        $image = Tinebase_Model_Image::getImageFromImageURL($savedInvItem['image']);
+        $this->assertEquals(52, $image->width);
+    }
 }
index b3960c4..c551a88 100644 (file)
@@ -4,8 +4,8 @@
  * 
  * @package     Phone
  * @license     http://www.gnu.org/licenses/agpl.html
- * @copyright   Copyright (c) 2008 Metaways Infosystems GmbH (http://www.metaways.de)
- * @author      Philipp Schuele <p.schuele@metaways.de>
+ * @copyright   Copyright (c) 2008-2016 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Philipp Schüle <p.schuele@metaways.de>
  */
 
 /**
  */
 require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'TestHelper.php';
 
-if (! defined('PHPUnit_MAIN_METHOD')) {
-    define('PHPUnit_MAIN_METHOD', 'Phone_AllTests::main');
-}
-
 class Phone_AllTests
 {
     public static function main ()
@@ -29,11 +25,8 @@ class Phone_AllTests
         $suite = new PHPUnit_Framework_TestSuite('Tine 2.0 Phone All Tests');
         $suite->addTestSuite('Phone_JsonTest');
         $suite->addTestSuite('Phone_ControllerTest');
+        $suite->addTestSuite('Phone_Call_ControllerTest');
         //$suite->addTest(Phone_Backend_Snom_AllTests::suite());
         return $suite;
     }
 }
-
-if (PHPUnit_MAIN_METHOD == 'Phone_AllTests::main') {
-    Phone_AllTests::main();
-}
diff --git a/tests/tine20/Phone/Call/ControllerTest.php b/tests/tine20/Phone/Call/ControllerTest.php
new file mode 100644 (file)
index 0000000..c4f3298
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Tine 2.0 - http://www.tine20.org
+ * 
+ * @package     Phone
+ * @license     http://www.gnu.org/licenses/agpl.html
+ * @copyright   Copyright (c) 2008-2016 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Philipp Schüle <p.schuele@metaways.de>
+ */
+
+/**
+ * Test class for Tinebase_Group
+ */
+class Phone_Call_ControllerTest extends TestCase
+{
+    /**
+     * @see 0011934: show contacts in phone call grid
+     */
+    public function testContactId()
+    {
+        $phoneNumber = '0406437435';
+        $myContact = Addressbook_Controller_Contact::getInstance()->getContactByUserId(Tinebase_Core::getUser()->getId());
+        $myContact->tel_work = $phoneNumber;
+        Addressbook_Controller_Contact::getInstance()->update($myContact);
+
+        $call = new Phone_Model_Call(array(
+            'line_id'               => 'phpunitlineid',
+            'phone_id'              => 'phpunitphoneid',
+            'direction'             => Phone_Model_Call::TYPE_INCOMING,
+            'source'                => '26',
+            'destination'           => $phoneNumber,
+        ));
+        $call = Phone_Controller_Call::getInstance()->create($call);
+
+        $this->assertTrue(isset($call->contact_id));
+        $this->assertEquals($myContact->getId(), $call->contact_id);
+    }
+}
index f2725af..51f65db 100644 (file)
@@ -4,23 +4,14 @@
  * 
  * @package     Phone
  * @license     http://www.gnu.org/licenses/agpl.html
- * @copyright   Copyright (c) 2008 Metaways Infosystems GmbH (http://www.metaways.de)
- * @author      Philipp Schuele <p.schuele@metaways.de>
+ * @copyright   Copyright (c) 2008-2016 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Philipp Schüle <p.schuele@metaways.de>
  */
 
 /**
- * Test helper
- */
-require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'TestHelper.php';
-
-if (!defined('PHPUnit_MAIN_METHOD')) {
-    define('PHPUnit_MAIN_METHOD', 'Phone_ControllerTest::main');
-}
-
-/**
  * Test class for Tinebase_Group
  */
-class Phone_ControllerTest extends PHPUnit_Framework_TestCase
+class Phone_ControllerTest extends TestCase
 {
     /**
      * Fixtures
@@ -37,18 +28,6 @@ class Phone_ControllerTest extends PHPUnit_Framework_TestCase
     protected $_backend;
     
     /**
-     * Runs the test methods of this class.
-     *
-     * @access public
-     * @static
-     */
-    public static function main()
-    {
-        $suite  = new PHPUnit_Framework_TestSuite('Tine 2.0 Phone Controller Tests');
-        PHPUnit_TextUI_TestRunner::run($suite);
-    }
-
-    /**
      * Sets up the fixture.
      * This method is called before a test is executed.
      *
@@ -56,6 +35,8 @@ class Phone_ControllerTest extends PHPUnit_Framework_TestCase
      */
     protected function setUp()
     {
+        parent::setUp();
+
         $this->_backend = Phone_Controller::getInstance();
 
         $this->_objects['call'] = new Phone_Model_Call(array(
@@ -69,29 +50,12 @@ class Phone_ControllerTest extends PHPUnit_Framework_TestCase
     }
 
     /**
-     * Tears down the fixture
-     * This method is called after a test is executed.
-     *
-     * @access protected
-     */
-    protected function tearDown()
-    {
-    }
-
-    /**
-     * test start
+     * test a whole call cycle - start, connect, disconnect
      * 
      */
-    public function testStartCall()
+    public function testWholeCall()
     {
-        // remove old call
-        try {
-            $call = $this->_backend->getCall($this->_objects['call']->getId());
-            $backend = Phone_Backend_Factory::factory(Phone_Backend_Factory::CALLHISTORY);
-            $backend->delete($this->_objects['call']->getId());
-        } catch (Exception $e) {
-            // do nothing
-        }
+        // start call
         $call = $this->_backend->callStarted($this->_objects['call']);
         
         $this->assertEquals($this->_objects['call']->destination, $call->destination);
@@ -99,37 +63,25 @@ class Phone_ControllerTest extends PHPUnit_Framework_TestCase
         
         // sleep for 2 secs (ringing...)
         sleep(2);
-    }
 
-    /**
-     * test connect
-     * 
-     */
-    public function testConnected()
-    {
+        // connect call
         $call = $this->_backend->getCall($this->_objects['call']->getId());
         $ringing = $call->ringing;
-        
+
         $connectedCall = $this->_backend->callConnected($call);
 
         $this->assertEquals($this->_objects['call']->destination, $connectedCall->destination);
         $this->assertEquals(-1, $call->start->compare($call->connected));
-        
+
         // sleep for 5 secs (talking...)
         sleep(5);
-    }
 
-    /**
-     * test disconnect
-     * 
-     */
-    public function testDisconnected()
-    {
+        // disconnect call
         $call = $this->_backend->getCall($this->_objects['call']->getId());
         $duration = $call->duration;
 
         $disconnectedCall = $this->_backend->callDisconnected($call);
-        
+
         $this->assertGreaterThan($duration, $disconnectedCall->duration);
         $this->assertLessThan(10, $disconnectedCall->ringing, 'wrong ringing duration');
         $this->assertLessThan(15, $disconnectedCall->duration, 'wrong duration');
index 043d813..5e8c581 100644 (file)
@@ -4,15 +4,11 @@
  * 
  * @package     Phone
  * @license     http://www.gnu.org/licenses/agpl.html
- * @copyright   Copyright (c) 2008-2013 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2008-2016 Metaways Infosystems GmbH (http://www.metaways.de)
  * @author      Philipp Schüle <p.schuele@metaways.de>
  */
 
 /**
- * Test helper
- */
-
-/**
  * Test class for Phone_JsonTest
  */
 class Phone_JsonTest extends TestCase
@@ -277,14 +273,15 @@ class Phone_JsonTest extends TestCase
             'source'                => '78',
             'destination'           => '050998877',
         ));
-        
+
+        $scleverContact = Addressbook_Controller_Contact::getInstance()->getContactByUserId($this->_personas['sclever']->getId());
         $this->_objects['call4'] = new Phone_Model_Call(array(
             'id'                    => 'phpunitcallhistoryid4',
             'line_id'               => $this->_objects['line2']->getId(),
-            'phone_id'              => $this->_objects['phone2']->getId(),
+            'phone_id'              => $this->_objects['phone']->getId(),
             'direction'             => Phone_Model_Call::TYPE_INCOMING,
             'source'                => '78',
-            'destination'           => '05036998877',
+            'destination'           => $scleverContact->tel_work,
         ));
         
         $this->_objects['paging'] = array(
@@ -317,7 +314,9 @@ class Phone_JsonTest extends TestCase
         );
         
         $this->_objects['filter4'] = array(
-            array('field' => 'phone_id', 'operator' => 'AND', 'value' => array(array('field' => ':id', 'operator' => 'equals', 'value' => $this->_objects['phone2']->getId())))
+            array('field' => 'phone_id', 'operator' => 'AND', 'value' =>
+                array(array('field' => ':id', 'operator' => 'equals', 'value' =>
+                    $this->_objects['phone2']->getId())))
         );
         
         $this->_objects['filter5'] = array(
@@ -329,7 +328,9 @@ class Phone_JsonTest extends TestCase
         $phoneController->callStarted($this->_objects['call2']);
         $phoneController->callStarted($this->_objects['call2a']);
         $phoneController->callStarted($this->_objects['call3']);
-        $phoneController->callStarted($this->_objects['call4']);
+
+        // create with normal controller to make sure we get contact relation
+        Phone_Controller_Call::getInstance()->create($this->_objects['call4']);
     }
 
     /**
@@ -355,7 +356,7 @@ class Phone_JsonTest extends TestCase
         // search calls without phone_id filter -> at least one call will be returned
         $result = $this->_json->searchCalls($this->_objects['filter1'], $this->_objects['paging']);
         $this->assertGreaterThanOrEqual(1, $result['totalcount']);
-        $this->assertLessThanOrEqual(2, $result['totalcount']);
+        $this->assertLessThanOrEqual(3, $result['totalcount']);
         
         // search query -> '05036' -> the user has made 2 calls each with another phone, another made one call, 1 is correct then
         $result = $this->_json->searchCalls($this->_objects['filter2'], $this->_objects['paging']);
@@ -461,7 +462,6 @@ class Phone_JsonTest extends TestCase
     
     /**
      * try to get registry data
-     *
      */
     public function testGetRegistryData()
     {
@@ -473,7 +473,7 @@ class Phone_JsonTest extends TestCase
         $this->assertStringEndsWith('user phone', $data['Phones'][0]['description'], 'no description');
     }
     
-    // we need some mocks for asterisk backends...
+    // TODO we need some mocks for asterisk backends...
     public function _testDialNumber()
     {
         $number = '+494031703167';
@@ -486,4 +486,24 @@ class Phone_JsonTest extends TestCase
         $this->assertTrue((isset($status['success']) || array_key_exists('success', $status)));
         $this->assertTrue($status['success']);
     }
+
+    /**
+     * @see 0011934: show contacts in phone call grid
+     */
+    public function testContactId()
+    {
+        // search phone 2 calls (on should be linked to sclever)
+        $result = $this->_json->searchCalls($this->_objects['filter3'], $this->_objects['paging']);
+
+        $scleverCall = null;
+        foreach ($result['results'] as $call) {
+            if ($call['id'] == 'phpunitcallhistoryid4') {
+                $scleverCall = $call;
+            }
+        }
+
+        $this->assertTrue($scleverCall !== null);
+        $this->assertTrue(isset($scleverCall['contact_id']));
+        $this->assertEquals($this->_personas['sclever']->getId(), $scleverCall['contact_id']['account_id'], print_r($scleverCall['contact_id'], true));
+    }
 }
index 0a55a17..e0ce886 100644 (file)
@@ -373,7 +373,7 @@ class Projects_JsonTest extends PHPUnit_Framework_TestCase
                 'own_model'              => 'Projects_Model_Project',
                 'own_backend'            => 'Sql',
                 'own_id'                 => 0,
-                'own_degree'             => Tinebase_Model_Relation::DEGREE_SIBLING,
+                'related_degree'         => Tinebase_Model_Relation::DEGREE_SIBLING,
                 'type'                   => 'COWORKER',
                 'related_record'         => NULL,
                 'related_backend'        => 'Sql',
index 4019e95..a50404f 100644 (file)
@@ -70,7 +70,7 @@ class Sales_CustomersTest extends PHPUnit_Framework_TestCase
             'own_model' => 'Sales_Model_Coustomer',
             'own_backend' => 'Sql',
             'own_id' => $ipnet->getId(),
-            'own_degree' => 'sibling',
+            'related_degree' => 'sibling',
             'remark' => 'phpunit test',
             'related_model' => 'Sales_Model_Contract',
             'related_backend' => 'Sql',
@@ -151,7 +151,7 @@ class Sales_CustomersTest extends PHPUnit_Framework_TestCase
                     array(
                         'own_model' => 'Sales_Model_Address',
                         'own_backend' => 'Sql',
-                        'own_degree' => 'sibling',
+                        'related_degree' => 'sibling',
                         'remark' => 'phpunit test',
                         'related_model' => 'Sales_Model_Contract',
                         'related_backend' => 'Sql',
index fb76806..7402273 100644 (file)
@@ -75,7 +75,7 @@ class Sales_InvoiceControllerTests extends Sales_InvoiceTestCase
                 'own_model'              => 'Sales_Model_Contract',
                 'own_backend'            => Tasks_Backend_Factory::SQL,
                 'own_id'                 => NULL,
-                'own_degree'             => Tinebase_Model_Relation::DEGREE_SIBLING,
+                'related_degree'         => Tinebase_Model_Relation::DEGREE_SIBLING,
                 'related_model'          => 'Sales_Model_CostCenter',
                 'related_backend'        => Tasks_Backend_Factory::SQL,
                 'related_id'             => $this->_costcenterRecords->getFirstRecord()->getId(),
@@ -364,8 +364,6 @@ class Sales_InvoiceControllerTests extends Sales_InvoiceTestCase
 
     public function testInvoiceRecreation()
     {
-        $this->markTestSkipped('FIXME: this fails randomly :(');
-
         $result = $this->_createInvoiceUpdateRecreationFixtures();
 
         $oldInvoiceId0 = $result['created'][0];
@@ -416,16 +414,23 @@ class Sales_InvoiceControllerTests extends Sales_InvoiceTestCase
         $this->assertEquals(1, $pA->count());
         $pA = $pA->getFirstRecord();
         $pA->interval = 4;
+        sleep(1);
         Sales_Controller_ProductAggregate::getInstance()->update($pA);
         $contract4->title = $contract4->getTitle() . ' changed';
-        sleep(1);
         $this->_contractController->update($contract4);
+        sleep(1);
 
         $this->sharedTimesheet->id = NULL;
         $this->_timesheetController->create($this->sharedTimesheet);
 
         $result = $this->_invoiceController->checkForContractOrInvoiceUpdates();
-        $this->assertEquals(true, (count($result)===2||count($result)===3));
+
+        if (count($result) == 3) {
+            // this fails sometimes ... maybe due to timing issues - skip the rest if that's the case
+            return;
+        }
+
+        $this->assertEquals(2, count($result));
 
         $mapping = $this->_invoiceController->getAutoInvoiceRecreationResults();
         $this->assertEquals(true, isset($mapping[$oldInvoiceId0]));
@@ -770,6 +775,53 @@ class Sales_InvoiceControllerTests extends Sales_InvoiceTestCase
     }
     
     /**
+     * tests invoice merging
+     */
+    public function testMergingInvoices()
+    {
+        $startDate = clone $this->_referenceDate;
+        
+        $this->_createProducts();
+        
+        $this->_createCustomers(1);
+        $this->_createCostCenters();
+        
+        $monthBack = clone $this->_referenceDate;
+        $monthBack->subMonth(1);
+        $addressId = $this->_addressRecords->filter(
+                'customer_id', $this->_customerRecords->filter(
+                    'name', 'Customer1')->getFirstRecord()->getId())->filter(
+                        'type', 'billing')->getFirstRecord()->getId();
+        
+        $this->assertTrue($addressId !== NULL);
+        
+        // this contract begins 6 months before the first invoice will be created
+        $this->_createContracts(array(array(
+            'number'       => 100,
+            'title'        => 'MyContract',
+            'description'  => 'unittest',
+            'container_id' => $this->_sharedContractsContainerId,
+            'billing_point' => 'begin',
+            'billing_address_id' => $addressId,
+            
+            'interval' => 1,
+            'start_date' => $startDate->subMonth(6),
+            'last_autobill' => clone $this->_referenceDate,
+            'end_date' => NULL,
+            'products' => array(
+                array('product_id' => $this->_productRecords->getByIndex(0)->getId(), 'quantity' => 1, 'interval' => 1, 'last_autobill' => $monthBack),
+            )
+        )));
+        
+        $startDate = clone $this->_referenceDate;
+        $startDate->addDay(5);
+        $startDate->addMonth(24);
+        
+        $result = $this->_invoiceController->createAutoInvoices($startDate, null, true);
+        $this->assertEquals(1, $result['created_count']);
+    }
+    
+    /**
      * tests if a product aggregate gets billed in the correct periods
      */
     public function testOneProductContractInterval()
index d1056cc..432df21 100644 (file)
@@ -326,7 +326,7 @@ class Sales_InvoiceJsonTests extends Sales_InvoiceTestCase
         $c1['relations'] = array(array(
             'related_model' => 'Timetracker_Model_Timeaccount',
             'related_id'    => $ta['id'],
-            'own_degree'    => 'sibling',
+            'related_degree'=> 'sibling',
             'type'          => 'TIME_ACCOUNT',
             'remark'        => 'unittest',
             'related_backend' => 'Sql'
@@ -344,7 +344,7 @@ class Sales_InvoiceJsonTests extends Sales_InvoiceTestCase
         $c2['relations'] = array(array(
             'related_model'   => 'Timetracker_Model_Timeaccount',
             'related_id'      => $ta['id'],
-            'own_degree'      => 'sibling',
+            'related_degree'  => 'sibling',
             'type'            => 'TIME_ACCOUNT',
             'remark'          => 'unittest',
             'related_backend' => 'Sql'
index dcc0741..29be6d4 100644 (file)
@@ -579,7 +579,7 @@ class Sales_InvoiceTestCase extends TestCase
                     'own_model'              => 'Sales_Model_Contract',
                     'own_backend'            => Tasks_Backend_Factory::SQL,
                     'own_id'                 => NULL,
-                    'own_degree'             => Tinebase_Model_Relation::DEGREE_SIBLING,
+                    'related_degree'         => Tinebase_Model_Relation::DEGREE_SIBLING,
                     'related_model'          => 'Sales_Model_CostCenter',
                     'related_backend'        => Tasks_Backend_Factory::SQL,
                     'related_id'             => $costcenter->getId(),
@@ -589,7 +589,7 @@ class Sales_InvoiceTestCase extends TestCase
                     'own_model'              => 'Sales_Model_Contract',
                     'own_backend'            => Tasks_Backend_Factory::SQL,
                     'own_id'                 => NULL,
-                    'own_degree'             => Tinebase_Model_Relation::DEGREE_SIBLING,
+                    'related_degree'         => Tinebase_Model_Relation::DEGREE_SIBLING,
                     'related_model'          => 'Sales_Model_Customer',
                     'related_backend'        => Tasks_Backend_Factory::SQL,
                     'related_id'             => $customer->getId(),
@@ -602,7 +602,7 @@ class Sales_InvoiceTestCase extends TestCase
                     'own_model'              => 'Sales_Model_Contract',
                     'own_backend'            => Tasks_Backend_Factory::SQL,
                     'own_id'                 => NULL,
-                    'own_degree'             => Tinebase_Model_Relation::DEGREE_SIBLING,
+                    'related_degree'         => Tinebase_Model_Relation::DEGREE_SIBLING,
                     'related_model'          => 'Timetracker_Model_Timeaccount',
                     'related_backend'        => Tasks_Backend_Factory::SQL,
                     'related_id'             => $timeaccount->getId(),
index f90a2ee..8755b06 100644 (file)
@@ -208,7 +208,7 @@ class Sales_JsonTest extends TestCase
         $relationData = array();
         foreach ($contacts as $contact) {
             $relationData[] = array(
-                'own_degree' => 'sibling',
+                'related_degree' => 'sibling',
                 'related_degree' => 'sibling',
                 'related_model' => 'Addressbook_Model_Contact',
                 'related_backend' => 'Sql',
@@ -496,7 +496,7 @@ class Sales_JsonTest extends TestCase
                     'container_id'  => $personalContainer[0]->getId(),
                 ),
                 'related_model' => 'Addressbook_Model_Contact',
-                'own_degree'    => 'sibling'
+                'related_degree'=> 'sibling'
             ),
             array(
                 'type'              => Sales_Model_Contract::RELATION_TYPE_RESPONSIBLE,
@@ -505,7 +505,7 @@ class Sales_JsonTest extends TestCase
                     'container_id'  => $personalContainer[0]->getId(),
                 ),
                 'related_model' => 'Addressbook_Model_Contact',
-                'own_degree'    => 'sibling'
+                'related_degree'=> 'sibling'
             ),
         );
     }
@@ -657,7 +657,7 @@ class Sales_JsonTest extends TestCase
         
         // a partner may be added
         $relation = new Tinebase_Model_Relation(array(
-            'own_degree' => 'sibling',
+            'related_degree' => 'sibling',
             'own_model'  => 'Addressbook_Model_Contact',
             'own_backend' => 'Sql',
             'own_id' => $contact2->getId(),
@@ -676,7 +676,7 @@ class Sales_JsonTest extends TestCase
         
         // a second partner may be added also
         $relation = new Tinebase_Model_Relation(array(
-            'own_degree' => 'sibling',
+            'related_degree' => 'sibling',
             'own_model'  => 'Addressbook_Model_Contact',
             'own_backend' => 'Sql',
             'own_id' => $contact3->getId(),
@@ -697,7 +697,7 @@ class Sales_JsonTest extends TestCase
 
         // but a second responsible must not be added
         $relation = new Tinebase_Model_Relation(array(
-            'own_degree' => 'sibling',
+            'related_degree' => 'sibling',
             'own_model'  => 'Addressbook_Model_Contact',
             'own_backend' => 'Sql',
             'own_id' => $contact4->getId(),
index 826f5da..8f7cc5c 100644 (file)
@@ -126,7 +126,7 @@ class Sales_PurchaseInvoiceTest extends TestCase
                 'price_total' => 12.9,
                 'relations' => array(array(
                         'own_model' => 'Sales_Model_PurchaseInvoice',
-                        'own_degree' => Tinebase_Model_Relation::DEGREE_SIBLING,
+                        'related_degree' => Tinebase_Model_Relation::DEGREE_SIBLING,
                         'related_model' => 'Sales_Model_Supplier',
                         'related_record' => $customerData,
                         'type' => 'SUPPLIER'
index a38029e..53822e8 100644 (file)
@@ -526,6 +526,43 @@ abstract class TestCase extends PHPUnit_Framework_TestCase
     }
 
     /**
+     * test record json api
+     *
+     * @param $modelName
+     */
+    protected function _testSimpleRecordApi($modelName)
+    {
+        $uit = $this->_getUit();
+        if (!$uit instanceof Tinebase_Frontend_Json_Abstract) {
+            throw new Exception('only allowed for json frontend tests suites');
+        }
+
+        $newRecord = array(
+            'name' => 'my test ' . $modelName,
+            'description' => 'my test description'
+        );
+        $savedRecord = call_user_func(array($uit, 'save' . $modelName), $newRecord);
+
+        $this->assertEquals('my test ' . $modelName, $savedRecord['name'], print_r($savedRecord, true));
+        $savedRecord['description'] = 'my updated description';
+
+        $updatedRecord = call_user_func(array($uit, 'save' . $modelName), $savedRecord);
+        $this->assertEquals('my updated description', $updatedRecord['description']);
+
+        $filter = array(array('field' => 'id', 'operator' => 'equals', 'value' => $updatedRecord['id']));
+        $result = call_user_func(array($uit, 'search' . $modelName . 's'), $filter, array());
+        $this->assertEquals(1, $result['totalcount']);
+
+        call_user_func(array($uit, 'delete' . $modelName . 's'), array($updatedRecord['id']));
+        try {
+            call_user_func(array($uit, 'get' . $modelName), $updatedRecord['id']);
+            $this->fail('should delete Record');
+        } catch (Tinebase_Exception_NotFound $tenf) {
+            $this->assertTrue($tenf instanceof Tinebase_Exception_NotFound);
+        }
+    }
+
+    /**
      * returns true if main db adapter is postgresql
      *
      * @return bool
index 2388e67..994734e 100644 (file)
@@ -54,6 +54,10 @@ class TestServer
 
         $config = $this->getConfig();
 
+        // set some server vars. sabredav complains if REQUEST_URI is not set
+        $_SERVER['DOCUMENT_ROOT'] = $config->docroot;
+        $_SERVER['REQUEST_URI'] = '';
+
         Tinebase_Core::startCoreSession();
         
         Tinebase_Core::initFramework();
@@ -166,12 +170,11 @@ class TestServer
             $config = new Zend_Config($configData);
 
             Zend_Registry::set('testConfig', $config);
-
-            $_SERVER['DOCUMENT_ROOT'] = $config->docroot;
-            $_SERVER['REQUEST_URI'] = '';
+        } else {
+            $config = Zend_Registry::get('testConfig');
         }
 
-        return Zend_Registry::get('testConfig');
+        return $config;
     }
     
     /**
index 4aae724..db8f181 100644 (file)
@@ -11,7 +11,7 @@
 /**
  * Timetracker_AbstractTest Test class
  */
-abstract class Timetracker_AbstractTest extends PHPUnit_Framework_TestCase
+abstract class Timetracker_AbstractTest extends TestCase
 {
     /**
      * @var Timetracker_Frontend_Json
@@ -144,7 +144,7 @@ abstract class Timetracker_AbstractTest extends PHPUnit_Framework_TestCase
         $ts = new Timetracker_Model_Timesheet($data, TRUE);
 
         if ($_forceCreation) {
-            $tsRec = $this->_json->saveTimesheet($ts->toArray(), $_forceCreation);
+            $tsRec = $this->_json->saveTimesheet($ts->toArray());
             $this->_lastCreatedRecord = $tsRec;
         }
 
index c68bd19..e09f979 100644 (file)
@@ -277,6 +277,15 @@ class Timetracker_ControllerTest extends TestCase
         )));
         
         $this->_grantTestHelper($grants, 'searchTS', 1);
+
+        $filter = $this->_getTimesheetFilter();
+
+               $be = new Timetracker_Backend_Timesheet();
+        $result = $be->search($filter)->toArray();
+        $this->assertArrayHasKey('is_billable_combined', $result[0]);
+
+        $result = $this->_timesheetController->search($filter)->toArray();
+        $this->assertArrayHasKey('is_billable_combined', $result[0]);
     }
 
     /**
@@ -423,7 +432,8 @@ class Timetracker_ControllerTest extends TestCase
             'account_id'        => Tinebase_Core::getUser()->getId(),
             'timeaccount_id'    => $timeaccount->getId(),
             'description'       => 'blabla',
-            'start_date'        => Tinebase_DateTime::now()->toString('Y-m-d')
+            'start_date'        => Tinebase_DateTime::now()->toString('Y-m-d'),
+            'duration'          => 30,
         ), TRUE);
     }
 
index 53ce03c..46cb442 100644 (file)
@@ -137,7 +137,7 @@ class Timetracker_FilterTest extends Timetracker_AbstractTest
             'own_model' => 'Timetracker_Model_Timeaccount',
             'own_backend' => 'Sql',
             'own_id' => $timeaccount->getId(),
-            'own_degree' => 'sibling',
+            'related_degree' => 'sibling',
             'remark' => 'phpunit test',
             'related_model' => 'Sales_Model_Contract',
             'related_backend' => 'Sql',
@@ -164,6 +164,7 @@ class Timetracker_FilterTest extends Timetracker_AbstractTest
             'account_id' => Tinebase_Core::getUser()->getId(),
             'description' => 'lazy boring',
             'start_date' => $date,
+            'duration' => 30,
         ));
         
         $r->setTimezone('UTC');
@@ -183,4 +184,15 @@ class Timetracker_FilterTest extends Timetracker_AbstractTest
         
         $this->assertEquals(1, $results->count());
     }
+    
+    /**
+     * tests if the Timeaccount Filter is there
+     */
+    public function testTimeaccountfilterWithoutAdmin()
+    {
+        $this->_removeRoleRight('Timetracker', Tinebase_Acl_Rights::ADMIN);
+        $this->assertFalse(Tinebase_Core::getUser()->hasRight('Timetracker', Tinebase_Acl_Rights::ADMIN));
+        $config = Tinebase_ModelConfiguration::getFrontendConfigForModels(array('Timetracker_Model_Timesheet'));
+        $this->assertTrue(isset($config['Timesheet']['filterModel']['timeaccount_id']));
+    }
 }
index 470f2e4..09cc99e 100644 (file)
@@ -58,7 +58,7 @@ class Timetracker_JsonTest extends Timetracker_AbstractTest
 
         // checks
         $this->assertEquals($timeaccount->description, $timeaccountData['description']);
-        $this->assertEquals(Tinebase_Core::getUser()->getId(), $timeaccountData['created_by']);
+        $this->assertEquals(Tinebase_Core::getUser()->getId(), $timeaccountData['created_by']['accountId']);
         $this->assertTrue(is_array($timeaccountData['container_id']));
         $this->assertEquals(Tinebase_Model_Container::TYPE_SHARED, $timeaccountData['container_id']['type']);
         $this->assertGreaterThan(0, count($timeaccountData['grants']));
@@ -83,7 +83,7 @@ class Timetracker_JsonTest extends Timetracker_AbstractTest
 
         // checks
         $this->assertEquals($timeaccount->description, $timeaccountData['description']);
-        $this->assertEquals(Tinebase_Core::getUser()->getId(), $timeaccountData['created_by']);
+        $this->assertEquals(Tinebase_Core::getUser()->getId(), $timeaccountData['created_by']['accountId']);
         $this->assertTrue(is_array($timeaccountData['container_id']));
         $this->assertEquals(Tinebase_Model_Container::TYPE_SHARED, $timeaccountData['container_id']['type']);
 
@@ -107,7 +107,7 @@ class Timetracker_JsonTest extends Timetracker_AbstractTest
         // check
         $this->assertEquals($timeaccountData['id'], $timeaccountUpdated['id']);
         $this->assertEquals($timeaccountData['description'], $timeaccountUpdated['description']);
-        $this->assertEquals(Tinebase_Core::getUser()->getId(), $timeaccountUpdated['last_modified_by']);
+        $this->assertEquals(Tinebase_Core::getUser()->getId(), $timeaccountUpdated['last_modified_by']['accountId']);
 
         // cleanup
         $this->_json->deleteTimeaccounts($timeaccountData['id']);
@@ -161,7 +161,31 @@ class Timetracker_JsonTest extends Timetracker_AbstractTest
         $this->assertEquals(1, count($searchResult['filter']), 'did not get ta filter: ' . print_r($searchResult, TRUE));
         $this->assertEquals($timeaccountData['id'], $searchResult['filter'][0]['value']['id']);
     }
-    
+
+    /**
+     * try to get a Timeaccount with a tag filter
+     *
+     * @see 0012238: tag filter is not working for timesheets
+     */
+    public function testSearchTimesheetsWithTagFilter()
+    {
+        $timeaccount = $this->_getTimesheet();
+        $timeaccount['tags'] = array(array(
+            'type'          => Tinebase_Model_Tag::TYPE_PERSONAL,
+            'name'          => 'mytag',
+            'description'   => 'testtagfilter',
+            'color'         => '#009B31',
+        ));
+        $timeaccountData = $this->_json->saveTimesheet($timeaccount->toArray());
+        $this->assertEquals(1, count($timeaccountData['tags']));
+
+        $filter = array(
+            array('field' => 'tag', 'operator' => 'equals', 'value' => $timeaccountData['tags'][0]['id']),
+        );
+        $searchResult = $this->_json->searchTimesheets($filter, array());
+        $this->assertEquals(1, $searchResult['totalcount']);
+    }
+
     /**
      * try to add a Timeaccount with grants
      */
@@ -206,9 +230,9 @@ class Timetracker_JsonTest extends Timetracker_AbstractTest
 
         // checks
         $this->assertEquals($timesheet->description, $timesheetData['description']);
-        $this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetData['created_by']);
+        $this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetData['created_by']['accountId']);
         $this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetData['account_id']['accountId'], 'account is not resolved');
-        $this->assertEquals(Tinebase_DateTime::now()->toString('Y-m-d'),  $timesheetData['start_date']);
+        $this->assertEquals(Tinebase_DateTime::now()->toString('Y-m-d') . ' 00:00:00',  $timesheetData['start_date']);
 
         // cleanup
         $this->_json->deleteTimeaccounts($timesheetData['timeaccount_id']['id']);
@@ -381,7 +405,7 @@ class Timetracker_JsonTest extends Timetracker_AbstractTest
 
         // checks
         $this->assertEquals($timesheet->description, $timesheetData['description']);
-        $this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetData['created_by']);
+        $this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetData['created_by']['accountId']);
         $this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetData['account_id']['accountId'], 'account is not resolved');
         $this->assertEquals($timesheet['timeaccount_id'], $timesheetData['timeaccount_id']['id'], 'timeaccount is not resolved');
 
@@ -409,7 +433,7 @@ class Timetracker_JsonTest extends Timetracker_AbstractTest
         // check
         $this->assertEquals($timesheetData['id'], $timesheetUpdated['id']);
         $this->assertEquals($timesheetData['description'], $timesheetUpdated['description']);
-        $this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetUpdated['last_modified_by']);
+        $this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetUpdated['last_modified_by']['accountId']);
         $this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetUpdated['account_id']['accountId'], 'account is not resolved');
         $this->assertEquals($timesheetData['timeaccount_id'], $timesheetUpdated['timeaccount_id']['id'], 'timeaccount is not resolved');
 
@@ -870,7 +894,7 @@ class Timetracker_JsonTest extends Timetracker_AbstractTest
         $r = new Tinebase_Model_Relation(array(
             'own_model' => 'Timetracker_Model_Timeaccount',
             'own_backend' => 'Sql',
-            'own_degree' => 'sibling',
+            'related_degree' => 'sibling',
             'own_id' => $ta->getId(),
             'remark' => 'PHP UNITTEST',
             'related_model' => 'Sales_Model_Contract',
@@ -985,8 +1009,8 @@ class Timetracker_JsonTest extends Timetracker_AbstractTest
         $contract = $contractController->create(new Sales_Model_Contract(array('number' => '123', 'title' => 'UnitTest')));
         
         Tinebase_Relations::getInstance()->setRelations('Timetracker_Model_Timeaccount', 'Sql', $ta['id'], array(
-            array('related_backend' => 'Sql', 'type' => 'RESPONSIBLE', 'related_model' => 'Addressbook_Model_Contact', 'related_id' => $contact->getId(), 'own_degree' => 'sibling'),
-            array('related_backend' => 'Sql', 'type' => 'TIME_ACCOUNT', 'related_model' => 'Sales_Model_Contract', 'related_id' => $contract->getId(), 'own_degree' => 'sibling'),
+            array('related_backend' => 'Sql', 'type' => 'RESPONSIBLE', 'related_model' => 'Addressbook_Model_Contact', 'related_id' => $contact->getId(), 'related_degree' => 'sibling'),
+            array('related_backend' => 'Sql', 'type' => 'TIME_ACCOUNT', 'related_model' => 'Sales_Model_Contract', 'related_id' => $contract->getId(), 'related_degree' => 'sibling'),
         ));
         
         // add 2 relations
@@ -1031,7 +1055,7 @@ class Timetracker_JsonTest extends Timetracker_AbstractTest
         $bday = $contact['bday'];
         
         Tinebase_Relations::getInstance()->setRelations('Timetracker_Model_Timeaccount', 'Sql', $ta['id'], array(
-            array('related_backend' => 'Sql', 'type' => 'RESPONSIBLE', 'related_model' => 'Addressbook_Model_Contact', 'related_id' => $contact->getId(), 'own_degree' => 'sibling'),
+            array('related_backend' => 'Sql', 'type' => 'RESPONSIBLE', 'related_model' => 'Addressbook_Model_Contact', 'related_id' => $contact->getId(), 'related_degree' => 'sibling'),
         ));
         
         // update a few times, bday of contract should not change
@@ -1096,7 +1120,7 @@ class Timetracker_JsonTest extends Timetracker_AbstractTest
                 'own_backend' => 'Sql',
                 'own_id' => $contract->getId(),
                 'own_model' => 'Sales_Model_Contract',
-                'own_degree' => 'sibling',
+                'related_degree' => 'sibling',
                 'remark' => 'PHP UNITTEST',
                 'related_model' => 'Addressbook_Model_Contact',
                 'related_backend' => 'Sql',
@@ -1109,7 +1133,7 @@ class Timetracker_JsonTest extends Timetracker_AbstractTest
         $taToFind->relations = array(
             new Tinebase_Model_Relation(array(
                 'own_backend' => 'Sql',
-                'own_degree' => 'sibling',
+                'related_degree' => 'sibling',
                 'own_id' => $taToFind->getId(),
                 'own_model' => 'Timetracker_Model_Timeaccount',
                 'remark' => 'PHP UNITTEST',
@@ -1189,7 +1213,7 @@ class Timetracker_JsonTest extends Timetracker_AbstractTest
             'related_id' => $ta->id,
             'related_model' => 'Timetracker_Model_Timeaccount',
             'related_record' => $ta,
-            'own_degree' => 'sibling',
+            'related_degree' => 'sibling',
             'type' => 'INVOICE'
         )));
         
@@ -1258,7 +1282,6 @@ class Timetracker_JsonTest extends Timetracker_AbstractTest
     
     /**
      * try to update a Timesheet with a closed TimeAccount
-     *
      */
     public function testUpdateClosedTimeaccount()
     {
@@ -1269,16 +1292,17 @@ class Timetracker_JsonTest extends Timetracker_AbstractTest
         $timesheet = $this->_getTimesheet(array(
              'timeaccount_id'    => $timeaccount['id'],
         ));
-        $timesheetData = $this->_json->saveTimesheet($timesheet->toArray());
-        
-        Timetracker_ControllerTest::removeManageAllRight();
-        
-        $this->setExpectedException('Tinebase_Exception_AccessDenied');
+        $timesheetData = $this->_json->saveTimesheet($timesheet->toArray(), array('skipClosedCheck' => true));
         
         // update Timesheet
         $timesheetData['description'] = "blubbblubb";
         $timesheetData['account_id'] = $timesheetData['account_id']['accountId'];
         $timesheetData['timeaccount_id'] = $timesheetData['timeaccount_id']['id'];
-        $timesheetUpdated = $this->_json->saveTimesheet($timesheetData);
+        try {
+            $timesheetUpdated = $this->_json->saveTimesheet($timesheetData, array('skipClosedCheck' => false));
+            $this->fail('Failed asserting that exception of type "Timetracker_Exception_ClosedTimeaccount" is thrown.');
+        } catch (Timetracker_Exception_ClosedTimeaccount $tect) {
+            $this->assertEquals('This Timeaccount is already closed!', $tect->getMessage());
+        }
     }
 }
index 4e87a5c..4643977 100644 (file)
@@ -82,6 +82,7 @@ class Tinebase_AllTests
         $suite->addTest(Tinebase_Frontend_AllTests::suite());
         $suite->addTest(Tinebase_Acl_AllTests::suite());
         $suite->addTest(Tinebase_Tree_AllTests::suite());
+        $suite->addTest(Tinebase_Record_AllTests::suite());
         $suite->addTest(Tinebase_Scheduler_AllTests::suite());
         $suite->addTest(Tinebase_WebDav_AllTests::suite());
         $suite->addTest(OpenDocument_AllTests::suite());
index ce24cd9..e3c42f6 100644 (file)
@@ -255,4 +255,232 @@ class Tinebase_ApplicationTest extends TestCase
             }
         }
     }
+
+    /**
+     * Test
+     */
+    public function testGetModelsOfAllApplications()
+    {
+        $models = Tinebase_Application::getInstance()->getModelsOfAllApplications();
+        $applications = Tinebase_Application::getInstance()->getApplicationsByState(Tinebase_Application::ENABLED);
+        $appNames = $applications->name;
+
+        $expectedData = array(
+            'ActiveSync' => array(
+                'ActiveSync_Model_Policy',
+                'ActiveSync_Model_Device',
+            ),
+            'Addressbook' => array(
+                'Addressbook_Model_Salutation',
+                'Addressbook_Model_List',
+                'Addressbook_Model_ListRole',
+                'Addressbook_Model_ListMemberRole',
+                'Addressbook_Model_Contact',
+            ),
+            'Admin' => array(
+                'Admin_Model_Config',
+                'Admin_Model_SambaMachine',
+            ),
+            'Calendar' => array(
+                'Calendar_Model_Resource',
+                'Calendar_Model_iMIP',
+                'Calendar_Model_Rrule',
+                'Calendar_Model_AttendeeRole',
+                'Calendar_Model_Event',
+                'Calendar_Model_FreeBusy',
+                'Calendar_Model_Exdate',
+                'Calendar_Model_Attender',
+                'Calendar_Model_AttendeeStatus',
+            ),
+            'CoreData' => array(
+                'CoreData_Model_CoreData',
+            ),
+            'Courses' => array(
+                'Courses_Model_Course',
+            ),
+            'Crm' => array(
+                'Crm_Model_LeadType',
+                'Crm_Model_LeadSource',
+                'Crm_Model_LeadState',
+                'Crm_Model_Lead',
+            ),
+            'ExampleApplication' => array(
+                'ExampleApplication_Model_ExampleRecord',
+                'ExampleApplication_Model_Status',
+            ),
+            'Expressomail' => array(
+                'Expressomail_Model_Account',
+                'Expressomail_Model_Sieve_Vacation',
+                'Expressomail_Model_Sieve_Rule',
+                'Expressomail_Model_PreparedMessagePart',
+                'Expressomail_Model_Message',
+                'Expressomail_Model_Folder',
+            ),
+            'Felamimail' => array(
+                'Felamimail_Model_Account',
+                'Felamimail_Model_Sieve_Vacation',
+                'Felamimail_Model_Sieve_Rule',
+                'Felamimail_Model_PreparedMessagePart',
+                'Felamimail_Model_Message',
+                'Felamimail_Model_Folder',
+            ),
+            'Filemanager' => array(
+                'Filemanager_Model_Node',
+                'Filemanager_Model_DownloadLink',
+            ),
+            'HumanResources' => array(
+                'HumanResources_Model_ExtraFreeTime',
+                'HumanResources_Model_Account',
+                'HumanResources_Model_Employee',
+                'HumanResources_Model_FreeTimeType',
+                'HumanResources_Model_ExtraFreeTimeType',
+                'HumanResources_Model_FreeTimeStatus',
+                'HumanResources_Model_Contract',
+                'HumanResources_Model_CostCenter',
+                'HumanResources_Model_FreeDay',
+                'HumanResources_Model_WorkingTime',
+                'HumanResources_Model_FreeTime',
+            ),
+            'Inventory' => array(
+                'Inventory_Model_Status',
+                'Inventory_Model_InventoryItem',
+            ),
+            'Phone' => array(
+                'Phone_Model_Call',
+                'Phone_Model_MyPhone',
+            ),
+            'Projects' => array(
+                'Projects_Model_Project',
+                'Projects_Model_AttendeeRole',
+                'Projects_Model_Status',
+            ),
+            'Sales' => array(
+                'Sales_Model_Number',
+                'Sales_Model_Config',
+                'Sales_Model_PurchaseInvoice',
+                'Sales_Model_Supplier',
+                'Sales_Model_PaymentMethod',
+                'Sales_Model_OrderConfirmation',
+                'Sales_Model_Customer',
+                'Sales_Model_Address',
+                'Sales_Model_ProductCategory',
+                'Sales_Model_InvoiceCleared',
+                'Sales_Model_InvoiceType',
+                'Sales_Model_Invoice',
+                'Sales_Model_Contract',
+                'Sales_Model_InvoicePosition',
+                'Sales_Model_Division',
+                'Sales_Model_ProductAggregate',
+                'Sales_Model_Offer',
+                'Sales_Model_CostCenter',
+                'Sales_Model_Product',
+            ),
+            'SimpleFAQ' => array(
+                'SimpleFAQ_Model_Faq',
+                'SimpleFAQ_Model_Config',
+            ),
+            'Tasks' => array(
+                'Tasks_Model_Task',
+                'Tasks_Model_Priority',
+                'Tasks_Model_Pagination',
+                'Tasks_Model_Status',
+            ),
+            'Timetracker' => array(
+                'Timetracker_Model_TimeaccountGrants',
+                'Timetracker_Model_Timesheet',
+                'Timetracker_Model_Timeaccount',
+            ),
+            'Tinebase' => array(
+                'Tinebase_Model_AccessLog',
+                'Tinebase_Model_ContainerContent',
+                'Tinebase_Model_Application',
+                'Tinebase_Model_Registration',
+                'Tinebase_Model_Image',
+                'Tinebase_Model_Tree_Node',
+                'Tinebase_Model_Tree_FileObject',
+                'Tinebase_Model_ModificationLog',
+                'Tinebase_Model_Config',
+                'Tinebase_Model_Group',
+                'Tinebase_Model_State',
+                'Tinebase_Model_CredentialCache',
+                'Tinebase_Model_PersistentFilterGrant',
+                'Tinebase_Model_AsyncJob',
+                'Tinebase_Model_CustomField_Value',
+                'Tinebase_Model_CustomField_Config',
+                'Tinebase_Model_CustomField_Grant',
+                'Tinebase_Model_Container',
+                'Tinebase_Model_Tag',
+                'Tinebase_Model_Relation',
+                'Tinebase_Model_TagRight',
+                'Tinebase_Model_NoteType',
+                'Tinebase_Model_Alarm',
+                'Tinebase_Model_FullTag',
+                'Tinebase_Model_SAMGroup',
+                'Tinebase_Model_EmailUser',
+                'Tinebase_Model_Department',
+                'Tinebase_Model_ImportException',
+                'Tinebase_Model_User',
+                'Tinebase_Model_Role',
+                'Tinebase_Model_Note',
+                'Tinebase_Model_RoleRight',
+                'Tinebase_Model_Pagination',
+                'Tinebase_Model_TempFile',
+                'Tinebase_Model_ImportExportDefinition',
+                'Tinebase_Model_OpenId_Association',
+                'Tinebase_Model_OpenId_TrustedSite',
+                'Tinebase_Model_FullUser',
+                'Tinebase_Model_Import',
+                'Tinebase_Model_UpdateMultipleException',
+                'Tinebase_Model_SAMUser',
+                'Tinebase_Model_Path',
+                'Tinebase_Model_Preference',
+                'Tinebase_Model_PersistentObserver',
+                'Tinebase_Model_Grants',
+            ),
+        );
+
+        // remove bogus apps
+        $remove = array('Voipmanager', 'RequestTracker', 'Sipgate', 'Expressodriver');
+        foreach($remove as $r)
+        {
+            if (($key = array_search($r, $appNames)) !== false) {